This is post number 4 in a series of articles covering how I am building my pet project Boing, a scripting playground to create Amiga style cracktros.
Last time we have successfully set up Löve2D and tested loading a script. Now it is time to set up Boing’s basic architecture and get something drawn on the screen.
When developing games I always liked the nodes and actions mechanism that I first encountered in Cocos2D and which was also adopted in Apple’s SpriteKit. It makes it very intuitive to define actions like animations and assign them to an on-screen object. It is possible to assign multiple actions simultaneously, group them, play them in sequence or reverse them. It is a perfect match for Boing. In fact, I built the Paranoimia demo presented in the first article of this series using SpriteKit actions.
Löve2D does not provide a mechanism like that and also some research did not yield any 3rd party libraries that would provide similar functionality. So I decided to implement my own little nodes and actions framework, heavily inspired by and borrowing a lot from Cocos2D-Objc.
First I needed to implement the concept of nodes. In Cocos2D nodes can have sub-nodes and make up a whole hierarchy called the scene graph. For now I do not need this complexity in Boing and will only create a flat list of nodes, eventually implementing a tree-like structure only if really necessary.
Nodes are able to run actions, i.e. you can add actions to a node which will modify certain properties like its position, scale or rotation over time.
Actions have a certain inheritance hierarchy:
The Lua language is not inherently object oriented like other languages, i.e. it does not support classes or inheritance out of the box. But it is easily possible to get a simple OOP setup working. I used a small library called Classic.
Node base class defines the basic properties common for every node:
node class also has two functions that are meant to be implemented by its subclasses:
update() function will be called from
love.update(dt) function and gets the time passed since the program started as the
dt parameter. This will later be used to update the nodes actions and do any other time-dependent operations.
draw() function will be implemented by subclasses to do their specific drawing. Like
update() this is called from
main.lua in the
love.draw() function for each node in the scene.
Back in the main file there are some additional things we need. First we need a place to store all the nodes and a way to add them:
Then there are the implementations for
love.draw() which both for now just iterate all nodes in the scene and call their respective
draw() functions. This will get more complicated once we start supporting animatable properties.
The First Node is a Box
To test out the setup let’s create a simple node that just draws a box on the screen.
And let’s also create a test scene:
And by running
$ love . box.lua … we have a box!