A few weeks ago, I posted an introduction to the Tiny game engine, which you can read at the link below:
Tinkering with Tiny
While browsing Hacker News recently, I came across a post about a new game engine called Tiny. The pitch had me intrigued from the get-go: The virtual console that offers an easy and efficient way to build games and other applications with its Lua programming support, hot reloading, and 256-color maximum.
Since then, Iโve been sporadically working on a little game called Tiny Gardening, which is intended to be something of a re-vamp of one of my first coding projects:
When I was first learning how to code (many years ago) one of the very first programs I wrote was a text-based simulation of an orange tree, where you had to water the tree and collect the oranges regularly. I donโt know why, but thereโs something about simulating plants which keeps coming back to me, so why not continue the theme with Tiny?
Though Tiny Gardening is by no means complete - or even โa gameโ - at this point, Iโve made enough progress to warrant a quick update, so without further ado, allow me the pleasure of taking you on a tour of my digital allotment!
Where Weโre At
Currently, the game has a handful of basic features which need further fleshing out:
Players can plant seeds
Players can water their plants
Plants grow as their โwater levelโ increases
Plants lose water over time - currently shrinking back down to their โseedโ sprites, but in the long run, they should have some kind of โdeathโ sprite.
When all your plants are dead, itโs game over.
The current season is represented by the bar along the top, with a yellow circle (actually a photorealistic representation of our glorious sun!) moving along it to represent the passage of time.
Right now, time moves very quickly. Seasons pass in the blink of an eye, and your plants will โdieโ if left un-watered for longer than about 10 seconds - so good luck trying to manage more than a few plants for any length of time!
To get some idea of how things currently work, see the video below:
Itโs a bit of a free-for-all with the placement of the plants - which Iโm not too keen on. I may play around with some kind of grid-based layout, which will also help provide a nice system for more interesting rules and challenges later on.
Seasons will ultimately cause different effects, though right now they do nothing but change the colour of the ground. In summer, for example, it might be fun for plants to lose water more rapidly, or for certain types to grow more quickly. Autumn may have an increased likelihood of rainfall, but โsummer plantsโ may not grow so easily. Iโd also like to introduce some pests and pollinating insects later on, but weโre a little way away from that kind of thing right now!
In the medium term, I need some kind of win condition for the player. Right now itโs just a case of surviving for as long as you can, but thatโs not particularly interesting. Iโd like to introduce some kind of farming-like mechanic: some plants could be vegetables you have to harvest and sell, and perhaps you need to meet a certain quota for some particular type of vegetable within the year. Iโm not too hung up on that for now - there are plenty of things I want to implement just to explore what Tiny can do - so Iโm holding off bothering too much with it for the time being.
Challenges
Tiny is a brand-new game engine, currently gearing up for its v1.0.0 release, so bugs and shortcomings are to be expected.
Generally speaking, the engine doesnโt offer all that much aside from the absolute basics: itโs up to you to build each system your game might require. There is no concept of 2D physics for collisions, no UI system, no entity-component system and very limited support for input and audio. In many ways, this makes it a brilliant engine for the programmer who has some idea of how to implement those kinds of things - but absolute beginners may struggle. I would say Tiny suits those who have some familiarity with other game engines, but who enjoy a challenge. Doing anything beyond the most basic of games will require some understanding of non-trivial concepts and systems, and youโll need to work out collisions and any other physics for yourself. Thankfully, the maths involved is generally relatively simple and can be worked out in your head (or, more likely, looked up online!).
There are also bugs in the engine which require some attention. One I discovered very early on was in the engineโs implementation of math.clamp, which, for the uninitiated, is a function you can call which restricts a number so that it always resides between two other values:
This is a standard function available in virtually all math libraries - and a particularly useful function in game development. The bug, in this case, meant that values would only actually be clamped if they were greater than the upper bound:
This kind of thing can be a painful bug to come across - the nature of it means you end up with unclamped values causing things to spin out of control - and since Tiny doesnโt offer any kind of debugger, the cause of the problem can be difficult to spot - particularly if youโre controlling and constraining values in multiple different ways.
Thankfully, in this instance, I was able to spot the problem easily since its impact was obvious: Iโm not sure what happens in the real world when plants have โnegative waterโ, but in Tiny Gardening, they become very dead very quickly. I fixed the issue in the engineโs source code and submitted a Pull Request on GitHub - which was promptly accepted and merged into the engineโs codebase.
Iโm sure Iโll find more issues as I continue - I have a sneaking suspicion thereโs an issue with audio not looping correctly in builds which are exported for the web, but I need to test further to confirm.
Bootstrapping
Since Tiny is such a bare-bones game engine, itโs up to the programmer to implement systems and utilities to make the game development process more straightforward. Below, Iโll cover some of the things Iโve implemented to make further development more flexible and less time-consuming. Wherever I include a code snippet, keep in mind that Iโve probably omitted some parts of the code which arenโt strictly relevant. You can always take a look at the full source code over on GitHub if you want to see all of the nuts and bolts!
State Machinery
At the highest level, the game is broken up into three distinct states, which allows me to encapsulate the core loop and easily add or remove extra screens or switch out different implementations without too much fuss.
For those unfamiliar with the terminology, or state machines in general - for now, you can imagine that a โstateโ corresponds to a โscreenโ in the game.
The basic states Iโm working with right now are:
Main Menu
This state represents the first screen players will see and does nothing but provide a big button to press to start the game.
Game
This is where players spend most of their time - all of the actual gameplay occurs when the program is in this state
Game Over
This is where players end up when theyโve won or lost the game. It will provide some kind of summary of how the player did and also provides a way to return to the main menu so players can start again.
Below you can see the skeleton of a State:
The State:new() function acts as a Constructor. Lua - the language Tiny games are written in - does not provide objects in quite the same way that other Object-Oriented languages do, and so some basic boilerplate code is required to give ourselves something akin to the objects and classes you may be familiar with. If youโre interested in learning more, you can read the lua documentation on the subject - but to summarise: every time I want a new State object, I can just use:
myNewState = State:new({})
From there, I can call functions on my new object instance as follows:
myNewState:update()
myNewState:draw()
Those who recall Tinkering With Tiny will remember that the engine calls an _update() and a _draw() function on every frame, so, in keeping with this pattern, thereโs a corresponding update() and draw() function on virtually every custom object throughout the Tiny Gardening code.
Entities
There are some basic features which are common to pretty much everything on-screen in Tiny Gardening:
They all have a size and position
I need to know if theyโve been clicked
I need to check if they overlap with some other entity
I want some basic debugging functionality that I can easily turn on and off as I see fit.
For these reasons (and more!), it makes sense to build some kind of entity system which allows me to share these features across different kinds of objects. In Tiny Gardening, you can click on buttons and you can click on plants. What happens when you click on either is radically different, but they are both โclickable thingsโ, and like any good programmer, I am incredibly lazy, so I donโt want to write โclick detectionโ code more than once if I can avoid it!
Using what passes for inheritance in lua, I can implement new object types which are based on this Entity object, meaning that every object created in this way can detect clicks.
User Interface
Tiny offers absolutely nothing in the way of a UI system. There are no buttons, sliders, text fields, or anything else that other game engines might offer. This is a little frustrating since user-interface code can be a pain even when the engine does provide something for you to use - but Iโm not one to complain, so one of the first things I did was implement a Button, which features something akin to โclick eventsโ:
Here, the Button object is instantiated by a call to Entity:new(), which means that every Button object I create automatically benefits from click detection. The onClick property is itself a table, which can be thought of as an array, meaning I can attach multiple handlers to a single button, which are triggered whenever a click is detected. The Button:fireClickEvent function loops over those handlers and calls them one by one.
As an example of how the Button object is used in Tiny Gardening, hereโs my generic โdebug buttonโ which always lives at the top of the screen:
Here, you can see that the onClick handler is itself an anonymous function - meaning it has no name and canโt be called except by accessing the value of onClick. This is a nice way of handling simple functionality which should occur when a button is clicked - but is not particularly well suited to more complex behaviour. For my purposes, this system works well and means I have a nice, easy-to-use, basic button.
Of course, you rarely need just one button, so I also implemented a ButtonBar, which allows me to lay out a series of buttons either vertically or horizontally:
Tiny Gardening also utilises a variant of the base Button called ToggleButton, which allows me to implement such thrilling and revolutionary concepts as a selected toolbar:
Wrapping Up
In this post, weโve covered some of the basic components of Tiny Gardening. Admittedly, most of what Iโve mentioned here is a far cry from โgame stuffโ or even touches on the main theme of the game, but in an engine like Tiny, it can pay dividends to build yourself a little toolkit of reusable components and functions which form the backbone of the rest of your game. Things like buttons and entities might seem trivial at first glance, but their absence can be felt keenly when youโre trying to build anything that requires shared functionality and predictable behaviour!
In the next progress update, Iโll dive into the core mechanics of the game so far - how I track plant growth and animate the sprites, the particle system for water and seeds, and how Iโm implementing seasonal effects. Iโll also talk more about the pros and cons Iโve discovered about the Tiny game engine. In the meantime, you can explore the code as-is on GitHub, and try Tiny Gardening out for yourself here!