CrackGM Opublikowano 19 Sierpnia 2014 Udostępnij Opublikowano 19 Sierpnia 2014 Ponieważ wiele osób ma problemy z organizacją kodu w grach pisanych poza GM i często stosują artystyczny nieład w którym później sami nie mogą się połapać postanowiłem napisać krótki tutorial który może pomóc. Zapewne wielu bardziej doświadczonych koderów gier ode mnie wyśmieje ten sposób - z góry mówię nie jest to najlepszy sposób - ma on na celu pomóc przemyśleć organizację w kodzie. A więc gwoździem programu są klasy i dziedziczenie które musicie opanować. (http://pl.wikibooks.org/wiki/C%2B%2B/Czym_jest_obiekt oraz http://pl.wikibooks.org/wiki/C%2B%2B/Dziedziczenie), sam mistrzem nie jestem, często zaglądam do pomocy online ale podstawy trzeba znać. Nie będę tutaj się rozpisywał, lepiej przejdę do konkretów. Najpierw musimy sobie zrobić "szkielet" naszych przyszłych gjeemowych obiektów: class Object { public: int myID; bool exists; virtual void onCreate()=0; virtual void onStep()=0; virtual void onRender()=0; virtual void onDestroy()=0; }; Jak każdy GMowy obiekt mamy eventy, dlatego jest to umieszczone w szkielecie (każdy obiekt ma eventy - tutaj pokazałem przykładowe). Zwróćcie uwagę na to że metody wewnątrz szkieletu są abstrakcyjne, jest to ważne. Zmienna booleanowa exists jest pierdołą która może się przydać później, oczywiście pokażę to niżej. Warto również zapisać sobie ID obiektu, które zapodamy później w naszym vectorze, który będzie nam przechowywał stworzone już obiekty, który definiujemy w ten sposób: vector<Object*> objects; Vector nie przechowuje klas abstrakcyjnych...ale może przechowywać wskaźniki na nie. To teraz możemy dodać trochę kolejnych pierdół do naszego kodu typu: int ids = 0; bool gameIsOn = true; Zalecam zadeklarować to jako zmienne globalne. Teraz definicja naszego obiektu: class oPlayer : public Object { public: virtual void onCreate(); virtual void onStep(); virtual void onRender(); virtual void onDestroy(); int health; // nasze zmienne }; void oPlayer::onCreate() { health = 10; } void oPlayer::onStep() { health -= 1; if (health <= 0) { onDestroy(); } } void oPlayer::onRender() { cout << health << endl; } void oPlayer::onDestroy() { gameIsOn = false; exists = false; } Jeżeli rozumiecie klasy i dziedziczenie to nie ma co tutaj się rozpisywać... raczej wszystko jest jasne :) Teraz najważniejsza część kodu - pętla główna gry itp: int main() { int playerID = ids; // jak przechowywać ID playera objects.push_back(new oPlayer()); //dodajemy nowy obiekt do vectora ids ++; //i zapisujemy sobie ile to już mamy obiektów. //obsługa eventów - onCreate - wykonywane tylko raz. Oczywiście onCreate można zastąpić sobie zwykłym konstruktorem (w sumie jest niepotrzebne, lepiej użyć konstruktor - wtedy jest łatwiej jeżeli tworzymy obiekty w toku gry) for (int i = 0; i < ids; i++) { objects[i]->myID = i; // zapisujemy sobie id obiektu z vectora objects[i]->onCreate(); } //pętla głowna gry - tutaj wszystko się "dzieje" while(gameIsOn) { //znów obsługa eventów...onStep for (int i = 0; i < ids; i++) { if (objects[i]->exists) { objects[i]->onStep(); } } //...i onRender for (int i = 0; i < ids; i++) { if (objects[i]->exists) { objects[i]->onRender(); } } } cout << "Game End." << endl; system("pause"); return 0; } Mam nadzieję że wszystko jest w miarę jasne. Znów podkreślam że tutorial nie jest "sztywnym" szkieletem dla twórców gier - to jest tylko najprostszy przykład organizacji obiektów/kodu, dla początkujących koderów gier. Sam na tym działam...no i działa :D Cały kod: #include <iostream> #include <vector> using namespace std; class Object { public: int myID; bool exists; virtual void onCreate()=0; virtual void onStep()=0; virtual void onRender()=0; virtual void onDestroy()=0; }; vector<Object*> objects; int ids = 0; bool gameIsOn = true; class oPlayer : public Object { public: virtual void onCreate(); virtual void onStep(); virtual void onRender(); virtual void onDestroy(); int health; }; void oPlayer::onCreate() { health = 10; } void oPlayer::onStep() { health -= 1; if (health <= 0) { onDestroy(); } } void oPlayer::onRender() { cout << health << endl; } void oPlayer::onDestroy() { gameIsOn = false; exists = false; } int main() { int playerID = ids; objects.push_back(new oPlayer()); ids ++; for (int i = 0; i < ids; i++) { objects[i]->myID = i; objects[i]->onCreate(); } while(gameIsOn) { for (int i = 0; i < ids; i++) { if (objects[i]->exists) { objects[i]->onStep(); } } for (int i = 0; i < ids; i++) { if (objects[i]->exists) { objects[i]->onRender(); } } } cout << "Game End." << endl; system("pause"); return 0; } (polecam również każdy obiekt zapodać sobie w oddzielnym headerze (dla mało wiedzących *.h)) I tak nikt nie doceni, ale przynajmniej jest. xD Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
PsichiX Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 niestety, ale nie doceniam. brak generycznego sposobu tworzenia game objectow, do tego generowanie identyfikatorow na poczatku programu, co powoduje ze nie mozna dodawac instancji w locie (bullety, itp.). Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
CrackGM Opublikowano 20 Sierpnia 2014 Autor Udostępnij Opublikowano 20 Sierpnia 2014 Do dodawania instancji w locie wystarczylo zamienic onCreate na zwykly konstruktor i dopisac funkcje w stylu findfreeid (banalne) Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
PsichiX Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 w takim razie pokaz im jak to zrobic, skoro to banalne :) Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Pasztet Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 Do dodawania instancji w locie wystarczylo zamienic onCreate na zwykly konstruktor i dopisac funkcje w stylu findfreeid (banalne) Ale niepraktyczne. Ja swoją scene napisałem w trochę innym soposobem ;) https://github.com/Mati365/Potato3D-Engine/...phics/Scene.hpp Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
PsichiX Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 @Pasztet: setParent() nie powinno byc w ogole publiczne - stwarzasz tym mozliwosc zepsucia apki przez uzytkownika. Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Pasztet Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 @Pasztet: setParent() nie powinno byc w ogole publiczne - stwarzasz tym mozliwosc zepsucia apki przez uzytkownika. Racja, chyba cos przeoczylem bo dodalem po to przyjaciol ;) By zbatchowac swiatla ch6na ja upublicznilem Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
CrackGM Opublikowano 20 Sierpnia 2014 Autor Udostępnij Opublikowano 20 Sierpnia 2014 #include <iostream> #include <vector> using namespace std; class Object { public: bool exists; virtual void onStep()=0; virtual void onRender()=0; virtual void onDestroy()=0; Object() { exists = true; } }; vector<Object*> objects; int ids = 0; bool gameIsOn = true; class oPlayer : public Object { public: oPlayer(); virtual void onStep(); virtual void onRender(); virtual void onDestroy(); int health; }; oPlayer::oPlayer() { health = 10; } void oPlayer::onStep() { health -= 1; if (health <= 0) { onDestroy(); } } void oPlayer::onRender() { cout << health << endl; } void oPlayer::onDestroy() { gameIsOn = false; exists = false; } int findFreeID() { for (size_t i = 0; i < objects.size(); i++) { if (!objects[i]->exists) return i; } return -1; } int newObject(Object* obj) { int id = findFreeID(); if(id != -1) { objects[id] = obj; } else { objects.push_back(obj); id = objects.size()-1; } return id; } int main() { int playerID = newObject(new oPlayer()); cout << "Player ID: " << playerID << endl; while(gameIsOn) { for (size_t i = 0; i < objects.size(); i++) { if (objects[i]->exists) { objects[i]->onStep(); } } for (size_t i = 0; i < objects.size(); i++) { if (objects[i]->exists) { objects[i]->onRender(); } } } cout << "Game End." << endl; system("pause"); return 0; } V2 + Dodawanie obiektów w locie :3 Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Sutikku Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 Mi tam się podoba. Wyciągnąłem z tego cenną naukę :thumbsup: Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Pasztet Opublikowano 20 Sierpnia 2014 Udostępnij Opublikowano 20 Sierpnia 2014 Nie ucz się tworzyć wylęgarni memory leaków. Wydajność przy wielu elementach tutaj dosłownie leży D: Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
CrackGM Opublikowano 20 Sierpnia 2014 Autor Udostępnij Opublikowano 20 Sierpnia 2014 He, wiesz, nie napisalem ze to jest najlepszy sposób tylko pomoc/drogowskaz dla tych którzy nie mają o tym zielonego pojęcia :D Odnośnik do komentarza Udostępnij na innych stronach Więcej opcji udostępniania...
Rekomendowane odpowiedzi
Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto
Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.
Zarejestruj nowe konto
Załóż nowe konto. To bardzo proste!
Zarejestruj sięZaloguj się
Posiadasz już konto? Zaloguj się poniżej.
Zaloguj się