Pages

Tuesday, February 28, 2017

Almost three years? Time is a rare commodity, these days. Between a full time job, two colleges, commissions, I am depleting all my free time and then some. Still, I have to say that having so little free time has forced me to learn how to actually put it to good use, something I, as many others, needed to. One of the consequences of this good use of time is the unshelving of an old personal project; better yet, a game project.

This old shelved personal is a story driven
game, in a sci-fi setting inspired by Beneath a Steel Sky, The Dig and I Have No Mouth, and I Must Scream. It is a multiple endings visual novel about
three children born and raised without human contact. With lives on their hands, these children have to make decisions and save or doom tens of thousands of people.

I did not intent to push it and rush things, but news about Greenlight being taken down
are forcing me to increase the pace. We hope to go use Greenlight before it is taken down. That will be a big challenge, which will certainly test my discipline and speed. All of this will be for nothing without you guy's support, and I want to count on it when the time comes.

Expect some more posts over the next couple of weeks as I try to keep you guys informed. Me and my beautiful partner will be working our
essays off to bring this game to life, and that depends heavily on being on approved on Steam.

Given the nature of this blog (it is about programming isn't it?), I must say that the game will be commercial, but will be source available for all those who get a copy of the game. The license will be posted later this week, as I finish writing it.

Today, we are going to talk about how to render animated sprites with the Löve2D framework (v0.9.1). The principle is simple, you store the image and shared animation data and keep the animation control data somewhere. Whenever you need to render the sprite, you get the control data, apply the "fix" animation data and in the end render the correct portion of the image with the correct rotation, flips and scale.

The difficulty on this guide here is much higher than that of the introduction. I suggest you master that previous one before venturing any further.

This is what we want to achieve today (source code download at the bottom):

The first thing that comes to mind is that we have data that is shared between all our animated sprites, as the spritesheet, while there is data that is unique for every single animated sprite, as the elapsed time. So, let's determine the necessary data and differentiate what we can share from what we need to duplicate on each instance.

Shared or Instance Data

Straight out, the first things that come to mind are the spritesheet and a name. Every animation needs the access to an image/texture (or maybe the steps to render it with primitives) and a name to identify it, uniquely would be preferable. This data wouldn't change if you had, say, two separate goblins being animated. The sprite's size and speed are also fixed, the number of animations, total frames for each of them and these frames' offset in the texture are also static information, that would not change between the goblins walking side by side.

So, for the fix data, we have:

Sprite Name (or an ID);

Image (may be shared between sprites);

Frame Duration;

Animations (list); and for each animation

Size;

Frames Offsets (a list or a way to calculate these);

Frames Sizes.

Basically, this is all we need to have an animated sprite. If you want, you can store the size and frame duration for each animation or even for every single frame, if you want to; this would add some more flexibility. But here I won't do that since it detracts the code's readability.

Ok, with all these in place, we can calculate what frame to draw at a given time, using an elapsed time and the specific sprite and animation we want to render. So, that is the basics of what we'll need, a variable to control the animation time and another to store what animation is being rendered. We also need to know where on the window we'll render the sprite, and also give it some scale and rotation.

And this is what we need for every copy of the animation being rendered:

Sprite Name (or ID, so we know what static data to use);

Current Animation;

Current Frame;

Elapsed Time (from the last frame change);

Position (x, y);

Scale (in size and speed);

Rotation (in degrees);

Flip (horizontal, vertical, both or none);

Alpha.

Alternatively, you could store just the elapsed time and refrain from keeping the current frame. This would save you a variable, but you'd need to use the % operator for every sprite on every frame. I prefer to use the extra variable and keep the math a little lighter.

That is basically what we'll need. The first list is what we need to have a single copy in memory despite of how many animations are running simultaneously. The second list's variables is what we need to keep a copy for every single instance. Sometimes, it doesn't make sense having rotation, scale, alpha or even flip when your game wouldn't use it.

Sometimes, some of these items can be left off the sprite instance, such as its position, scale, alpha, rotation, flip, as these would actually be stored in your game's entities, not in the rendering information.

As for the data, that is all. Let's move on to the serialization of the static part.

Simple Sprite Serialization with Lua

Lua makes our lives really easier when it comes to data serialization. Lots of content creation tools such as the Tiled map editor export directly to Lua, and all we need to do is call a single function and it is all in memory, ready to use.

SerializedData

return { -- Do you remember? These {} make a table.--Insert all the stuff here!
first_name = "Not",
last_name = "Sure"
}

GetTheData

Our first script with more than one file. The first file -GetTheData- gets the serialized data from the second one -SerializedData- by executing it with Lua's dofile() function. It then prints the contents of the received table.

The dofile() function simply calls the script file as if it was a single function and returns to us whatever the script file returns. Did you notice the file has a return statement outside of any functions? In Lua, you can treat a file as a single function and add return in its main body, outside of any blocks. That is really useful for serialized data, and we'll do that with almost every serialized table we have.

There's also some other similar functions to load external files: require(...), loadfile(...), load(...), and some others. You can find them here, under the sections 5.1 through 5.3.

This is how we are going to serialize the static data for all our sprites. We start the data file with return { and add all the data we need before closing with the respective }. The importance of the serialization can't be overstated.

Löve2D Note:
In L2D, you can zip your entire game in a single .zip file and rename it to .love. This way people can run it directly with less hassle (info here). The problem is that these loadfile() and dofile() functions do not work, you need to use the love.filesystem counterparts.

Real Example

To create our serialization fie, we'll need a sprite to serve as example. For that, I'll be using some graphics available here. I will need to make some changes so it fits our use better.

Lava Man from Capcom's Breath of Fire 3

Our first step will be serializing the information we need in order to animate the Lava Man. We will do that by creating a new Lua file named LavamanSprite.lua. This file will contain all the fix information for the sprite as described earlier. This is how we are starting our file (warning - this file will be relatively big).

LavamanSprite.lua:

local image_w = 739--This info can be accessed with a Löve2D call
local image_h = 438-- after the image has been loaded.--I'm creating these for readability.
return {
serialization_version = 1.0-- The version of this serialization process
sprite_sheet = "images/Sheet.png", -- The path to the spritesheet
sprite_name = "lavaman", -- The name of the sprite
frame_duration = 0.10, --How much time on each frame (default)

As you can see, we are using the return {}, that means return the following table; and I start listing miscellaneous information on the sprite. The image_w and image_h variables hold the dimensions of the entire spritesheet. We could get these by loading the image and checking its size or adding these directly as I did here.

The serialization_version variable is very important, as usually the serialization process may change while your game is in active development. Having this version control will allow you to create backward compatibility if no breaking changes are made. So, even if you think you won't use it, I advise you to use this control (or a better one for that matter).

The sprite_sheet and sprite_name won't be used on every frame, but are really important nevertheless. The name is mostly for internal data control, something mnemonic you can use as reference. The sheet should be the path to the image (absolute or relative) so we can get it ready.

The frame_duration here is basically the time our sprite will spend on each frame (in seconds). In here, we'll be using this value for the entire sprite, but you can use one for each animation or even one for each frame.

--This will work as an array.--So, these names can be accessed with numeric indexes starting at 1.--If you use < #sprite.animations_names > it will return the total number-- of animations in in here.
animations_names = {
"idle",
"attack",
"get_hit",
"idle_back",
"attack_back",
"get_hit_back"
},

So, here we list all the animations our sprite will have. If you have seen the video on the top, you have seen that it has 3 different animations in two points of view (6 animations). So, I list their names here so we can access them by index: mySprite.animations_names[1] would return the string 'idle'.

Note: the code above is not in its final form. It is here just to make it clearer for now.
This animations map holds arrays with the frames' offsets and respective sizes. Every animation has one of these arrays.

Now, how can we add the rectangles (as in offset+size) we need in order to render the desired portion of the image? One approach would be to simply add the coordinates to that array, as in here:

What is the problem with this approach? None really. It is just not taking advantage of one of Lua's strongest points, the fact that it isn't necessary to parse data serialized with it. If we add the numbers, we will still need to convert these into a Löve2D structure called a quad (docs here).

Creating this quad structure takes some runtime effort, so it is not good to create a quad for every time we'd render a sprite. We could get these numbers and parse them into quads when we first load the sprite, that is much better. But Lua gives us a third option - serializing the quads commands directly. So, we'll need to use the love.graphics.newQuad(x, y, width, height, source_w, source_h ) function (docs here).

The first two numbers are the offset for the frame. The origin of the rectangle we want to draw from the image. The 3rd and 4th represent the size of that rectangle. The last two parameters are actually the size of the spritesheet. I have no idea why Löve2D needs this information, but it does. You can do as I did and insert this information manually or you can do it as follows:

Phew! Now our serialization file is ready to be used. And all this hard work paid off, to get all the information serialized in this file in a table is now as simple as this:

lavamanSprite = dofile("LavamanSprite.lua")

And the lavamanSprite variable now holds all the static information on the sprite.

If you think about it, this code is very long, but relatively simple. It is simple enough to be automatically generated with a simple content creation tool. But we'll be doing these manually for now.

Sprites Manager

Now that we have our sprite properly serialized in its own file, we need to manage it somehow. In order to be able to use all that static data, we need to use some dynamic data for every sprite, as well as we need to load the spritesheet into memory. It would also be wise to do some error checking and automate the instantiation of the dynamic data. So, how do we start?

AnimatedSprite.lua

local ManagerVersion = 1.0
sprite_bank = {} --Map with all the sprite definitions
image_bank = {} --Contains all images that were already loaded

So, first thing first, we define the manager version. As of now, it is the same version as our LavamanSprite.lua serialization, but it will come in handy if we need to make changes on either file and need to create some backwards compatibility.

The tables sprite_bank and image_bank both store data mapped to unique indentifier keys, the sprites' being their definition file path and the images' being their own path. (note: if you load them with relative and absolute paths, it'll store one duplicate)

With these tables in hand, we can check whether a given sprite or image has already been loaded and, if not, load it properly. To be able to draw our sprites, we'll need the following functions:

LoadSprite - Loads a sprite from a definition file (such as LavamanSprite.lua)
GetInstance - Gets an instance (dynamic data) for a given sprite
UpdateInstance - Updates an instance with the elapsed time from the last call
DrawInstance - Draws the instance using its own dynamic data at [x, y]

If you call GetInstance in a sprite that is not on memory, it will be loaded automatically. We will always try to pre-load them though, so we avoid loading anything at runtime. LoadSprite and GetInstance can return nil if there is an error (file doesn't exist or something like that).

function LoadSprite (sprite_def)
if sprite_def == nil then return nil end
--Load the sprite definition file to ensure it exists
local definition_file = loadfile(sprite_def)
--If the file doesn't exist or has syntax errors, it'll be nil.
if definition_file == nil then
--Spit out a warning and return nil.print("Attempt to load an invalid file (inexistent or syntax errors?): "
..sprite_def)
return nil
end

We start by checking if the user has passed us a nil value, and aborting if that's the case. Following, we use loadfile(file) and then check whether the file was successfully loaded or not, as it returns nil on error (file not found, bad syntax, etcetera). If we get a nil value, then there is an error. We report the problem by printing to the console and return nil (so the game can continue even on failure).

If the loadfile function return non-nil, then we are good to go as the file exists and is valid. So we need to run the file and check its version.

local old_sprite = sprite_bank [sprite_def]
sprite_bank [sprite_def] = definition_file()
--Check the version to verify if it is compatible with this one.
if sprite_bank[sprite_def].serialization_version ~= ManagerVersion then
print("Attempt to load file with incompatible versions: "..sprite_def)
print("Expected version "..ManagerVersion..", got version "
..sprite_bank[sprite_def].serialization_version.." .")
sprite_bank[sprite_def] = old_sprite -- Undo the changes due to error-- Return old value (nil if not previously loaded)
return sprite_bank[sprite_def]
end

We start by saving the previous content of the sprite. If it wasn't loaded previously, that will be nil. This is done in case the loading fails and we need to revert it at a future point.

Then the second line runs the previously loaded file by calling definition_file as if it was a function. It stores the returned value in our sprite_bank map under an index that is the file path passed to this function. If there was another sprite here, it is overwritten, this allows for hot-reloads while a game is still running, really handy. Just remember to reset the instance if you hot-reload something (or you may crash your game). We could also use dofile() as we did before, but dofile loads the file before running it and this file was already loaded when we checked its validity.

We then compare the versions of both (Manager and Sprite) and report any problems in the console, aborting if they are incompatible. If it is invalid, we need to undo the changes and report it in the console.

The last resource we need to make sure exists and is valid is the image.

As the last step we need to load the image. We first cache the sprite_sheet path (so I don't need to write sprite_bank[sprite_def].sprite_sheet every time) and backup the old image, there's no problem if it is nil. Now we try to load the image by using the Löve2D newImage function (docs here).

Once the image is loaded, we need to check if Löve2D returned nil. If it did, our image couldn't be loaded properly. So, we need to undo what changes have been made by reverting both the image and the sprite to their previous state. We then return the new value (or the old in case of error) to the user.

And that is it for the LoadSprite function. As you can see, you can call it several times for the same sprite and it will only load it once, overwriting if duplicate. That's what we wanted, as this is the static data, fix data, that we will share between all the instances of a given sprite. Being able to hot-reload is a plus.

Sprite Instances

Now I ask you, what does the LoadSprite function do? It grabs all of a sprite's static data and prepares the necessary resources (the image). We can finally start creating a lot of different instances, each with their own set of dynamic values.

But how do we prepare a new instance? If you remember from the beginning of this guide there is some data that we need for every instance. Creating a new instance is as easy as preparing a table with that data inside in their default values. We also want to make sure a sprite is loaded before creating the instance. This what the GetInstance function looks like:

Much simpler than the last one isn't it? First we do some simple error checking to check for misuse and if the sprite is ready and, if it is not, try and load it. Abort if necessary, returning nil.

Updating an Sprite Instance

Of course, we need our sprite instances to change their current frame. And this is what the UpdateInstance is here for. We simply call it, pass along the elapsed time from the last update and it will get everything updated.

function UpdateInstance(spr, dt)
--Increment the internal counter.
spr.elapsed_time = spr.elapsed_time + dt
--We check we need to change the current frame.
if spr.elapsed_time > spr.sprite.frame_duration * spr.time_scale then
--Check if we are at the last frame.-- # returns the total entries of an array.
if spr.curr_frame < #spr.sprite.animations[spr.curr_anim] then
-- Not on last frame, increment.
spr.curr_frame = spr.curr_frame + 1
else
-- Last frame, loop back to 1.
spr.curr_frame = 1
end
-- Reset internal counter on frame change.
spr.elapsed_time = 0
end
end

The first thing we do when updating an instance is incrementing its internal counter. When this counter exceeds the frame duration (adjusted with the instance's time_scale) we skip to the next frame. If this frame is the last one, we revert back to frame one. Whenever we change the frame, we reset the counter to 0. Note that the time_scale multiplies the frame_duration. So, if it is higher than 1 it will slow the animation down, while values smaller than 1 will make it faster. Any negative values or 0 sets the speed to the maximum (1:1 with the game's fps).

That's it, update counter and check time then change frame and reset counter if needed.

Drawing an Instance

Ok, now we have all our static data in place, we have our image loaded, a central map where we can get our static data reference from, the same with our image. We can also get instances of our unique sprites easily as well as update them with a single function call. There's just on thing missing: drawing. We still can't draw our sprite!

With all that data so neatly organized, drawing the correct rectangle is really straight forward:

A single call to Löve2D draw function and we are done! I mean it! That is all it takes! The walls of code on the previous sections have reduced the last two ones into really small chunks with no loops at all. That's good, since this is the part that'll be called repeatedly at runtime.

This is our final AnimatedSprite.lua file:

AnimatedSprite.lua:

--[[
AnimatedSprite.lua - 2014
Copyright Dejaime Antônio de Oliveira Neto, 2014
Released under the MIT license.
Visit for more information:
http://opensource.org/licenses/MIT
]]print("AnimatedSprite.lua loaded")
local ManagerVersion = 1.0
sprite_bank = {} --Map with all the sprite definitions
image_bank = {} --Contains all images that were already loaded
function LoadSprite (sprite_def)
if sprite_def == nil then return nil end
--Load the sprite definition file to ensure it exists
local definition_file = loadfile(sprite_def)
--If the file doesn't exist or has syntax errors, it'll be nil.
if definition_file == nil then
--Spit out a warning and return nil.print("Attempt to load an invalid file (inexistent or syntax errors?): "
..sprite_def)
return nil
end
--[[Loading the sprite definition as an entry in our table.
We can execute the file by calling it as a function
with these () as we loaded with loadfile previously.
If we used dofile with an invalid file path our program
would crash.
At this point, executing the file will load all the necessary
information in a single call. There's no need to parse
this of serialization.
]]
local old_sprite = sprite_bank [sprite_def]
sprite_bank [sprite_def] = definition_file()
--Check the version to verify if it is compatible with this one.
if sprite_bank[sprite_def].serialization_version ~= ManagerVersion then
print("Attempt to load file with incompatible versions: "..sprite_def)
print("Expected version "..ManagerVersion..", got version "
..sprite_bank[sprite_def].serialization_version.." .")
sprite_bank[sprite_def] = old_sprite -- Undo the changes due to error-- Return old value (nil if not previously loaded)
return sprite_bank[sprite_def]
end
--All we need to do now is check if the image exist-- and load it.--Storing the path to the image in a variable (to add readability)
local sprite_sheet = sprite_bank[sprite_def].sprite_sheet
--Load the image.
local old_image = image_bank [sprite_sheet]
image_bank [sprite_sheet] = love.graphics.newImage(sprite_sheet)
--Check if the loaded image is valid.
if image_bank[sprite_sheet] == nil then
-- Invalid image, reverting all changes
image_bank [sprite_sheet] = old_image -- Revert image
sprite_bank[sprite_def] = old_sprite -- Revert spriteprint("Failed loading sprite "..sprite_def..", invalid image path ( "
..sprite_sheet.." ).")
end
return sprite_bank [sprite_def]
end
function GetInstance (sprite_def)
if sprite_def == nil then return nil end -- invalid use
if sprite_bank[sprite_def] == nil then
--Sprite not loaded attempting to load; abort on failure.
if LoadSprite (sprite_def) == nil then return nil end
end
--All set, return the default table.
return {
sprite = sprite_bank[sprite_def], --Sprite reference--Sets the animation as the first one in the list.
curr_anim = sprite_bank[sprite_def].animations_names[1],
curr_frame = 1,
elapsed_time = 0,
size_scale = 1,
time_scale = 1,
rotation = 0,
flip_h = 1,
flip_v = 1
}
end
function UpdateInstance(spr, dt)
--Increment the internal counter.
spr.elapsed_time = spr.elapsed_time + dt
--We check we need to change the current frame.
if spr.elapsed_time > spr.sprite.frame_duration * spr.time_scale then
--Check if we are at the last frame.-- # returns the total entries of an array.
if spr.curr_frame < #spr.sprite.animations[spr.curr_anim] then
-- Not on last frame, increment.
spr.curr_frame = spr.curr_frame + 1
else
-- Last frame, loop back to 1.
spr.curr_frame = 1
end
-- Reset internal counter on frame change.
spr.elapsed_time = 0
end
end
function DrawInstance (spr, x, y)
love.graphics.draw (
image_bank[spr.sprite.sprite_sheet], --The image--Current frame of the current animation
spr.sprite.animations[spr.curr_anim][spr.curr_frame],
x,
y,
spr.rotation,
spr.size_scale,
spr.size_scale,
flip_h,
flip_v
)
end

Using the Sprite

Now that we have our sprite information serialized as well as means of loading all its resources, checking for errors and instantiating new independent sprites, all we need to do is use it!

The simplest way to do it would be creating it and updating/drawing it on every frame:

With only this handful of lines you get a sprite on its default animation (idle), scale and speed rendering at [50, 50] in the screen. This is what it looks like:

Nice huh? But this is what we can do with just one line of code on each Löve2D callbacks, as simple as it can be. Our simple sprite system can do more than that, can scale, flip, accelerate, rotate and all that stuff. It can also render more than one of the same sprite at a given time without them having to be synchronized. This is the main.lua I used to make the video at the top of the post:

You can download the entire source code (with the image) through this link here.

This is it!Our next steps are to change this sprite system to use what's called a SpriteBatch, return an error sprite when something goes wrong (something like a red square) instead of returning nil. And then creating a tiled map rendering system.

Wednesday, June 18, 2014

Today I'm going to talk about Löve2D, an easy to use Lua game development framework. It is licensed under the zlib license, so there is nothing to worry about its license.

The biggest advantage of Löve2D is that you can get things going really fast with it, it is easy to learn and Lua is extremely flexible. This environment requires less planning than my usual C++/SDL, but you still need to plan a bit ahead. The counterpart is that we have breaking changes in every major version, but no backwards compatibility. So, a game made with Löve2D 0.8 probably won't work in 0.9.1, what I consider a major issue. You should always distribute your game with the binary part included to avoid this problem (more info on this here).

Keep in mind that the usual structure of a Löve2D game leaves your source code accessible, so it is not ideal for commercial projects where you wouldn't want to publish your source code. Still, this makes games made with it very extensible, especially if you release the source code as a .love file. Modding the game is as easy as adding some extra Lua files and editing a line or two in the existing ones.

Hello World!

All the code in this post is released under the MIT License.

The Löve2D framework is partially based on callbacks. These are the main ones:

love.load() - A function called in the initialization, runs only once

love.update(dt) - Called every frame, dt is the elapsed time since last call

love.draw() - Called on the draw step, this is where your render logic comes

love.mousepressed(x, y, button) - called when a mouse button is pressed

love.mousereleased(x, y, button) - as above, when released

love.keypressed(key) - Called when a key is pressed on the keyboard

love.keyreleased(key) - as above, when released

love.focus(f) - Called when the game loses/gains focus

Löve2D Hello World:

function love.draw ()
love.graphics.print ("Hello World!")
end

Löve2D requires that you have a file named main.lua. It is the core file for your game, and will always be executed by Löve2D. You should include in this file all the callbacks you want from the list above (they are optional though). In this example main.lua file I only overwrite the love.draw function and all this does is print "Hello World!" at the window origin (top-left corner) in white text and black background. This function is called every frame, so remember it is actually being written over and over again.

The rendering usually clocks at 60Hz and you have an easy way to access it. The love.timer.getFPS() function returns the FPS, straight and easy.

This main.lua file loads an image called Lena-small.png and draws it wherever we click with the mouse. It also keeps track of the running time (with update() to exemplify). You can use whatever image you want in here, this is just an example.

In here, we are using four different callbacks.
The load() function is called first thing when our game is loaded by Löve2D, and never touched again. The update(dt) function is where we should update our simulation using the elapsed time -dt-. Similarly, mousepressed() is called whenever a button of the mouse is pressed, any button, or the scroll changes its position.

As you can see, the module love.graphics is responsible for anything related to rendering. So, if you are going to load, render, manipulate or do anything with graphics, you'll touch the love.graphics module.

Did you notice that I called love.draw while drawX and drawY were still nil? These variables are only created on the first call to the love.mousepressed callback. Löve2D usually has default values, (0,0) in this case.

Quick Questions:

What happens if we add the keyword local before drawY = y in the love.mousepressed function?

As above, but with drawX? (You can find the love.graphics.draw docs here)

Answers:

The image would move only horizontally, as the drawY is a local variable inside the mouse callback inaccessible globally. This would make drawY nil, so the drawing function receive only drawX love.graphics.draw(Lena, drawX).

The script would crash on the first click as drawY ceases to be nil and turns into a number. The draw function would assume a form that expects an image, a quad (more on that soon) and the x and y coordinates as the first 4 parameters but, as drawX was nil, the quad is invalid and the script crashes. The drawY parameter would actually be interpreted as the x coordinate, in this case.

Wrapping Up

What have we learnt here?

Löve2D has multiple callback functions that you can overload to create your game.

The most important callbacks are love.update, love.draw and the input ones. These are probably the bare minimum for a game.

Most functions have default values for when you don't want to pass on something (works pretty much the same way as in C++).

Variable scopes can get messy, plan ahead. This will become especially visible when we start to move up into more complex stuff.

What's Next?

In the next post, we'll see how to draw an animated sprite with Löve2D, how to serialize it, initialize it and render the correct rectangles from the spritesheet. To do so we should go through some basics of data serialization, one of the strongest points of Lua.

Before going any further, make sure you run this code in your own machine and mess around a bit with it. Try making the image move around with the arrow keys (the key codes are simply 'up,' 'left,' 'right' and 'down'), not only with the mouse. A possible implementation can be found below.

Tuesday, June 10, 2014

Warning: there is an update of the blog itself on the next paragraphs. You may skip to the Lua section below if you're not interested.

This blog has been inactive for quite some time as I took some time away from my game development hobby. Good news is: something happened that made me regret this immensely, so I am back. Bad news is: I must focus on my main personal project amap, period in which I'll leave our C++ game unattended given the giant amount of work it would be (as I chose to code the engine from SDL up).

I don't plan on abandoning this though, as I owe this same thing that brought me back to game development so quickly to this very blog. Creating a quality C++ framework that is flexible yet easy to use is something that is sure to take months of work. But I can't spare all this time right now nor want to take the easy route and create lower quality stuff as I wouldn't learn anything from it, in contrast to creating a quality one with which I, myself, would learn a lot by doing. So I'll change this blog's direction for the time being and retake its old course some months from now.

For now, I'll change my focus into getting results faster. I'll be using Löve2D for at least the next weeks, trying to get a hold of how it all works. It is a Lua framework, but my choice has nothing to do with the language, but with the framework itself. It has one of the easiest interfaces I've seen and, if necessary, I can always step into C and do what's necessary, although I don't believe it would really be a necessity.

Lua

It is a scripting language very popular on the game development world, possibly the most popular. The language itself is too big to fit in a blog post, and I am not proficient enough to give a good overview, but I'll still give you guys some short snippets to show the basics of the language.

HelloWorld.lua

print("Hello World!") --Self Explanatory

This print command would output the line to the console, as simple as that. To run this lua script, just type issue the console command [ lua path/HelloWorld.lua ] and it should output the message.

Lua doesn't support the most common syntaxes for most things, what can be a pain sometimes, but you'll soon get the hang of how it works. In the next example, I'll create a Lua array (table with numeric indexes) with two strings in it, and then print them.

Hell-o World.lua

myTable here is an 'array' with two entries, that we can access by their numeric values (since it is not a map). The .. operator concatenates strings, really useful.

Did you notice that Lua's array indexes actually start with 1? Some people consider this the best thing about Lua, personally I don't like it as I already had to write workarounds for this when interfacing with C. Doesn't make much difference in the end though.

If you try to use a variable that doesn't exist, it will be treated as nil. nil in Lua is a special type of data that means "no data". It is treated as false when used in conditionals.

Lua uses double for all its numeric operations. If you want to change this behavior, you can do so by editing the Lua configuration file. More details on this can be found here.

Notice how a table is printed. First, Lua warns you that it is printing a table, and then it spits its memory address. This happens because it doesn't know exactly how to print a table, but, in case you want Lua to print your table in a given manner, you can use what's called a metatable. You can think of this as overloading some behaviors, but it is not exactly what is happening. If you wish to know more, take a look here.

As you can see, metatables must be explicitly set. In here, we used __tostring, but one can also overwrite several behaviors such as addition (__add), equality (__eq), userdata garbage collection (__gc, not for tables).

That # operator (#table) returns the total number of entries in a given array.

Other notable thing about this snippet is the word local, right before resultingString. In Lua, everything is defaulted as global, but sometimes you'll want to set variables as local as they can be >3x faster to operate with (as in my benchmarks).

As you can see, global variables are heavier than file-level local variables which are, in turn, heavier than function-level local variables. This is extremely situational though, but sometimes it is worth it copying a global into a local variable if you're going to perform too many operations with it. At least make the test wherever you think globals are holding you back and see if there is any performance gain. I guess this is enough to illustrate the importance of the local keyword in Lua. Keep this in mind when designing performance sensitive code.

Here, you can see that Lua can hold functions as variables. That is why so many Lua frameworks rely on callbacks, it is simply convenient to use callbacks in Lua.

Other important thing, especially when you guys go around hunting for examples in Lua, is the difference between . and : .
When using period, the function is called as one would expect. But the colon is actually OO eye candy, it passes the table itself to the function when calling it. In other words, table:function(p1, p2) is the same as table.function(table, p1, p2) .

Did you notice that the last call had its parameters displaced due to the myTable variable being passed along in the first slot? You need to be careful with this kind of thing, since in Lua there is no type checking, finding a problem where you used a colon instead of a period can be quite frustrating. The key is to be consistent and try to use one of the two whenever possible. It is up to personal preference though.

Lua is a really flexible language, and I certainly didn't do it justice with these few snippets. But I hope this was a good introduction nonetheless, and maybe sparked some interest. I'll be using it in the next posts while using Löve2D.

Tuesday, April 8, 2014

After a lot of time finding excuses not to work on my main projects, this one got to a point where I can no longer waste time on it. I can't think of anything I'd want to add to it as of now, and now I have no other option but to go back to the code SpaceRock Miners... That probably means it is complete! Well, kind of amateurish, but that's exactly what I am, don't judge me. I am simply adding the files to my projects and they are compiled alongside with my code. It is still missing a decent build mechanism, but this has been postponed indefinitely.