Some people aren’t very interested in programming, and that’s fine. You might want to skip this post if you’re one of them.
I wanted to detail some of the technology I’ve used to make Pocket Titans. There’s nothing dramatic here or anything, it’s all pretty standard stuff but might be interesting to someone thinking of getting in to game programming.
Firstly, if you’re going to write a game like Pocket Titans, don’t do what I did, instead get yourself a Unity license. It’ll easily handle all the requirements here and do a great job. Why didn’t I? Because I like writing my own tech and this project was started mostly for fun so I did the bits I find fun, and that meant no engine.
I decided I wanted to write the majority of the gameplay code in Lua. Lua is a great programming language with a slightly ugly syntax, its easy to integrate with an engine and executes pretty speedily. Lua is a dynamic language perfect for the gameplay domain (in my opinion), and this has the handy side-benefit of enforcing a split between “game” and “engine”, where the “engine” is C++ and the “game” is Lua. There are no game-specific C++ lines in the whole game beyond a single start-up function which tells the engine where everything is.
Underneath Lua I use a C++ component / entity model for all game objects. All components (except a specific script one detailed below) know nothing about the Lua integration which is important to ensure modularity.
Communication between components (and between entities) is through a messaging system. The Lua integration also hooks in here by registering for particular messages and calling a named Lua function using the message’s arguments.
Here’s a short code example:
local e = Entity.New( "ENT_TEST" )
e.widget = Widget.New( e )
The first line above creates an empty entity called ENT_TEST. It has nothing but a name (hashed) and an empty list of components.
The Lua Entity.New function causes the entity to be put on the Lua stack. This is done by adding a “hidden” (ie not explicity handled by the Lua integration) component called ComponentLua to it. That component creates an empty Lua table, associates it with the entity and pushes it on the stack. That table is then stored in the “e” Lua variable. There’s a slight cheat here, which is that operations in Lua which look like they’re operating on the entity are in fact operating on the ComponentLua.
The second line calls a function called Widget.New using the Lua table e as an argument. Since the function is told to expect an entity the Lua integration checks that e is associated with one (via a ComponentLua) and calls the Widget.New C++ function with the entity as the argument. That causes a “Widget” component to be created and returned to Lua. A generic component is pushed on the Lua stack as user data linked to the component’s address.