Strona Główna     FAQFAQ  SzukajSzukaj  UżytkownicyUżytkownicy  GrupyGrupy


Poprzedni temat :: Następny temat
[c/c++] Wzorzec projektowy i komunikacja między obiektami
Autor Wiadomość
WebCM 

Pomógł: 4 razy
Skąd: Polska
Wysłany: 2012-01-01, 03:36   [c/c++] Wzorzec projektowy i komunikacja między obiektami

Piszę grę planszową 2D w C++ obiektowo. Jaki wzorzec architektoniczny wybrać?

Wstępne założenia
1. Można podpiąć dowolną warstwę prezentacji, np. WinAPI, GDI, Qt.
2. Łatwa konwersja na inną platformę, np. Linux.
3. Obiekty nie wchodzą sobie w kompetencje - wykonują tylko swoje zadania.

Zacząłem pisać grę w WinAPI i rysować planszę za pomocą GDI. Prawdopodobnie zmienię na MFC, bo pisanie z palca całego interfejsu i innych okien z komponentami jest czasochłonne. Z drugiej strony tworząc coś w MFC można się zamęczyć. Biblioteki wykorzystujące cały czas 100% czasu procesora odpadają.

Założenie drugie to niedyskryminowanie innych platform niż Windows. I tu się zaczyna. Dylemat jest następujący - pisać spójną aplikację czy z podziałem na warstwy?

1. Czy warstwa logiki ma operować bezpośrednio na obiektach okna?
2. Jak interfejs ma komunikować się z warstwą logiki i pobierać dane?

Przykładowe problemy
1. Kiedy gracz wykonuje ruch, warstwa logiki musi się o tym dowiedzieć i wykonać obliczenia.
2. Kiedy komputer wykonuje ruch, pionki na planszy muszą się przestawić.
3. Zatem jest potrzebna komunikacja obustronna.

Przykłady komunikacji
1. Fasady - każda warstwa ma fasadę, czyli specjalny interfejs, przez który poszczególne warstwy mogą komunikować się. Zarówno model i widok mają funkcje, które mogą wywoływać nawzajem (może ich być dużo).
Kod:
model.przesun(pionek, pozycja); //widok każe modelowi wykonać akcję
widok.koniecGry(); //model informuje widok o końcu gry

2. MVC - komunikacja model-widok jest jednostronna. Widok odwołuje się do modelu i nie na odwrót. A co wtedy, gdy model musi wykonać akcję w widoku, np. przesunąć pionek na planszy lub powiadomić, że gra się skończyła? Można zastosować wzorzec Obserwator. Albo inaczej - widok nadzoruje model.
Kod:
if(model.przesun(pionek, pozycja))
{
   this.przesun(pionek, pozycja); //wewnątrz widoku
}
while(akcja = model.getAction()) {} //można tak
if(model.zaznacz(pionek))
  if(model.pokazDozwolone(...)) {} //albo tak
if(model.wykonajRuchy()) {}

3. Zdarzenia - można wysłać zdarzenie do okna, ale wtedy uzależnimy logikę od widoku. Innym sposobem jest utworzenie metod dla zdarzeń w obu warstwach albo wykorzystanie wzorca Obserwator.. Zdarzenia trzeba nazwać i obsłużyć instrukcją switch.
Kod:
switch(zdarzenie)
{
   case EVENT_FINISH: this.finish(); break;
   default: /* błąd */
}

4. Wolne obiekty - nie ma ścisłego podziału na warstwy. Poszczególne obiekty mogą odwoływać się do publicznych metod i własności innych obiektów. Wyjątkiem są obiekty, które z założenia mogą być obsługiwane tylko przez 1 klasę lub metodę. To jednak nie rozwiązuje problemów z implementacją!

**Jeszcze jedna rzecz**
Zdarzenie WM_PAINT odrysowuje okno. Trzeba narysować aktualny stan planszy, pionki, a przy tym użyć właściwych kolorów lub bitmap. Kiedy zaznaczamy pionka, też trzeba to uwidocznić np. innym obramowaniem pola. Podobnie ostatni ruch oraz podpowiedzi, gdzie wolno przesunąć pionek. Pojawiają się pytania:

1. Jak odczytać położenie pionków z klasy bez obciążenia procesora?
2. Jaka warstwa ma przechowywać informacje o kolorach pól i graczy?

Ad 1. Aktualnie w klasie Gra mam własność int pola[10][10]. Powiecie, że powinna ona być prywatna. W końcu implementacja może się zmienić i zamiast tablicy liczb całkowitych będzie tablica obiektów Pole pola[10][10] bądź zostanie przeniesiona do innej klasy, cokolwiek. Z drugiej strony gdyby co chwilę wywoływać metody getCzyjePole(), getKolorPola(), getCosTam() - za duże obciążenie dla procesora.
Kod:
for(x=0; x<10; x++)
   for(y=0; y<10; y++)
      switch(model.getCzyjePole(x, y)) {...}

A skąd wiem, ile jest pól? Że plansza jest kwadratowa? Jak zmienimy planszę na okrągłą, nic nie da zamiana klasy w modelu z PlanszaKwadrat na PlanszaKolo, bo trzeba wymienić cały widok. To tylko przykład, aby pokazać paradoks MVC. Nie da się całkowicie wyeliminować logiki (biznesu) programu z widoku.

Ad 2. Takie rzeczy zwykle podajemy w ustawieniach. A ich nie powierzymy widokowi. Równie dobrze widokiem może być tryb tekstowy bez kolorów. 2 pliki ustawień (drugi dla widoku, jak ma wyglądać plansza)? No way!

Pole może należeć do gracza lub być puste; być zaznaczone lub nie; być oznaczone jako ostatnie przesunięcie lub nie; jako podpowiedź lub nie - zatem gdzieś trzeba trzymać stany pól. Model lub widok. Bitwise operators? Obiekt Pole, a tam własności to opisujące? Hm? Sugestie?

Chyba wszystko już wyjaśniłem. Mam mało czasu na napisanie gry, chcę to zrobić dobrze, piszę głównie dla Windowsa. Jak poszczególne obiekty powinny się komunikować?
_________________
Przeciwdziałajmy coraz niższemu poziomowi polskiego Internetu i rozpustom.
 
 
   
ExeQtoR 
Moderator



Pomógł: 38 razy
Skąd: K.P.
Wysłany: 2012-01-01, 21:35   

poruszyłeś parę rzeczy ale jednego do końca jednoznacznie nie powiedziałeś:

aplikacja WWW
aplikacja Windows

Dopiero potem możemy jednoznacznie rozmawiać ;-P bo to całkiem różne technologie i jak a.WWW ograniczają się do możliwości aktualnych przeglądarek, tak a.Windows ograniczają się do mocy kompów a bardziej mówiąc do ograniczeń naszej wyobraźni i czasu ;-)
_________________
Moderatora grzecznie się słuchamy,
nie spamujemy, nie bluzgamy...


 
 
   
ExeQtoR 
Moderator



Pomógł: 38 razy
Skąd: K.P.
Wysłany: 2012-01-01, 21:58   

Po sylwestrze jeszcze słabo myślę, ale sądzę że to ta druga odpowiedź xD

WebCM napisał/a:
Przykładowe problemy
1. Kiedy gracz wykonuje ruch, warstwa logiki musi się o tym dowiedzieć i wykonać obliczenia.
2. Kiedy komputer wykonuje ruch, pionki na planszy muszą się przestawić.
3. Zatem jest potrzebna komunikacja obustronna.

1. To warstwa logiki przecież "myśli" nie od picu nazywa się warstwą logiki ??
2. No to oczywiste xD Tobie chodzi o to że jak rozwiązać gę z "komputerem" ??
ja bym zrobił "virtualnego" gracza ;-) logika w grę planszową musi mieć(wypadało by) stopnie trudności, a nauczyć grać kompa w jakaś grę(zaimplementować konkretną logikę na dany ruch przeciwnika nie jest łatwo) - to będą setki linijek kodu ;-)
Czyli podpinasz wirtualnego gracza, który wywołuję akcję przesunięcia pionka tak samo jak zwykły user ;-) już mamy jedną sprawę ujednoliconą ;-)
3. moje szare komórki nie znają dzisiaj odpowiedzi na to pytanie xD


Jeszcze nadal nie myślę do końca ale ja bym zrobił to tak:

Baza danych(plikowa) -> albo chociaż w pamięci, jakaś truktura danych czy cokolwiek -> przeanalizować jakie dane będą potrzebne -> jaka to gra ??
np:
Struktura(typ pionka, gracz)
tablica[][] Struktury
To ma być w obiekcie BAZA + metody dostępu:
a) int max X
b) int max Y
c) int ile_pionków_gracz(gracz)
d) bool przesun_pionek(xx,yy, x,y) -> true-OK, False-> inny pionek tam jest
e) bool czy_wolne_pole(x,y)
f) bool usun_pionka(x,y)

chyba tyle

dalej kolejny obiekt który będzie dziedziczył po Bazie to np. plansza
z rozbudowaną logiką

tutaj obiekt "user" -> zwykły user prawa itp..

tutaj obiekt "komputer" -> "myślenie komputera"

--
dodatki:
obiekt: historia wykonanych operacji
obiekt: historia błędów(wyników operacji usera)
--
kolejny obiekt to "gra" dziedziczy po planszy, user, komputer
zarządza i sprawdza dokładnie co się dzieje ;-) innymi słowy to pilnuje "zasad gry"
--- tutaj ważne metody dostępu ;-)

Teraz robisz interfejs na bazie tego i podpinasz konkretne metody dostępu np. jak user kliknie i przesunie pionka to wywoła dużo funkcji itp... jak dostanie zwrotną info że operacja prawidłowa, to może pobrać "nową" plansze(z nowym układem pionków) i odświeży tym samym widok ;-)

1. Widok---akcja---> Logika(myśli) ---"Info zwrotne do" bool ---> widok
jak False -> Pobierz info z "błędów usera" wyświetl odpowiedni komunikat, czekaj na akcje w pk1(linijka wyżej)
jak True -> odśwież(pobierz) plansze i czekaj na akcje w pk1

To chyba tyle ;-) ja polecam zrobić lekko po swojemu xD jak dobrze obiekty rozplanujesz to mało się narobisz ;-)
_________________
Moderatora grzecznie się słuchamy,
nie spamujemy, nie bluzgamy...


 
 
   
WebCM 

Pomógł: 4 razy
Skąd: Polska
Wysłany: 2012-02-05, 19:56   

Pisanie programów w czystym WinAPI bez graficznego edytora to samobójstwo. Szczególnie gdy trzeba wyświetlić tekst na ekranie przechowywany w innej klasie jako char*. Trudno zastosować wzorzec MVC. Zgodnie z założeniami model i widok mają nic nie wiedzieć o kontrolerze, a widok operuje na modelu. W odmianie MVP widok nie odwołuje się bezpośrednio do modelu. Kontroler operuje na modelu, pobiera wynik i przekazuje widokowi gotowe dane do wyświetlenia.

Główny problem - kompetencje poszczególnych warstw. W aplikacji okienkowej kontroler i widok przenikają się.

Kontroler - przyjmuje dane wejściowe od użytkownika, reaguje na poczynania, aktualizuje model, odświeża widok.
Widok - opisuje, jak wyświetlić pewną część modelu w ramach interfejsu użytkownika.

Ile programów, tyle implementacji. Każdy interpretuje inaczej. W przypadku MVP (luźne tłumaczenie):

Widok - wyświetla dane i przekazuje komendy użytkownika (zdarzenia) do prezentera i działa na tych danych
Prezenter - nadzoruje model i widok, pobiera dane z modelu, formatuje je i przekazuje widokowi do wyświetlenia

Zostawmy wzorce architektoniczne i przejdźmy do interfejsu użytkownika.

Piszę grę planszową 2D. Początkowo miałem ambitne plany:

- jednocześnie może grać 2, 3 lub 4 graczy dobrowolnie wybranych z listy (po kliknięciu ich nazwy)
- okno wyboru graczy, gdzie można stworzyć ich dowolną ilość (ludzi lub komputerowych)
- czyli możliwa byłaby nawet gra 4 komputerów...
- sztuczna inteligencja z przewidywaniem ruchów
- statystyki graczy
- zmiana wyglądu, opcje gry, dostosowanie do potrzeb
- gra przez sieć LAN

Wcielmy się z gracza, który chce zagrać z komputerem. Odpala aplikację i co? Brak graczy, 4 puste pola zamiast imion... Jeżeli utworzymy gracza domyślnego, przyjdzie 4 graczy i będą chcieli zagrać razem. Utworzenie nowych graczy chwilę trwa, a oni chcą grać już i tylko raz, bez dodawania ich do systemu!

A może łatwiej - dodać do menu kilka pozycji:

- gra z komputerem
- gra z innym użytkownikiem
- gra na 4 graczy
- gra z innym użytkownikiem przez LAN (a co z grą przez LAN na 3 i 4 graczy?)

Tylko co ze statystykami graczy?

Algorytm sztucznej inteligencji z przewidywaniem ruchów MinMax z założenia stosuje się dla 2 graczy. Czy da się go zastosować dla większej ilości? Pamiętajmy o optymalizacjach typu przycinanie Alfa-Beta. Kolejny problem - wątki. Bez tego nie da się zrobić gry sieciowej lub z komputerem, gdzie obliczenia będą trwać długo. A ile powinno być wątków i za co odpowiadać? Jak ma wyglądać synchronizacja i z którą warstwą wzorca MVC/MVP?

Jak powinien wyglądać intuicyjny interfejs w grze?
_________________
Przeciwdziałajmy coraz niższemu poziomowi polskiego Internetu i rozpustom.
 
 
   
Wyświetl posty z ostatnich:   
Dodaj do: WypowiedÄ˝ dla Wykop  WypowiedÄ˝ dla Facebook  WypowiedÄ˝ dla Wyczaj.to  WypowiedÄ˝ dla Gwar  WypowiedÄ˝ dla Delicious  WypowiedÄ˝ dla Digg  WypowiedÄ˝ dla Furl  WypowiedÄ˝ dla Google  WypowiedÄ˝ dla Magnolia  WypowiedÄ˝ dla Reddit  WypowiedÄ˝ dla Simpy  WypowiedÄ˝ dla Slashdot  WypowiedÄ˝ dla Technorati  WypowiedÄ˝ dla YahooMyWeb
Odpowiedz do tematu
Możesz pisać nowe tematy
Możesz odpowiadać w tematach
Nie możesz zmieniać swoich postów
Nie możesz usuwać swoich postów
Nie możesz głosować w ankietach
Nie możesz załączać plików na tym forum
Możesz ściągać załączniki na tym forum
Dodaj temat do Ulubionych
Wersja do druku

Skocz do:  

Powered by phpBB modified by Przemo © 2003 phpBB Group
system walidacji dla gości opracował Petermechanic
Forum komputerowe
Strona wygenerowana w 0,11 sekundy. Zapytań do SQL: 11