There are many reasons to use Lua with C++. One of them is that you can put some of the logic from C++ code into scripts, so you can easily change them without the need or recompilation. You can also write some good interfaces, so the scripts are easy enough for even non-coders to write them. Lua is free, Lua is fast, Lua is used in game development quite often.

While there are plenty of good articles about using Lua with C++, I think there are not enough articles about how to use Lua in real projects.

This article is one of the many articles I plan to write. Here are some topics which my articles will cover:

Entity creation and other basic stuff (you’re reading this now)

How to implement entity creation

Managing Lua state and cleaning up

Scriptable state machines

Events and callbacks

The stuff described in the articles was mostly discovered during the development of my game called Re:creation.

I don’t think the methods here are perfect, but they’re good enough, fast and work well for me. So, your feedback is welcome. Feel free to leave comments and write e-mails to me about the stuff I can do better. I’m interested in hearing about your Lua/C++ usage!

While this is a C++ article, I think you can implement most of the things mentioned here in your favourite language. I’ll use Lua C API and LuaBridge for examples, so I recommend to read the following articles if you’re not familiar with them:

Entity creation

My game’s engine is build around entity/component/system (ECS) model. Because there are lots of different ways to implement ECS. I’ll explain my approach.

Entity is every object you see (and don’t see, e.g. collision boxes, triggers, etc.) in the game: rocks, tress, NPC’s, etc. Each entity has a number of components which are stored in std::vector<Component*>.

Component is a data about a particular aspect of an entity. There are a number of different components: GraphicsComponent (contains info about sprite, texture, animations, etc.), CollisionComponent (information about bounding box, collision response function, etc.), HealthComponent, etc.

Systems are where logic lives. They store a list of pointers to components of currently active entities which they iterate through. They don’t care which entity the component belongs to. For example, RenderingSystem iterates through GraphicsComponent‘s and renders them in a particular order. CollisionSystem checks collisions between entities using their CollisionComponent‘s , etc.

What’s cool about ECS is that there is no complex inheritance tree and this solves lots of problems (blob-classes, deadly diamond problem, etc.).

Entities are created by creating components with different parameters and adding them to entity’s component list. Here’s a simple example of how it looks in C++ code:

Entity e; auto gc = new GraphicsComponent; gc->setSprite(entitySprite); ... // setting component properties e.addComponent(gc); ...

Here’s how I can get components by the class name (get function uses dynamic_cast to do this):

auto gc = e->get<GraphicsComponent>(); // gc is nullptr if entity doesn't have GraphicsComponent

Okay, pretty cool. But how do you create specific entities, like an NPC or a house? A Factory pattern may be used, but eventually you’ll have lots of different types of entities and customizing entity definitions would cause recompilation which is not very good. It will also be impossible for non-coders to create new entities or modify existing ones.

This is where Lua helps a lot.

Here’s an example of a simple Lua script:

Note, that this script doesn’t create an entity. It’s simply used to obtain data to set different components parameters and then create Entity in C++. I create template entity using information from the script and then create instances of this entity class by copying. Here’s how the entity creation process works in general:

When loading template entity:

Get entity table from script

Get table keys list (this gives us a list of components to create)

Create each component, passing corresponding table to component constructor (you’ll need to create an instance of class by class name. I’ll show one cool way to do that in the next article)

When creating other entities of this type

Copy every component from template entity

Assign unique properties of this entity (position, state, etc.)

Why didn’t I expose component classes to Lua?

You can easily create C++ objects in Lua with LuaBridge (or a binding of your choice) like this:

someObject = SomeClass()

More info here

So why do I use tables and create components in C++ instead of creating them in Lua? There’s a number of reasons for this:

Scripts look simpler this way

Imagine if the script looked something like this:

tree = function() gc = GraphicsComponent() gc.setFilename("res/images/tree.png") gc.setZ(0) gc.setAnimated(false) gc.setFrame(64, 0, 64, 74) cc = CollisionComponent() cc.setType("Solid") cc.setBoundingBox(14, 60, 32, 10) tree = Entity() tree.addComponent(gc) tree.addComponent(cc) return tree end

I don’t think that this script looks easier than the one I’ve shown before. And it may be difficult to read, understand and change for non-programmers.

There’s no need for Lua to know about components at all. It’s better to hide implementation details in C++

Here’s an example of how I can set animation in a Lua script in my game:

setAnimation(entity, "some_animation")

This calls this function in C++:

void setAnimation(Entity* e, const std::string& animationName) { auto gc = e->get<GraphicsComponent>(); if(gc) { gc->setAnimation(animationName); } else { ... // write about error in a log! } }

Imagine if I had to do it like this in Lua each time I wanted to set some animation:

gc = entity.get("GraphicsComponent") if(gc ~= nil) then gc.setAnimation("some_animation") else ... -- print about error end

Not that easy anymore. And I have to do error checking in Lua. I think it’s a lot better to do it in C++ and hide implementation details there. Some functions may be even more complex in C++ but look very simple in Lua. Writing error checking in Lua would make scripts confusing and error-prone.

You can optimize entity creation by moving some entity declarations into JSON/XML/binary files

You may notice that the Lua table presented before doesn’t hold any information which cannot be stored in JSON or XML. And this is true. If you create every component and entity in C++, you can easily move entity descriptions from Lua to JSON or XML to speed things up.

So what’s the point of using Lua then? Lua is used for adding different functions to entities and this makes scripting very enjoyable and lets me put lots of code in Lua instead of C++. This is very awesome, because it lets me easily change entity behaviour with no recompilation and hardcore a lot less. I can even change entity properties and functions while the game is still running! Isn’t this great?

Scripting entity behaviour with Lua

Here’s an example when Lua functions are used to provide different entity behaviour.

For example, different entities may react differently to collisions.

Suppose I want to create a cute ghost which blushes when it collides with some entity (it also damages it. This is absurd, but hey, it’s just an example!). Here’s how it would look in the script:

Here’s how it works: when CollisionSystem finds a collision between two entities, it calls a collide function which is stored in entity’s CollisionComponent. It also passes two arguments to the function: this – a pointer to the entity of the type which this function belongs to, second – a pointer to the entity which collided with this (this is a name of a variable I use, not a Lua keyword!)

Conclusion

This article got pretty big so I’ve decided to explain implementation details in the next part. You’ll learn some cool patterns and Lua stuff along the way. The next article will cover:

Entity creation process

Getting list of table keys

Creating components by their names in C++

Adding and using simple Lua callbacks to common events (collision, damage, etc.)

I hope that this article sparkled your interest in Lua. If you want to learn more, you can read my Lua articles on this blog (especially this one which will help you to configure Lua for the next article) to learn more about Lua or read some of my dev logs to see how I use Lua to solve problems during the development. Stay tuned, the next article will cover lots of stuff!