How to directly map a Lua variable to a C ++ variable?

I am working on a C ++ game engine using Lua to define NPCs.

I can define an NPC prototype as follows:

orc = { name = "Generic Orc", health = 100 } function orc:onIdle() print("Orc idles...") end 

and then create an instance of "Orc" using entitySpawn(orc) . This is a C ++ function that reads values โ€‹โ€‹such as health and name from a given table, creates an Entity object in C ++ with the given values โ€‹โ€‹and, in addition, creates a Lua table for a specific NPC.

Now I would like to have a direct connection between the orc.health variable in Lua and the mHealth member mHealth corresponding Entity object in C ++, so I could assign a value in Lua and use it instantly in C ++ and vice versa.

Is it possible? Or do I need to use setter / getter functions? I took a look at the light user data and got to the point of storing a pointer to a C ++ variable in Lua, but couldn't assign a value.

+6
source share
2 answers

It is possible. I assume entitySpawn returns a table created for a C ++ object. I also assume that you can expose a function from C ++ that takes an entity table and returns the current state of health, and similarly for customization. (To implement this, you can use the easy userdata pointer for a C ++ object as a member of this table.)

So the ugly way would look like this:

 local myOrc = entitySpawn(orc) local curHealth = getEntityHealth(myOrc) setEntityHealth(myOrc, curHealth + 10) 

To make it more beautiful, we can have fun with metatables. First, we will place accessors for all the properties we care about.

 entityGetters = { health = getEntityHealth, -- ... } entitySetters = { health = setEntityHealth, -- ... } 

Then we will create a metatable that uses these functions to handle property assignments.

 entityMetatable = {} function entityMetatable:__index(key) local getter = entityGetters[key] if getter then return getter(self) else return nil end end function entityMetable:__newindex(key, value) local setter = entitySetters[key] if setter then return setter(self, value) end end 

Now you need to make entitySpawn assign a metatable. You would do this with the lua_setmetatable function.

 int entitySpawn(lua_State* L) { // ... // assuming that the returned table is on top of the stack lua_getglobal(L, "entityMetatable"); lua_setmetatable(L, -2); return 1; } 

Now you can write it beautifully:

 local myOrc = entitySpawn(orc) myOrc.health = myOrc.health + 10 

Note that this requires that the table returned by entitySpawn does not have a set of health properties. If so, then metatable will never consult on this property.

You can create entityGetters , entitySetters and entityMetatable , as well as __index and __newindex in C ++ instead of Lua, if that seems cleaner to you, but the general idea is the same.

+6
source

I donโ€™t have time to give you any code, but keep in mind that orc.health same as orc["health"] ; that is, orc is a table, and "health" is an element.

With that in mind, you can change the index and newindex your table to have your own specific behavior. Save your โ€œrealโ€ instance of orc as some private metadata, and then use it to update.

+2
source

Source: https://habr.com/ru/post/890174/


All Articles