Actualmente estoy tratando de implementar un sistema de entidad basado en componentes, donde una entidad es básicamente una ID y algunos métodos auxiliares que unen un conjunto de componentes para formar un objeto de juego. Algunos objetivos de eso incluyen:
- Los componentes solo contienen estado (por ejemplo, posición, estado, recuento de munición) => la lógica entra en "sistemas", que procesan estos componentes y su estado (por ejemplo, PhysicsSystem, RenderSystem, etc.)
- Quiero implementar componentes y sistemas tanto en C # puro como a través de scripting (Lua). Básicamente quiero poder definir componentes y sistemas completamente nuevos directamente en Lua sin tener que recompilar mi fuente C #.
Ahora estoy buscando ideas sobre cómo manejar esto de manera eficiente y consistente, por lo que no necesito usar una sintaxis diferente para acceder a componentes de C # o componentes de Lua, por ejemplo.
Mi enfoque actual sería implementar componentes de C # usando propiedades públicas regulares, probablemente decoradas con algunos atributos que le informan al editor sobre valores predeterminados y otras cosas. Entonces tendría una clase C # "ScriptComponent", que simplemente envuelve una tabla Lua internamente con esta tabla creada por un script y que contiene todo el estado de ese tipo de componente en particular. Realmente no quiero acceder a ese estado desde el lado de C #, ya que no sabría en el momento de la compilación qué componentes de script con qué propiedades estarían disponibles para mí. Aún así, el editor tendrá que acceder a eso, pero una interfaz simple como la siguiente debería ser suficiente:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
Esto simplemente accedería a la tabla Lua y establecería y recuperaría esas propiedades de Lua y también podría incluirse fácilmente en los componentes puros de C # (pero use las propiedades normales de C # entonces, mediante reflexión o algo así). Esto solo se usaría en el editor, no por el código de juego regular, por lo que el rendimiento no es tan importante aquí. Haría necesario generar o escribir a mano algunas descripciones de componentes que documenten qué propiedades ofrece un determinado tipo de componente, pero eso no sería un gran problema y podría automatizarse lo suficiente.
Sin embargo, ¿cómo acceder a los componentes desde el lado de Lua? Si hago una llamada a algo así getComponentsFromEntity(ENTITY_ID)
, probablemente obtendré un montón de componentes nativos de C #, incluido "ScriptComponent", como datos de usuario. Acceder a los valores de la tabla Lua envuelta resultaría en que llame al GetProperty<T>(..)
método en lugar de acceder a las propiedades directamente, como con los otros componentes de C #.
Tal vez escriba un getComponentsFromEntity()
método especial solo para ser llamado desde Lua, que devuelve todos los componentes nativos de C # como datos de usuario, a excepción de "ScriptComponent", donde devolverá la tabla envuelta. Pero habrá otros métodos relacionados con los componentes y realmente no quiero duplicar todos estos métodos tanto para ser llamados desde el código C # o desde el script Lua.
El objetivo final sería manejar todos los tipos de componentes de la misma manera, sin una sintaxis de caso especial que diferencie entre los componentes nativos y los componentes Lua, especialmente desde el lado Lua. Por ejemplo, me gustaría poder escribir un script Lua así:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
El script no debería importar qué tipo de componente tiene realmente y me gustaría usar los mismos métodos que usaría desde el lado C # para recuperar, agregar o eliminar componentes.
¿Quizás hay algunas implementaciones de muestra de integración de scripts con sistemas de entidades como ese?