Pracuję nad prostą grą logiczną opartą na blokach.
Rozgrywka polega głównie na przesuwaniu bloków w obszarze gry, więc jest to trywialna symulacja fizyki. Moje wdrożenie jest jednak moim zdaniem dalekie od ideału i zastanawiam się, czy możesz dać mi jakieś wskazówki, jak to zrobić lepiej.
Podzieliłem kod na dwa obszary: logikę gry i interfejs użytkownika, podobnie jak w przypadku wielu gier logicznych:
- Logika gry odpowiada za ogólne zasady gry (np. Formalny system reguł w szachach)
- Interfejs użytkownika wyświetla obszar gry i pionki (np. Szachownicę i pionki) i odpowiada za animacje (np. Animowany ruch szachów)
Logika gry reprezentuje stan gry jako logiczną siatkę, gdzie każda jednostka ma szerokość / wysokość jednej komórki na siatce. Tak więc dla siatki o szerokości 6 możesz przesunąć blok o szerokości 2 cztery razy, aż zderzy się z granicą.
Interfejs użytkownika pobiera tę siatkę i rysuje ją, konwertując rozmiary logiczne na rozmiary pikseli (to znaczy, pomnaża ją przez stałą). Ponieważ jednak gra nie ma prawie żadnej logiki, moja warstwa logiki gry [1] nie ma wiele do roboty poza wykrywaniem kolizji. Oto jak to działa:
- Gracz zaczyna przeciągać kawałek
- Interfejs użytkownika pyta logikę gry o legalny obszar ruchu tego elementu i pozwala graczowi przeciągnąć go w tym obszarze
- Gracz puszcza kawałek
- Interfejs użytkownika przyciąga element do siatki (aby znalazł się w prawidłowej pozycji logicznej)
- Interfejs użytkownika informuje logikę gry o nowej pozycji logicznej (metodami mutatora, których wolałbym unikać)
Nie jestem z tego zadowolony:
- Piszę testy jednostkowe dla mojej warstwy logiki gry, ale nie dla interfejsu użytkownika, i okazało się, że cały trudny kod znajduje się w interfejsie: powstrzymywanie elementu przed kolizją z innymi lub granicą i przyciąganie go do siatki.
- Nie podoba mi się fakt, że interfejs użytkownika mówi logice gry o nowym stanie, wolę, aby wywoływała
movePieceLeft()
metodę lub coś takiego, jak w moich innych grach, ale nie posunęłam się za daleko z tym podejściem, ponieważ logika gry nie wie nic na temat przeciągania i przyciągania, które są możliwe w interfejsie użytkownika.
Myślę, że najlepiej byłoby pozbyć się mojej warstwy logiki gry i zamiast tego wdrożyć warstwę fizyki. Mam kilka pytań na ten temat:
- Czy taka warstwa fizyki jest powszechna, czy może bardziej typowa jest warstwa logiki gry?
- Czy przyciąganie do siatki i kodu do przeciągania elementów należałoby do interfejsu użytkownika lub warstwy fizyki?
- Czy taka warstwa fizyki zazwyczaj działałaby z rozmiarami pikseli lub z jakąś jednostką logiczną, taką jak moja warstwa logiki gry?
- Widziałem wykrywanie kolizji oparte na zdarzeniach w bazie kodu gry raz, to znaczy, gracz po prostu przeciągał element, interfejs użytkownika renderowałby to posłusznie i powiadamiał system fizyki, a system fizyki wywoływałby metodę onCollision () na kawałku po wykryciu kolizji. Co jest bardziej powszechne? To podejście lub najpierw prośba o legalny obszar przemieszczania się?
[1] warstwa prawdopodobnie nie jest właściwym słowem na to, co mam na myśli, ale podsystem wydaje się przesadzony, a klasa wprowadza w błąd, ponieważ każda warstwa może składać się z kilku klas.
Odpowiedzi:
Spróbuję odpowiedzieć na to pytanie, ponieważ rozumiem, o co pytasz, chociaż nie mam dużego doświadczenia w tworzeniu gier, ponieważ wciąż się uczę.
Widzę, że należy oddzielić kod GUI od logiki gry i obiektów domeny, czyli elementów układanki. Są to rzeczywiście trzy osobne warstwy - i tak,
layer
moim zdaniem , jest to właściwe określenie. Jest często używany do wyjaśnienia pojęć rozdzielania poziomu każdego obiektu w systemie na niezależne od siebie podsystemy.W odniesieniu do programowania obiektowego każdy obiekt powinien być klasą. Tak więc każdy element układanki powinien składać się z jednej klasy, a więc z planszy. Plansza powinna zawierać X elementów układanki w zależności od jej wielkości i zdolności ruchowej, którą chcesz dać graczowi.
Oto moje przemyślenia na ten temat - mam nadzieję, że to pomoże:
W tej architekturze warstwa GUI pokazywałaby graczowi stan gry, położenie poszczególnych elementów układanki. Warstwa GUI byłaby wówczas odpowiedzialna za uzyskiwanie danych wejściowych gracza i przekazywanie jej do podstawowej warstwy kontrolera gier, która byłaby wówczas odpowiedzialna za wykrywanie kolizji. Jeśli go nie ma, element można nakazać przesunąć w tym kierunku wejściowym. Aby to zrobić, wystarczy nazwać ten utwór
MoveLeft
,MoveRight
itp. metody poruszania elementu. Równie dobrze możesz poinformować planszę, który element chcesz przenieść, a następnie sam zarządza ruchem elementu, a następnie element porusza się w żądanym kierunku. Ta architektura ułatwia testowanie każdego fragmentu kodu na różnych warstwach, a następnie umożliwia testowanie jednostkowe, testy integracji i testy funkcjonalne.Wiem, że może to wydawać się nieco mylące z powodu widoku i dzięki Bogu, jeśli tak nie jest! Jeśli potrzebujesz dodatkowych informacji i pomocy, nie wahaj się zapytać, chętnie pomogę najlepiej jak potrafię, choć jestem początkującym w tworzeniu gier.
Dziękuje za przeczytanie! =)
źródło
Position
funkcji pobierania właściwości, dzięki czemu kontroler gier wymaga od GUI wyświetlenia tego przesuniętego elementu w tej nowej pozycji.