Using Lua with C++. Using Lua scripts with C++ classes.

This part will show you how to register C++ classes in Lua, call member functions and how to apply scripts to something practical like putting object behaviour code in scripts.
I’m a game developer, so I’ve used examples related to gamedev but you can use Lua almost everywhere, so take a look even if you’re not interested in gamedev.
The code used in this article is as simple as possible while also remaining a complete example which you can run and compile.
I leave out the details which are irrelevant to focus on the main topic: scripts.

The first approach

Suppose you want to make NPCs which react differently to the player interacting with them.
First of all, we have a Guard which just says “Hello” and a witch, who heals the player if his health is low.

|Player walks around the town and talks with some npcs
Lucina: Hi! Come back when you're wounded.
Sam: Hello! Be safe!
|Player goes on a great adventure!
|but gets beaten up by some foes...
> Player: 5 HP
| Back to the town... Let's talk to the witch
Lucina: Hi! Let me heal you.
> Player: 10 HP

Cool, let’s now analyze how scripts can make this whole thing better.

Let’s look closer at Guard and Witch classes.
The only thing different about them is an interact function.
This will be the only difference between classes for the most friendly NPCs. Do we really need to make a new class for this?

We can use the Strategy pattern. But still, we have to create a new class for each new behaviour. And it’s all in the code. This is not very good especially if you’re working with someone who doesn’t know how to program. If another dev wants to change some NPC’s behaviour or add a new type of NPC, he has to ask the programmer to do it. This is not very productive.

And even if you’re a programmer, there are still nice things which scripting will give to you. One of the most important: you don’t have to recompile the code when you change something in scripts. You can even change object behaviour during runtime, reload the its script and continue playing the game. Isn’t it awesome?

Let’s get to the scripting!

Scripting

First of all, let’s get rid of Witch and Guard classes. We won’t need them anymore.
Let’s start by modifying Character class.

What has changed? First of all, we have a LuaRef pointer named interactFunc which we’ll use to call a Lua interact function. It’s a pointer because LuaRef doesn’t have a default constructor so you have to allocate memory for interactFunc once you get if from the script.
I’ll assume that each NPC will have its own Lua table to make things as simple as possible.

What if you want to create multiple objects that use the same interact function? Loading the interactFunc over and over seems inefficient.
You can handle it this way: create some “template” characters from which you will copy the interact function. Use shared_ptr for interactFunc for reference counting to see how many objects use the particular interact function.
We also have loadScript function which will load character’s name and an interact function from the script.

We just call Lua interact function using pointers to Character and Player. There’s exception handling. You can make some mistakes in interact function but that wouldn’t crash your program and you’ll see where you made this mistakes. Very useful.

You start registering class with this. Notice that class name in Lua may be different in C++. It’s convenient for them to be the same though.

addConstructor<void(*)(void)>()

Here’s how you add constructor. You have to specify its arguments using function pointer syntax. You can’t have overloaded constructors.

addProperty("name", &Character::getName, &Character::setName)

Lua can handle some member variables as properties. So you can write something like this in Lua:

characterName = character.name
character.name = "Some guy"

Getters and setters will be called for each operation with a property.
If you want the property to be read only, just pass a getter to addProperty method without a setter.

Adding functions is simple too:

addFunction("say", &Character::say)

And we end class registration with this function.

endClass()

We can register derived classes like this:

deriveClass<Player, Character>("Player")

Virtual methods work normally. No special syntax needed.
Here are some notes from LuaBridge manual:

The `deriveClass` takes two template arguments: the class to be registered, and its base class. Inherited methods do not have to be re-declared and will function normally in Lua. If a class has a base class that is not registered with Lua, there is no need to declare it as a subclass.

What’s next?

In the next chapter I’ll cover object creation and their lifetime.
I also plan to write a chapter which will show how I use scripts in my game (I’ve written a lot about that in my dev logs, but I need to organize it a bit). I don’t have classes which I have to register because I use Entity/Component/System model so things are a bit different there.
See ya next time!

If you’ve noticed mistakes or just want to provide some feedback, feel free to send me an e-mail: eliasdaler@yandex.ru

My tutorial will use it as reference but I’ll also try to show some practical examples and show what happens if you do some incorrect stuff (like changing value of const variable) and stuff like that. :)

Hey Elias, me again, sorry for bombarding you with questions, but I am trying to use the technique you used here with the interaction function but I’m trying to implement the collide function we previously discussed. From what I can tell this should work well, and the bounding box in the example gives me no trouble, however when I call my collide function I get an access violation runtime error (Meaning I am reading memory I shouldn’t be). Anyway here is my code:

Hey, no problem, feel free to ask as many questions as you need.
So, did you check didCollide function after loading it? It shouldn’t be nullptr and it’s LuaRef shoudn’t have mRef == -1. And can you show me your script, please?

Thanks again, I appreciate the help.
If by checking didCollide you mean doing if (didCollide) { … } then yes. The only difference between my code and the code in this article is that I load the function in the constructor of my class, as shown by one of your other articles. Ghost script: http://pastebin.com/2e7k8gRC
Then here is the loading/calling of didCollide: http://pastebin.com/pe5atppX

Hmm, pretty strange, this should work. If mRef in didCollide LuaRef equals to -1 then it means that something goes wrong. It’s hard to know what.
And by the way, you shouldn’t pass pointers to the function, you should pass references, so you should write:
(*didCollide)(*ent1, *ent2);

i have got question. let’s say we programing RTS (…strategy) and we need difference interaction for player, ghost, guard, and even not character ( for example chest ) how to write that code? use field name?

there shouldn’t be “delete interactFunc;” in the Character destructor. It’s a shared_ptr so it cleans itself up automatically. You shouldn’t give Character a destructor at all, the default compiler-generated one is fine.