2011-09-22 14 views
5

Po pierwsze, pozwól mi przeprosić za zadanie pytania, które może wydawać się nieco niejasne (lub źle sformalizowane), ale brakuje mi doświadczenia, aby zadać coś bardziej konkretnego.C# Struktura obiektów w grze 2D

Buduję silnik do grania w gry 2D przygodowe (typ "ty-klik-na-obiekcie-i-coś-dzieje się") w C# i rozważam najlepszą jego strukturę. Jak możesz sobie wyobrazić, różne rzeczy mogą się zdarzyć, gdy wchodzisz w interakcję z obiektem: jeśli to drzwi, spodziewasz się wejść do innego pokoju, jeśli to jest osoba, spodziewasz się zacząć z nimi rozmawiać itd. Mój pomysł polega na osiągnięciu tego zachowania z delegatów, na przykład:

public abstract class GameObject { 
    public delegate void onAction(); 
    public onAction Click; 
} 

public class Door : GameObject { 
    public Door() { 
     Click = new onAction(ChangeRoom); 
    } 
    private void ChangeRoom() { 
     //code to change room here 
    } 
} 

public class Person : GameObject { 
    public Person() { 
     Click = new onAction(StartTalking); 
    } 
    private void StartTalking() { 
     //code to display dialogue here 
    } 
} 

Uważam to rozwiązanie dość elegancki, bo jeśli chcę utworzyć specjalny obiekt z jakiegoś zachowania nie objętej swojej klasie, I może po prostu to zrobić:

specialObject.Click += new onAction(SpecialMethod); 

Ale tu także sprawy się komplikują. Chcę, aby mój silnik mógł odtwarzać różne gry, ładując różne dane, bez zmian w samym silniku, więc zakodowanie SpecialMethod gdzieś w silniku nie jest opcją, musi być częścią danych. W przypadku normalnego obiektu można to zrobić z serializacją (de), ale z tego, co przeczytałem, jest to problematyczne dla delegatów. Czy możesz zaproponować sposób na zrobienie tego?

PS: Ponieważ wciąż jestem na poziomie koncepcji, a powyższy kod nie został jeszcze wdrożony, możesz zaproponować najlepsze rozwiązanie, nawet takie, które całkowicie eliminuje delegatów.

+0

Wygląda na to, że opisujesz silnik reguł http://martinfowler.com/bliki/RulesEngine.html – Jodrell

+1

Myślę, że możesz opublikować to pytanie pod adresem http://gamedev.stackexchange.com/ – Luca

+0

Dziękuję @luca for połączenie. Na pewno to sprawdzę, choć na pierwszy rzut oka wydaje się, że to forum jest nieco bardziej profesjonalne niż ja. –

Odpowiedz

1

Przede wszystkim pisanie silnika, gdy brakuje ci doświadczenia, może być trudniejsze niż myślisz. Proponuję Ci napisać pierwszą grę bez silnika i kodu, ile chcesz, a następnie uczyć się z doświadczenia i pisać silnik ... Wiem, że nie tego chcesz: D

Jeśli nie masz sprawdzone, ale spójrz na http://www.adventuregamestudio.co.uk/ grać z edytorem i pomyśl o modelu obiektu pod spodem. To pomoże.

Ponieważ chcesz, aby Twoje gry były oparte na danych, musisz dynamicznie ładować i uruchamiać kod. "Nie musi to być język skryptowy". Wbrew mojej naturze sugerowanie dodawania języka skryptowego i uczenie go w tym samym czasie, kiedy uczysz się budować silnik. .NET Framework ma świetny system refleksyjny, który pozwala załadować kod C# i skompilować go w czasie wykonywania. Muszę zaznaczyć, że jest to rodzaj skryptów w języku C#, ale brakuje właściwej definicji języka skryptowego.

Ponieważ nie masz dużego doświadczenia w tym, moja sugestia to użycie plików XML, które definiują twoje pokoje i mają podstawową sekwencję węzłów (poleceń), które definiują, co powinno się stać, gdy klikniesz coś. Powinieneś zaimplementować wszystkie polecenia w swoim "silniku", ale będziesz mógł łatwo tworzyć nowe pokoje, a więc podobne gry. XML będzie również bardzo rozszerzalnym podejściem, ponieważ ze względu na jego strukturę hierarchiczną pozwoli na dodanie warunków, pętli itp., Które rozszerzą możliwości "skryptowania" twojego silnika.

+0

Po pewnym przemyśleniu i zbadaniu różnych opcji, znalazłem tę odpowiedź w rzeczywistości najbardziej użyteczną. Przypomniało mi to, że nie musisz zbytnio komplikować rzeczy i dałeś mi pomysł, który mogę wykorzystać jako początek. Więc dziękuję! –

1

Nie trzeba ciężko kodem funkcji SpecialMethod do swojego silnika, można go używać z różnych gier wykorzystujących silnik:

var medievalDoor = new Door(); 
medievalDoor.Click += OpenDoorNormally; 

Ale w innej grze:

var starTrekDoor = new Door(); 
starTrekDoor.Click += SlideDoorUpward; 

Tak długo, jak wystawiasz zdarzenie Click, nie musisz niczego zakodować w silniku. Można go umieścić w grze, która może mieć twój silnik jako odniesienie DLL.

+0

Jeśli "medievalDoor.Click + = OpenDoorNormally' jest zdefiniowany na poziomie silnika, co wydaje się być tym, co implikuje, wtedy musisz zmodyfikować kod silnika za każdym razem, gdy zmienisz dane gry. – InBetween

0

Nie widzę problemu, jeśli "decyzja" o wykonaniu jakiegoś szczególnego zachowania zostanie pozostawiona samemu obiektowi gry. Jeśli chcesz, aby silnik zdecydował, to masz, jak sądzę, niezgodne specyfikacje projektu, ponieważ skutecznie zmusiłbyś silnik do podjęcia decyzji, która jest dokładnie taka, jakiej nie chcesz.

Utwórz pole ISpecialBehaviorProvider w swoich obiektach gry i ustaw je w odpowiednim momencie, jeśli to konieczne (przez konstruktora, własność publiczną, co masz).

Twój silnik zawsze będzie wykonywał GameObject.Click, gdy użytkownik klika. Jeśli jednak specialBehaviorProvider ma wartość null, wykonaj GameObject.Click wykonaj kod "w klasie", w przeciwnym razie wywołaj ISpecialBehaviorProvider.SpecialMethod.

W ten sposób silnik nie bierze udziału w podejmowaniu decyzji o wyborze metody.

+0

Tak, moim pomysłem jest, aby silnik uruchamiał 'GameObject.Click' w razie potrzeby bez żadnych kontroli. Ale wciąż muszę być w stanie przekazać to szczególne zachowanie jakiegoś obiektu "z zewnątrz". Jak sugerują następne odpowiedzi, jestem na dobrej drodze, aby poznać skrypty. –

0

Pierwszą rzeczą, na którą zwrócę uwagę, jest to, że , ponieważ są to klasy, polimorfizm byłby tutaj idealny - na przykład za pomocą metody wirtualnego kliknięcia.

Delegaci mogą być naprawdę trudne dla serializerów, w zależności od metody serializacji.BinaryFormatter zrobi to za, ale generalnie unikam tego serializatora za wszelką cenę.

Jeśli jest to możliwe, sugerowałbym, aby twoje dostosowania dokonywały podklasy standardowych impe- rementacji i używał polimorfizmu. Jeśli trzeba zdefiniować jako czysto poprzez dane, zasadniczo należy wprowadzić silnik skryptowy. Wiele takich jest dostępnych w .NET - IronPython może być przydatny, chociaż w przypadku gier lua jest dość powszechna (powinieneś być w stanie dość łatwo używać Lua.NET). Następnie możesz mieć opcjonalny skrypt powiązany z akcją i wywołać skrypt (zdefiniowany w danych).

+0

Powiedziałbym, że 90% zachowań obiektów może być zdefiniowane wyłącznie przez polimorfizm. Problem (jak zwykle) dotyczy pozostałych 10%. Czy mogę zapytać, dlaczego unikasz BinaryFormatter? (Jestem też całkiem nowy w tym obszarze.) –

3

Potrzebne jest skrypty.

Zasadniczo skrypt jest zasobem zewnętrznym (tzn. Plikiem zewnętrznym), który zawiera kod źródłowy, który opisuje działania.

C# ma inną opcję.

Można emitować zespoły z języków .NET. Lub możesz zintegrować inny język (na przykład python) i wykonać skrypt w środowisku wykonawczym. Zasadniczo skrypt jest ładowany, interpretowany lub kompilowany i uruchamiany we właściwym czasie. Jeśli skrypt jest w stanie zmodyfikować stan aplikacji (struktury danych), można zdefiniować zachowanie obiektów za pomocą danych zewnętrznych (rozwój oparty na danych).

Istnieje wiele literatury na ten temat, ale mam ochotę zasugerować GPU Programming Gems 6 (sekcja 4). Jednak wysiłek wymagany do zintegrowania doskonałego silnika skryptowego jest bardzo duży. W ten sposób próbowałem wymyślić prostą logikę opartą na plikach XML (here jest moje pytanie o, dołączenie do innego question do definiowania zawartości XML); Niestety, stwierdziłem, że prawie zależy to od elastyczności, jakiej potrzebujesz.

+0

+1 dla skryptów. IronLanguages ​​są trywialne, aby zintegrować się z aplikacją .NET i mają bardzo dobrą współdziałanie z C#: https://github.com/IronLanguages/main – robbrit