Autor Wątek: Wzorzec projektowy  (Przeczytany 16975 razy)

Offline cybek

  • Użytkownik
    • Strona domowa!

  • +1
# Czerwiec 26, 2012, 16:51:19
Skoro w tamtych czasach dawało radę, to raczej opłacalne. Źródła Quake i Quake 2 są dostępne, warto je poczytać.
Ja tam póki co jednak preferuję robienie interfejsu Object i po nim dziedziczenie z funkcjami wirtualnymi Update i Show.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline koirat

  • Użytkownik

# Czerwiec 26, 2012, 16:51:46
Powiedzmy że używam pewnych wzorców projektowych. No bo jeżeli większość gier robię w środku tak samo, to chyba można nazwać wzorcem? ;)
Najwyższy czas napisać jakąś książke na ich temat, i oświecić nas biednych szaraczków ;)

Co do encji to wspomniany wcześniej model oparty o komponenty wydaje się być pewnym bardziej elastycznym jej odpowiednikiem.

Co do c++ to jest to język który rzeczywiście nie należy do moich ulubionych, jednak wszystko ma swoje zastosowanie, gdy piszę aplikacje embeded stosuje C lub C++, natomiast aplikacje desktopową C#. Jeśli skryptuje gamplay to również wybrał bym C# gdybym mógł. Wszystko to związane jest z kwestią szybkości tworzenia aplikacji. A przy c++ nie jest to bynajmniej "rapid developmnet".

Offline hashedone

  • Użytkownik

# Czerwiec 26, 2012, 17:30:05
He i to jest opłacalne?
Na pewno wygodne. Przy czym zdaje się że Quake1 i Quake2 były pisane w C, w C++ możemy sobie zrobić encje uniami:
struct CommonObjectData
{
  // common object datafields
};

struct MonsterData
{
  // monster specific fields
};

struct NPCData
{
  // NPC specific fields
};

struct StaticObjectData
{
  // Static object specific fields
};

struct Object
{
  enum
  {
    Monster,
    NPC,
    StaticObject
  } type;
  CommonObjectData common;
  union
  {
    MonsterData monster;
    NPC npc;
    StaticObject;
  };
};
Ma tę przewagę, że można ograniczyć wielkość tej struktury i ma też chyba wszystkie zalety normalnej encji z Quake.

Offline Kos

  • Użytkownik
    • kos.gd

# Czerwiec 26, 2012, 17:47:29
Albo jeszcze inaczej (na przykładzie Q):

class Entity {
    // pola wspólne dla każdej klasy
    Vec3 position;
    Vec3 velocity;
    Graphics* model;
    // ...

    // pola "opcjonalne"
    PickupType* pickup; // null, jeśli się tego nie podnosi
    Inventory* inv; // null, jeśli to nie ma żadnego pojęcia ekwipunku
    AI* ai; // null, jeśli to nie jest czymś kontrolowanym przez komputer, or sth

    bool takesDamage; // true jeśli ma być np. trafialne z karabinu i zbierać splash damage z eksplozji
    int hp; // cokolwiek, jeśli s
}

W praktyce zamiast wskaźników robiłbym w wielu miejscach indeksy do globalnych tablic- wtedy można coś takiego łatwo zapisać na dysk (lub przesłać siecią).

Daleko to nie pada od wzorca Krzyśka, ale chciałem pokazać, że taki Entity to nie do końca musi być wszystkomający klocek, bo można z niego wyodrębnić na zewnątrz bardzo wiele rzeczy.
Dla inżynierów oprogramowania, por.: wzorzec strategii :)



Dodam, że o ile w Q sensowne jest mieć tylko 1 rodzaj encji, ale...
- Jeśli robimy np. Pacmana, to bym już robił 2 zupełnie niezależne klasy: "coś co leży na polu" i "coś co się rusza".
- Jeżeli robiłbym Starcrafta, to budynki i jednostki, a także np. kryształy robiłbym jedną klasą, lecz scenerię nie.



Ogólna idea w modelowaniu gier jest wg mnie taka, żeby obiekty różniły się przede wszystkim danymi - sama ilość klas do zrealizowania ich powinna być taka, jaka jest wygodna (czyli najczęściej mała - klasa Ork : public Potwór to najtragiczniejsze rozwiązanie jakie znam).

Odgórnego interfejsu Update / Draw (ostatecznie) nie lubię, bo jest interfejsem bardzo suchym i nie pozwala sam w sobie na żadną sensowną interakcję z obiektami. Wszystkie np. postacie lub jednostki w grze mogą przecież mieć interfejs dużo bogatszy, niż to. "Czy da się podnieść? Co się dzieje, gdy się to podniesie?" "Czy koliduje? Z kim? Jaki ma mesh kolizji?" Itp - wszystkie rzeczy tego rodzaju można imo spokojnie uogólnić w interfejs wspólny dla wielu obiektów w grze.

Offline rm-f

  • Użytkownik
    • Tu trolluje

# Czerwiec 26, 2012, 17:52:04
Cytuj
Jeśli robimy np. Pacmana, to bym już robił 2 zupełnie niezależne klasy: "coś co leży na polu" i "coś co się rusza".
Hmm, klasy w pacmanu? Puknij się :D

Cytuj
Jeżeli robiłbym Starcrafta, to budynki i jednostki, a także np. kryształy robiłbym jedną klasą, lecz scenerię nie.
Imho, wszystko dało by radę tak zrobić...

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 26, 2012, 18:06:19
He i to jest opłacalne?
A co w tym miało by być nieopłacalnego?

Offline yarpen

  • Użytkownik

# Czerwiec 26, 2012, 18:22:40
Marnotrawstwo pamieci. W Q1 to mialo znaczenia, bo tam w danym momencie bylo ze 30 obiektow na krzyz, ale w dzisiejszych grach raczej bym nie polecal... I tak czesto obiekty 'growe' maja po 1k.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 26, 2012, 18:28:07
Marnotrawstwo pamieci. W Q1 to mialo znaczenia, bo tam w danym momencie bylo ze 30 obiektow na krzyz, ale w dzisiejszych grach raczej bym nie polecal... I tak czesto obiekty 'growe' maja po 1k.
Zależy jakich dzisiejszych grach. W amatorskich projektach raczej ważniejsze będzie to, żeby taki projekt szybciej i łatwiej skończyć, niż to, że gra będzie zużywała o jakieś 20MB więcej pamięci.

Offline siso

  • Użytkownik

  • +2
# Czerwiec 26, 2012, 21:41:29
Ach, te klasy. Po cóż one są? Tylko gwałcą prostotę dizajnu... Nie prościej wszystko zamknąć w jednej klasie? Wystarczy mieć unię, enum do sprawdzania co tam akurat siedzi i garść funkcji przyjmujących i zwracających void* ?

Co za łośki z tych współczesnych programistów, no, no. Przecież im gury* C pokazały jak należy programować!

* taka tam liczba mnoga od "guru"

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 26, 2012, 23:12:51
Ach, te klasy. Po cóż one są? Tylko gwałcą prostotę dizajnu... Nie prościej wszystko zamknąć w jednej klasie? Wystarczy mieć unię, enum do sprawdzania co tam akurat siedzi i garść funkcji przyjmujących i zwracających void* ?
Z unią i void* to już nie teges. Unia to premature optimization. Po co masz aliasować pola, jak wystarczy Ci pamięci? Takie triki to się przydają jak ma się 128 bajtów pamięci operacyjnej (patrz: procesory AVR), a nie 1+ GB. A void* też nie potrzebujesz, skoro masz jeden typ.

Możesz się póki co naśmiewać z tego pomysłu, ale to po prostu jest sposób by kończyć gry, a nie tylko je zaczynać. A przynajmniej ja do tego doszedłem (co mi sporo czasu zajęło).

Offline siso

  • Użytkownik

# Czerwiec 26, 2012, 23:56:39
Możesz się póki co naśmiewać z tego pomysłu, ale to po prostu jest sposób by kończyć gry, a nie tylko je zaczynać. A przynajmniej ja do tego doszedłem (co mi sporo czasu zajęło).
Gość z Twoją wiedzą może sobie nawet i w asmie klepać, być w tym niesamowicie dobrym, kończyć projekty i być zadowolonym. Nie mam nic przeciwko :)

Problem pojawi się dopiero wtedy, kiedy takie zaawansowane uproszczenia zacznie stosować niezaawansowany programista i przegapi przez to kilka istotnych ścieżek zawodowego rozwoju.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

  • +3
# Czerwiec 27, 2012, 00:24:20
Cytuj
Problem pojawi się dopiero wtedy, kiedy takie zaawansowane uproszczenia zacznie stosować niezaawansowany programista i przegapi przez to kilka istotnych ścieżek zawodowego rozwoju.
Ja myślę, że obecny model nauki właśnie sprzyja przegapianiu istotnych ścieżek rozwoju. Kiedyś programista zaczynał od Basica na C64 czy podobnym lub w najlepszym razie Pascala i uczył się rozwiązywać proste problemy w sposób prosty. W tej chwili gdy ktoś chce programować podsuwa mu się Grębosza i Thinking in C++, gdzie uczą jak rozwiązywać złożone problemy w sposób złożony. Ale w tej chwili mało który początkujący ma przywilej nauczenia się prostych rozwiązań.

To, co ja sugeruję, to nie przechodzenie na dalszy stopień zaawansowania, tylko propozycja, by odrzucić cały bełkot teologów C++ i zacząć myśleć samemu.

Offline gmpro

  • Użytkownik

# Czerwiec 27, 2012, 10:13:44
Ach, te klasy. Po cóż one są? Tylko gwałcą prostotę dizajnu... Nie prościej wszystko zamknąć w jednej klasie? Wystarczy mieć unię, enum do sprawdzania co tam akurat siedzi i garść funkcji przyjmujących i zwracających void* ?

Co za łośki z tych współczesnych programistów, no, no. Przecież im gury* C pokazały jak należy programować!

* taka tam liczba mnoga od "guru"


Hmm nie no jeśli miałbym jedną klasę i np. w funkcji Update w zależności od typu (miliony ifów czy tam switch) wykonywać obliczenia to chyba bym dostał oczopląsu i w obawie o zdrowie zajął się ogrodnictwem zamiast programowaniem..

czyli najczęściej mała - klasa Ork : public Potwór to najtragiczniejsze rozwiązanie jakie znam
No już kiedyś się o tym przekonałem... Niszczenie i ponowne tworzenie innego typu obiektu, gdy zajdzie potrzeba zmiany typu to męczarnia :P

EDIT:
Co do klas IMO najlepiej tworzyć nowe gdy naprawdę jest taka potrzeba - dana metoda się znacząco zmienia..
« Ostatnia zmiana: Czerwiec 27, 2012, 10:18:45 wysłana przez gmpro »

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Czerwiec 27, 2012, 10:47:52
Cytuj
Hmm nie no jeśli miałbym jedną klasę i np. w funkcji Update w zależności od typu (miliony ifów czy tam switch) wykonywać obliczenia to chyba bym dostał oczopląsu i w obawie o zdrowie zajął się ogrodnictwem zamiast programowaniem..
Z reguły w amatorskich projektach nie ma milionów przypadków i da się to bez trudu ogarnąć.

Offline gmpro

  • Użytkownik

# Czerwiec 27, 2012, 11:09:24
Milion czytaj 10 to dla mnie dużo, wystarczająco dużo, aby sprawić aby kod był nieczytelny. No chyba, że zrobię przerwę z 3 pustych lini albo komentarze typu // ==================================

Z tym, że na moje - nie o to chodzi.. Wolę skorzystać z polimorfizmu.. Być może mam to tak wpojone, ale naprawdę jest to dla mnie przyjemniejsze.

A u mnie projekty nie upadają z powodu zawiłości kodu tylko dlatego, że muszę oprócz programowania zająć się jeszcze tym czego nie umiem czyli grafiką / ewentualnie jakieś efekty dźwiękowe.