Atualmente, estou tentando implementar um sistema de entidades baseado em componentes, em que uma entidade é basicamente apenas um ID e alguns métodos auxiliares que unem vários componentes para formar um objeto de jogo. Alguns objetivos incluem:
- Os componentes contêm apenas estado (por exemplo, posição, saúde, quantidade de munição) => a lógica entra em "sistemas", que processam esses componentes e seu estado (por exemplo, PhysicsSystem, RenderSystem, etc.)
- Quero implementar componentes e sistemas em C # puro e por meio de scripts (Lua). Basicamente, quero poder definir componentes e sistemas completamente novos diretamente em Lua sem precisar recompilar minha fonte de C #.
Agora, estou procurando idéias sobre como lidar com isso de maneira eficiente e consistente, portanto, não preciso usar sintaxe diferente para acessar componentes C # ou componentes Lua, por exemplo.
Minha abordagem atual seria implementar componentes C # usando propriedades públicas regulares, provavelmente decoradas com alguns atributos que informam o editor sobre valores e coisas padrão. Então eu teria uma classe C # "ScriptComponent", que apenas agrupa uma tabela Lua internamente, com essa tabela sendo criada por um script e mantendo todo o estado desse tipo de componente específico. Eu realmente não quero acessar muito esse estado do lado do C #, pois não saberia em tempo de compilação quais ScriptComponents com quais propriedades estariam disponíveis para mim. Ainda assim, o editor precisará acessar isso, mas uma interface simples como a seguinte deve ser suficiente:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
Isso simplesmente acessaria a tabela Lua e definiria e recuperaria essas propriedades de Lua, além de poder ser facilmente incluído nos componentes C # puros (mas use as propriedades C # regulares, por meio de reflexão ou algo assim). Isso seria usado apenas no editor, não pelo código normal do jogo; portanto, o desempenho não é tão importante aqui. Seria necessário gerar ou escrever à mão algumas descrições de componentes, documentando quais propriedades um determinado tipo de componente realmente oferece, mas isso não seria um problema enorme e poderia ser suficientemente automatizado.
No entanto, como acessar componentes do lado da Lua? Se eu telefonar para algo como getComponentsFromEntity(ENTITY_ID)
provavelmente vou obter vários componentes nativos do C #, incluindo "ScriptComponent", como dados do usuário. Acessar os valores da tabela embrulhada Lua resultaria na chamada do GetProperty<T>(..)
método, em vez de acessar as propriedades diretamente, como nos outros componentes do C #.
Talvez escreva um getComponentsFromEntity()
método especial apenas para ser chamado de Lua, que retorna todos os componentes C # nativos como dados do usuário, exceto "ScriptComponent", onde retornará a tabela agrupada. Mas haverá outros métodos relacionados a componentes e eu realmente não quero duplicar todos esses métodos para serem chamados do código C # ou do script Lua.
O objetivo final seria lidar com todos os tipos de componentes da mesma forma, sem nenhuma sintaxe especial de caso diferenciando componentes nativos e componentes Lua - especialmente do lado Lua. Por exemplo, eu gostaria de poder escrever um script Lua assim:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
O script não deve se importar com o tipo de componente que ele realmente possui e eu gostaria de usar os mesmos métodos que usaria no lado do C # para recuperar, adicionar ou remover componentes.
Talvez haja algumas implementações de exemplo de integração de scripts com sistemas de entidades como esse?