I would like to add some scripting to my models/actors. When a new model gets loaded, or a script is changed, the actor reacts.
For now, I have a base Lua class which has, for example, a Update() function and each model/actor should overload this function. But how to implement it? The main problem is that each model needs a unique name for the class,…
-
I was thinking of a table whose key values are the actorID(unique) and the value would be a class inherited from the baseclass, but it’s a bit difficult when the script gets reloaded.
Objects[ActorID] = Model(paramater)Objects[ActorID].Update = function() print("Update: actor 1") end -
Maybe it’s also possible to create a new lua state for each actor.
I got the inspiration for this, from the Leadwerks engine: http://www.youtube.com/watch?v=z-EuS1EYk8o
If anyone knows a good book for scripting in game engines please tell me
I think i got it:
Here is some pseudo code:
OnNewActorCreated:
//Add actor
Objects[param.ID] = createClass(baseclass)
//Check if this actor has a script to run.
if param.hasScript then
//Add the new ID to the script
Scripts[param.filename][param.ID]
Entity = Objects[param.ID]
doFile(param.filename)
Entity = nil
end
OnFileChanged:
foreach id in Scripts[changedfile] do
Entity = Objects[id]
dofile(changedfile)
Entity = nil
end
Example Script:
//check if Entity is valid
if not Entity then
print("[Error] Entity is invalid")
else
function Entity:Update()
print(self.name)
end
end
Could work 😉
The way the engine in the youtube video works does not rely on an overloaded Update function. The reason they have base classes is to provide default behavior and a common interface to their objects, but is not related to actually updating anything.
They are using functionality presented by the OS to listen for file updates (see this SO question for more info on that) and then simply execute the script in the game’s lua_State. Since the scripts only modify the type definitions (tables and metatables), when you reload the script (via simple luaL_dofile or equivalent I presume) the new definitions overwrite the old ones and lua happily chugs along using the updated behavior. If you really squint and look at the code the video shows in the editor, you’ll notice they are just defining functions, as opposed to running Update methods.
As a final note – if you create new lua_States for each actor, then you will lose the ability to freely pass things around between them in Lua, and will have to write C++ code to manually pass data between two (or more) lua_States.
Edit: With regards to inheritance from a common base object: modifying its metatable will alter the behavior of all objects, so we need to protect against that. One way would be to surround the entity script with guards against modifying the actual common metatable. Before loading the script we save a reference to the base metatable and replace it with a copy that can be used by the script.
In this way the script does not need to create its own metatable and does not need to know how the rest of the engine will refer to it. Instead it just uses the Entity one. Once the script is done defining it’s derived behavior, we can give its copy of Entity a new name (one based on the name of the script file, the name of the world object, etc.) and restore Entity to the original reference.
Aside from the above, we gain the added benefit of not persisting changes through different updates. Every time we want to change the script during runtime, we repeat the process and can be confident that if something was added in a previous update it will not remain after we execute an update that removes it. If we simply let the script overwrite metatables, then we cannot remove functions and members without explicitly setting them to
nil.