Obecnie próbuję wdrożyć system encji oparty na komponentach, w którym encja jest w zasadzie tylko identyfikatorem, a niektóre metody pomocnicze wiążą kilka komponentów razem, tworząc obiekt gry. Niektóre cele tego obejmują:
- Komponenty zawierają tylko stan (np. Pozycja, zdrowie, ilość amunicji) => logika przechodzi do „systemów”, które przetwarzają te komponenty i ich stan (np. PhysicsSystem, RenderSystem itp.)
- Chcę implementować komponenty i systemy zarówno w czystym języku C #, jak i za pomocą skryptów (Lua). Zasadniczo chcę mieć możliwość definiowania całkowicie nowych komponentów i systemów bezpośrednio w Lua bez konieczności ponownej kompilacji mojego źródła C #.
Teraz szukam pomysłów, jak radzić sobie z tym wydajnie i konsekwentnie, więc nie muszę używać innej składni, aby na przykład uzyskać dostęp do komponentów C # lub Lua.
Moje obecne podejście polegałoby na implementacji komponentów C # przy użyciu zwykłych, publicznych właściwości, prawdopodobnie ozdobionych pewnymi atrybutami informującymi redaktora o domyślnych wartościach i innych rzeczach. Następnie miałbym klasę C # „ScriptComponent”, która po prostu wewnętrznie otacza tabelę Lua, tworząc tę tabelę za pomocą skryptu i utrzymując cały stan tego konkretnego typu komponentu. Tak naprawdę nie chcę uzyskać dostępu do tego stanu od strony C #, ponieważ nie wiedziałbym w czasie kompilacji, jakie ScriptComponents z jakich właściwości byłyby dla mnie dostępne. Jednak edytor będzie musiał uzyskać do niego dostęp, ale wystarczy prosty interfejs podobny do następującego:
public ScriptComponent : IComponent
{
public T GetProperty<T>(string propertyName) {..}
public void SetProperty<T>(string propertyName, T value) {..}
}
Spowodowałoby to po prostu dostęp do tabeli Lua oraz ustawienie i odzyskanie tych właściwości z Lua, i mogłoby to być łatwo zawarte w czystych komponentach C # (ale wtedy używaj zwykłych właściwości C #, poprzez odbicie lub coś innego). Byłoby to używane tylko w edytorze, a nie w zwykłym kodzie gry, więc wydajność nie jest tutaj tak ważna. Konieczne byłoby wygenerowanie lub ręczne napisanie niektórych opisów komponentów dokumentujących, jakie właściwości faktycznie oferuje dany typ komponentów, ale nie byłby to ogromny problem i mógłby być wystarczająco zautomatyzowany.
Jak jednak uzyskać dostęp do komponentów od strony Lua? Jeśli zadzwonię do czegoś takiego getComponentsFromEntity(ENTITY_ID)
, prawdopodobnie dostanę kilka rodzimych składników C #, w tym „ScriptComponent”, jako dane użytkownika. Dostęp do wartości z zawiniętej tabeli Lua spowodowałby, że wywołałem GetProperty<T>(..)
metodę zamiast bezpośredniego dostępu do właściwości, tak jak w przypadku innych składników C #.
Może napisz specjalną getComponentsFromEntity()
metodę, która ma być wywoływana z Lua, która zwraca wszystkie natywne komponenty C # jako dane użytkownika, z wyjątkiem „ScriptComponent”, gdzie zamiast tego zwróci zapakowaną tabelę. Ale będą inne metody związane z komponentami i tak naprawdę nie chcę powielać wszystkich tych metod zarówno w celu wywołania z kodu C # lub ze skryptu Lua.
Ostatecznym celem byłaby obsługa wszystkich typów komponentów w ten sam sposób, bez specjalnej składni przypadków rozróżniającej komponenty natywne i komponenty Lua - szczególnie od strony Lua. Np. Chciałbym móc napisać taki skrypt Lua:
entity = getEntity(1);
nativeComponent = getComponent(entity, "SomeNativeComponent")
scriptComponent = getComponent(entity, "SomeScriptComponent")
nativeComponent.NativeProperty = 5
scriptComponent.ScriptedProperty = 3
Skrypt nie powinien dbać o to, jakiego rodzaju komponent faktycznie ma, i chciałbym użyć tych samych metod, których użyłem po stronie C # do pobierania, dodawania lub usuwania komponentów.
Może istnieją jakieś przykładowe implementacje integracji skryptów z takimi systemami?