Rozwijam prosty silnik gry (w języku C #, jeśli ma to znaczenie) i nie mogę wymyślić wystarczająco dobrego sposobu na wdrożenie skryptów pod względem architektury.
To prosta strategia turowa z niestandardowymi, niezależnymi od logiki animacjami do bitew. Ma globalną warstwę architektury dla rzeczy systemowych / niskopoziomowych i, co najważniejsze, dwa główne moduły - logikę i widok z gry - które komunikują się za pomocą menedżera zdarzeń.
Chodzi o to, że naprawdę chciałbym, aby skrypty wpływały zarówno na rzeczy związane z logiką gry (zmiana parametrów jednostek itp.), Jak i rzeczy związane z widokiem gry, takie jak specjalne animacje / dialogi dla bitew, które mogą zależeć od określony skrypt wyzwalacza.
(Szczerze mówiąc, idealnie chcę, aby skrypt kontrolował przebieg gry, pozostawiając tylko podstawową mechanikę / grafikę logice / widokowi, ale jestem nowy, więc nie jestem pewien, czy mogę to teraz zrobić)
Myślałem o trzech opcjach:
Po prostu pozwól skryptom żyć w logice, ale daj znać o graficznej stronie gry. Ale to spowodowałoby, że podział logiki / widoku byłby niejasny, prawda ...
Ustaw skrypt jako osobny moduł, który będzie wymieniał zdarzenia z innymi przy użyciu tego samego menedżera zdarzeń. Ale to wymaga bardzo ostrożnej synchronizacji zdarzeń, jak sądzę ... i dodania ogromnej ilości typów zdarzeń do menedżera. (Nadal osobisty faworyt)
Uczyń skrypt przede wszystkim modułem, aby mógł bezpośrednio wpływać na / wywoływać funkcje logiki / widoku. Pozwala to na z natury szerszą funkcjonalność kosztem zepsucia całego schematu wymiany zdarzeń i obawy, że skrypt może zepsuć wszystko, nawet jeśli tak naprawdę nie powinno.
Nie mogę więc zdecydować się na jeden z nich, ani wymyślić lepszego sposobu na wstawienie modułu skryptowego ... Jakieś sugestie lub przydatne linki?
Dziękuję Ci!
Ps dzięki za migrację pytania, nie wiedziałem, że jest specjalistyczna sekcja dla gamedev
źródło
Odpowiedzi:
Wierzę, że chcesz trzecią opcję, ale przekonasz się, że masz rację, myśląc, że logiczne zdarzenia w potencjalnie dwóch lokalizacjach to zła rzecz. Przekonasz się, że chcesz, aby moduł logiczny silnika stał się znacznikiem aktualizacji, który zadaje dwa pytania: „Co mam teraz zrobić?”. i „Jak to zrobić?” do którego można następnie przypisać skrypty do obsługi odpowiedzi na te pytania.
Połącz to z ujawnieniem obiektów, które zawierają dane i interfejs API, aby uzyskać dostęp do wymaganych komponentów logiki (mam na myśli, że możesz napisać skrypt do znalezienia ścieżki AI, ale ponieważ jest to ogólny fragment kodu, który prawdopodobnie będzie używany i ponownie wykorzystywany, dlaczego nie? osadzić go w module, a następnie dodać do interfejsu API wystawionego na język skryptowy?). Powinno to zapewnić dostępność, a także jasno określone lokalizacje, w których coś się dzieje.
Znów zastrzegam to tym samym stwierdzeniem, które zawsze robię. Gotowy działający produkt jest zawsze cenniejszy niż dobra teoria w programowaniu :)
Mam nadzieję że to pomoże!
źródło
Wiele osób nie docenia potężnych języków dynamicznych, myśląc, że taka elastyczność wiąże się z kosztem szybkości; To prawda, ale często koszt jest po prostu znikomy.
Osobiście mam tendencję do rozwijania się w jak największym stopniu za pomocą dynamicznych języków wykorzystujących ekspresję, a następnie profiluję prototyp, aby zrozumieć, gdzie i czy potrzebna jest optymalizacja.
W twoim przypadku oznacza to, że powinieneś spróbować przejść do trzeciej opcji, rozwijając „wyższą” część przy użyciu odpowiedniego języka dynamicznego, którego można również użyć jako języka skryptowego.
Po umieszczeniu dynamiki na odpowiedniej głębokości można zastosować wiele wzorów. Twoje niestandardowe skrypty mogą być zintegrowane z systemem opartym na zdarzeniach jako system wywołań zwrotnych, gdy rdzeń oddzwoni, może zapewnić odpowiednie środowisko, dzięki czemu skrypt może zmienić globalny status lub tylko stan podzbioru całego systemu.
Możesz enkapsulować interfejs, w który skrypt może wchodzić w interakcje, używając wzoru Fasada. W metodach fasadowych można umieścić logikę, która określa, w jaki sposób , kiedy , jeśli skrypt może korzystać z funkcji i oddziela interakcję skryptu od podstawowej implementacji.
Interfejs skryptu powinien zapewniać odpowiednie metody fabryczne, aby skrypt mógł generować elementy bez tworzenia ich bezpośrednio; instancje te mogą owijać rzeczywiste obiekty, dzięki czemu można zaimplementować logikę kontroli dostępu.
źródło
Obiekt skryptowy musi mieć dostęp do innych obiektów, dla których dostarczy dane. Uważaj, aby nie przekazać tych innych obiektów bezpośrednio do obiektu skryptowego. W ten sposób tworzy kruchy interfejs. Możesz chcieć mieć coś w rodzaju klasy mediatora, która zarządza tymi odwołaniami do obiektów i zapewnia dostęp do danych do obiektu skryptowego.
źródło
Lua jest popularnym wyborem dla języka skryptowego ogólnego przeznaczenia. Możesz stworzyć swój własny język skryptowy za pomocą Lexa i Yacca (sprawdź artykuł w Game Programming Gems 3), ale powiedziałbym, że większość twoich potrzeb mogłaby być zaspokojona z Luą, bez względu na to, jak duże lub małe.
źródło