I'm currently trying to implement a component-based entity system, where an entity is basically just an ID and some helper methods tying a bunch of components together to form a game object. Some goals of that include:
- Components only contain state (e.g. position, health, ammo count) => logic goes into "systems", which process these components and their state (e.g. PhysicsSystem, RenderSystem, etc.)
- I want to implement components and systems both in pure C# and through scripting (Lua). Basically I want to be able to define completely new components and systems directly in Lua without having to recompile my C# source.
Now I'm looking for ideas on how to handle this efficiently und consistently, so I don't need to use different syntax to access C# components or Lua components, for example.
My current approach would be to implement C# components using regular, public properties, probably decorated with some attributes telling the editor about default values and stuff. Then I'd have a C# class "ScriptComponent", which just wraps a Lua table internally with this table being created by a script and holding all the state of that particular component type. I don't really want to access that state much from the C# side, as I wouldn't know at compile time, what ScriptComponents with what properties would be available to me. Still, the editor will need to access that, but a simple interface like the following should suffice:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
This would simply access the Lua table and set and retrieve those properties from Lua and it could easily be included in the pure C# components as well (but use the regular C# properties then, through reflection or something). This would only be used in the editor, not by regular game code, so performance isn't as important here. It would make it necessary to generate or handwrite some component descriptions documenting what properties a certain component type actually offers, but that wouldn't be a huge issue and could be sufficiently automated.
However, how to access components from the Lua side? If I make a call to something like getComponentsFromEntity(ENTITY_ID)
I'll probably just get a bunch of native C# components, including "ScriptComponent", as userdata. Accessing the values from the wrapped Lua table would result in me calling the GetProperty<T>(..)
method instead of accessing the properties directly, like with the other C# components.
Maybe write a special getComponentsFromEntity()
method only to be called from Lua, which returns all the native C# components as userdata, except for "ScriptComponent", where it'll return the wrapped table instead. But there'll be other component-related methods and I don't really want to duplicate all these methods both for being called from C# code or from Lua script.
The ultimate goal would be to handle all types of components the same, with no special case syntax differentiating between native components and Lua components - especially from the Lua side. E.g. I'd like to be able to write a Lua script like that:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
The script shouldn't care what kind of component it actually got and I'd like to use the same methods I'd use from the C# side to retrieve, add or remove components.
Maybe there are some sample implementations of integrating scripting with entity systems like that?