Jak rozplanowac aplikację.

0

Witajcie

Próbuje sobie stworzyć grę i mam problem jak rozplanować kod - mianowicie ten cały kram na warstwy, wątki etc.
Co chce uzyskać - chciałbym uzyskać taką aplikację że mimo wykonywania operacji w tle ona się nie zawiesza.

Mam zatem kilka pytań:

Czym jest warstwa aplikacji - czy to jakaś wydzielona część np zbiór klas ?
Jakie aplikacja (tutaj gra) powinna posiadać warstwy (z całą pewnością GUI oraz jakąś logikę)
Czym jest logika aplikacji - za co odpwiada tak właściwie
Jak sensownie zaplanować kod- tak by wątki wykonywały swoje zadania nie przeszkadzając sobie oraz nie czekając na siebie?
Jak zaplanować komunikację między warstwami ?
Czym jest silnik gry (i czy zwykłe aplikację też mają silnik :) ) - czy to gotowe do użycia klasy, funkcję, moduły np DatabaseConnector, gotowe kontrolki GUI etc. ?

Wielowątkowość aplikacji - anty sposoby które stosowałem
Pierwszy sposób - były 3 wątki:

  • główny - miał w sobie pętlę główną i reagował na zdarzenia np
if(*****) PreviewWorldMapCamera->changeLevelOfZoom(event.mouseWheel.delta,*MainWindow);
  • rysujący - wołał metodę draw() ; jakiegoś obiektu
  • aktualizujący -wołał na elementach metodę update();
    Sterowałem tymi wątkami z wątku głównego ustawiając właściwe zmienne na np DExit lub UExit o_o

Drugi sposób to było że wszystko robię w głównym wątku a jak mam zadanie dodatkowe np odliczanie czasu to tworzyłem do tego nowy wątek
A komunikacje prowadziłem za pomocą klasy SignalManager i te sygnały były obsługiwane wewnątrz wątku głównego

W pierwszym sposobie to concurrent computing był o kant rozbić bo gdy wątek rysował to watek aktualizujący czekał aż skończy by np nie zmienić pozycji obiektu na ekranie podczas rysowania i na odwrót.
W drugi sposób też mnie nie zadowala - w przypadku gdy wykonuje trudne obliczenia cała aplikacja zawiesza się i nie reaguje.

Podsumowując
Na ile wątków podzielić aplikacje i jakie dawać im zadania ?
Na jakie warstwy najlepiej podzielić program, jaka jest funkcjonalność każdej warstwy i ile ich powinno być?
Jak należy zaimplementować komunikację między warstwami?

0

Nie wiem jaka zasada panuje w dużych projektach, ja przy pisaniu mniejszych gier 2d w c++ i ostatnio na androida w jave robiłem zawsze mniej więcej tak :

  1. Tworzyłem główną klasę gry, która była singletonem.
  2. Przed główną pętlą gry wykonywałem metodę stwórzŚwiatGry(), w której tworzyły się wszystko obiekty gry, inicjowały się ich położenia, ustawiał stan gry na zaczętą itd ...
  3. Następnie była główna pętla i wykonywały się po kolei metody:
  • sprawdźCoKliknąłGracz () - czy to myszka, czy button, czy ekran w androidzie, no ogólnie sprawdzałem wejście i ustawiałem na podstawie tego odpowiednie wartości, np po kliknięciu palcem w ekran telefonu wywoływałem bohater.ustawKierunek ( Kierunek.LEWO )

  • aktualizujŚwiatGry () - wszystkie obiekty wykonywały tutaj swoje zadania, tzn zmieniały współrzędne swoje itd. itp.

  • rysuj () - wiadomo ;)

Nie stosowałem wielu wątków w aplikacji.
Starałem się podzielić grę na jak najmniejsze moduły, np robiłem klasę Potwór, która miała w sobie tylko takie pole jak współrzędne, prędkość, kierunek i metody zróbRuch() i rysuj(). Takich Potworów na mapie było kilka i były od siebie zależne, więc zrobiłem klasę Potwory, która miała w sobie jakaś tablicę/listę Potworów i metody zarządzające ich wzajemnie zależnym ruchem.

0

@Bambo Ja pisałem/pisze aplikacje podobnie jak ty ale właśnie chciałem się dowiedzieć czy da się do zrobić bardziej hmm profesjonalnie żeby duże obliczenia nie powodowały zamulenia aplikacji. Więc właśnie by działała 'wielowątkowo' ale co mi po wątkach jak aktualizujący wątek czeka na rysujący.
Albo czytałem że dobrze jest aplikacje podzielić na "warstwy" i właśnie nie wiem jak to ugryźć czy chodzi o jakieś wzorce projektowe czy co ... :)

0

@kacper546
Ale z tego co mi wiadomo to na normalnych procesorach działanie na wątkach to jest tylko takie wirtualne - tzn sprawia wrażenie, że są jakieś wątki, a tak naprawdę nie jest to jakieś optymalniejsze pod względem obliczeniowym, ale no niech wypowie się ktoś kto ogarnia 100% temat. Kiedyś w książce traktującej o projektowaniu gier był przedstawiony nasz sposób i mi on się wydaje najbardziej intuicyjny, a poza tym Twoje obliczenia są tak skomplikowane, że muli Ci grę ?

0

Może podam inny przykład właściwie bardziej sensowny
Mam grę sieciową - nie mogę zrobić jej jako jeden wątek bo każde opóźnienie sieci to będzie zwiecha programu.
Inny przykład moja aplikacja ładuje 200 MB plik na jakimś IDE dysku to mój program będzie zamulał przy startowaniu.
Tutaj potrzebne są watki i mój problem jest taki czy dawać wątkowi specyficzne zadanie (ładuj plik, prowadź komunikację sieciową)
i go kasować czy go mieć włączonego cały czas ( wątek do rysowania, inny do łapania eventów).
Oczywiście wiem że zrobienie 256 wątków na apkę to będzie masakra :)
I jak już o wątkach pisze to jak je synchronizować że jeden nie użyje zasobu zanim ów zasób nie będzie gotowy.

Inna kwestia to jak mogę bardziej profesjonalnie organizować kod programu - te całe warstwy - to nawet nie mam specjalnie pomysłu.

0

Aa no dobra, chodzi Ci o sieciową grę to tutaj nie mam żadnego doświadczenia, więc niestety nie będę mógł pomóc, ale będę śledził temat bo zainteresował ;)

Pozdrawiam serdecznie

0

@Bambo Gra sieciowa to był przykład, TEN projekt to nie sieciówka ale kiedyś ....
Na wstępie powiem ze będę używał GNU GCC , SFML 2.3.2 (dosc istotne dla punktu 3) I GNU/Linux :)
Przemyślałem kilka rzeczy i proszę o ocenę .

1 Myślę że mieć osobny wątek rysujący i aktualizujący w grze n i zrobienie tego tak że oba wątki będą na siebie czekały to jest jakieś ..... nieporozumienie.
W związku z tym będzie wątek główny a dodatkowy wątek będzie wykonywał jakieś konkretne zadanie (tu ładowanie plików gry) a potem czekał na nowe (nie będzie niszczony tylko hmm nieaktywny - taki thread pool z jednym wątkiem - po co tracić czas na niszczenie i tworzenie wątku....)

2 Zakładając że w grze będzie dużo obiektów - pomyślałem ze niezbędny jest manager - DisplayManager - obiekt tej klasy będzie znal pozycje wszelkich obiektów oraz pozycje kamery i decydował które obiekty rysować i aktualizować (czy DisplayManager powinien to robić nie jestem pewien - patrz punkt 5) .

3 Co się jeszcze tyczy punktu 2 - wymyśliłem taki mniej więcej podział na te 'warstwy' - (ZAZNACZAM ) nie wiem za bardzo jak rozumieć warstwy ale....
Gra będzie składała się z kafli i wymyśliłem ze obiekt klasy CTile (klasa kafla) będzie miała w sobie obiekt klasy CDrawableObject.
Ostatnia wspominana klasa będzie udostępniać metodę draw() , setTexture() , setPosition() etc- ona będzie implementować wyświetlanie obiektu.
Klasa CTile będzie aktualizować stan kafla i w razie potrzeby wołać metodę setPosition() lub inną w obiekcie CDrawableObject.
Ten DisplayManager będzie tak naprawdę będzie rysował obiekty CDrawableObject - na nie przeniosę odpowiedzialność
za rysowanie i np jak bym zmieniał technologie na GDI :) to zmieni się implementacje CDrawableObject.
Podobnie mógłbym zrobić z dźwiękiem.

4 Gra będzie podzielona na hermetyczne fragmenty - roboczo nazwałem to sceną (super nazwa wiem ale mogło być gorzej ...)
Sceny będą następujące: ekran początkowy, ekran opcji, gra właściwa, podsumowanie gry właściwej.
Będzie abstrakcyjna klasa CGameSceneInterface i po niej dziedzicząca klasa taka jak np. COptionsScreenScene.

5 Zastanawiałem się tez czy tworzyć coś ala CEventManager - mając przykładowo CSoundsManager mógłbym poinformować go iż zmienia się scena (patrz punkt 4) i odegrał by on jakiś dźwięk przejścia i wyciszył obecne odgłosy / piosenki. Co myślicie ?
Jeżeli chodzi o realizacje tego CEventManager są 2 opcje:
a) Mam w pętli głównej coś typu EventMnager->handleEvent() a wewnątrz metody pełno ifów.
Jak się zastanowić to będzie jakaś porażka bo wiele elementów będą ze sobą 'sklejonych' - np SoundManager i przyciski wszelkiej maści
b) Każdy obiekt może zarejestrować siebie że gdy dany event zdarzy się to chce by wywołać jego metodę:
a') podaną przez niego z właściwymi parametrami - std::bind etc.
b') ogólną - catchEvent(Event e) w której obsłużył by zdarzenie.
Jest też inna sprawa czy eventy to mają być numery ( enum) czy może jakoś bardziej elegancko to zrealizować za pomocą szablonów ?
Podobnie jak tu https://www.gamedev.net/topic/646425-eventbus-possible-with-c-templates/ - swoja droga mniej mi się widzi ta opcja - brak pomysłu ;(

Co sądzicie - dobrze myślę ?

1

Zadaj to pytanie na warsztacie ;), Możesz spróbować napisać konsole, każde polecenie wywołane przez użytkownika,obiekt ląduje w kolejce konsoli( w postaci, obiektu emun'aa string'a czy funkcji) . A w pętli głównej gry robisz coś w stylu

 
while(true)
{
   if(_commandsQueue.Cout!=0)
  {
     var c = _commandsQueue.Dequeue();
     c.Draw();
     c.PlaySound();
     c.DoAction();
  }
}

jesli zapiszesz sobie wykonane akcje i czas, to łatwiej będzię Ci debugować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1