For reference, here is the code I am testing:
There is a lot wrong here. You keep re-running your Lua-script; that's why it keeps getting reset. The other problem is that your script is creating a global function, so each time you run it, you're getting a new global function, which uses a new local
variable.
Stop using globals. Each NPC is a separate object. Therefore, it needs to have object-specific data.
behavior = "testBehavior.lua";
luaL_dofile(luaState, behavior);
This does not create any object-specific data. It simply runs a Lua script and completely discards any return values. Unless that script actually stores something object-specific globally, there won't be any object-specific data created.
What your Lua script needs to do is return a table that contains the object-specific data that the script needs for the object. The script should look like this:
local function onHit(self)
self.health = self.health - 5
end
return {
health = 10,
onHit = onHit,
}
Your C++ code needs to store this table in the NPC class and then use it. This is done easily enough via Luabind calls. Your constructor should look like this:
NPC::NPC(lua_State* L)
{
behavior = "testBehavior.lua";
int err = luaL_loadfile(L, behavior);
//Handle compiler errors. DON'T FORGET THIS!
luabind::object func = luabind::from_stack(L, -1);
lua_pop(L, 1);
luaData = func(); //Catch exceptions for runtime errors
lua_pop(L, 1);
}
Instead of having lua_State* luaState
in your class, you keep around a luabind::object luaData
in your class. If you need the lua_State
, you can always get one from the luabind::object
.
To call your Lua onHit
function, simply use the luabind::object
interface:
void NPC::onHit()
{
luaData["onHit"](luaData);
}
Note that you do not re-run the Lua script. That's what your problem was. You're just calling a function that the Lua script already defined.
Now, you seem to want to use locals instead of table memory. That's fine; it would prevent C++ code from directly accessing health
(not without trickery). And it would simplify our code, since we wouldn't have to pass luaData
to onHit
. You can do that in Lua with this:
local health = 10
local NPC = {}
function NPC.onHit()
health = health - 5
end
return NPC
The NPC constructor doesn't need to change; just our call to onHit
.
void NPC::onHit()
{
luaData["onHit"]();
}
If you're dead-set on using globals, you could play games with the environment, but that's rather complicated. It would provide guaranteed isolation between individual script invocations.