Understanding the Framework
As I’m sure you know, the difference between a framework and a library is that a framework has a “batteries included” approach, and that means that they come loaded with opinions. With that in mind…
Read the documentation!
This really should go without saying. Every framework is going to be different. While you don’t need to dive deep into every method just yet, you should take the time to read at least all of the introductory text because it will tell you all of the steps you need to take to get your project actually started. You should also take the time to familliarize yourself with any special conventions they mention as well as all specialty datatypes and structures that the framework provides; chances are, if they give them to you, you’ll need it! You can, however, skip those for any module you know you will not be using (for instance, networking if your game is only meant to be played locally).
Understand callbacks
Almost every single framework is going to provide three callbacks which you will need to define in order to get the game to run: one to load the data you need for the game, one to update all of your objects, and another to draw to the screen. Depending on your framework, some methods will only work in the context of the callback they are in. For instance, in LÖVE, you cannot call love.graphics.draw()
in love.load()
. This makes logical sense because in this case, love.load()
might be called before the graphics system has fully initialized. But in many cases, where you actually put your code is not necessarily a hard and fast rule. Who is to stop you from making some last-second pixel adjustments to your draw commands right in the draw callback? Nonetheless, it’s generally wise to keep the types of code segregated. You’ll understand why as you go on.
The Load callback
To be perfectly honest, a better name for this might be preload. How often is it that you launch a game and you’re just suddenly right in the level? Pretty much every game will start with some sort of introductory sequence or menu. So rather than considering this as a place where you put in the code to load your complete level, you should consider this to be the place to initialize any of the systems you might need and to pre-emptively load any large datasets that are going to be common for each scene or level you will create.
In addition to your regular initialization and sundry file loading routines, the load callback usually also has an arguement passed to it that will help your project in the long run. LÖVE’s load callback syntax is as such:
love.load( arg, unfilteredArg )
Both of those arguements are the arguements passed into the LÖVE executable, just in different ways. That allows you to, for instance, use it to give testers a way to get right to the thing they need to get working on. You can just tell them to run yourgame --level=22 --cheats=infinitehealth
. This is where you’d write the code to skip to that point in the gameplay.
The Update callback
The update callback is one of the easiest things to misunderstand, because update callback is generally where time starts to become an important factor. Like the load callback, update also has an arguement.
love.update( dt )
dt is short for Δtime - or delta time, if you prefer. dt is a number that represents the number of seconds that have passed since the last time love.update()
was called. This is important because this allows us to make sure that animations are based on the actual time that passes rather than the framerate of the system it’s being run on. This is especially important if you have very complex operations being done and there is a chance that you might have slowdown. We’ll go a little bit further into time later in this chapter.
The other callbacks
I’ve mentioned the draw callback already. In LÖVE, the syntax is thus:
love.draw( )
No arguements. It’s pretty self-explanitory.
But it’s also really important to know that there are almost certainly other callbacks that you will need to be aware of. LÖVE for instance includes love.conf(t)
which is called before it loads the file main.lua
so you can configure the LÖVE framework. Most will also let you overload the error handler which can be particularly handy for debugging (or hiding your terrible coding sins on release, naughty). Or they can have a callback for when you close the game, giving you a chance to save the game state or to appologize for the user when they quit in the middle of an online multiplayer match.
Next: Animation and time