Klassenhierarchie für Jump&Run
-
Huhu!
Ich hab mir in den Kopf gesetzt ein Jump&Run zu programmieren. Also nur etwas einfaches, mit nicht zu viel Umfang.
Dafür hab ich mich in den letzten Wochen in SDL eingelesen und konnte auch schon einige Erfolge erzielen.Allerdings habe ich noch ein Problem mit der Planung. Natürlich will ich das ganze in Oop schreiben und nicht einfach irgendwas zusammenstöpseln. Allerdings ist mir nicht ganz klar, welche Klassen ich für ein j&r brauche und wie deren Hierachie aufgebaut sein muss und welche Interfaces ich zb brauche. Wie geht man dann am besten an sowas ran? Es wär nett, wenn ihr mir sagen könntet, wie ihr normalerweise bei der Planung vorgeht.
mfg
tipfehler
-
na dann zeig mal wie weit du mit der planung bist, dann koennen wir dir gerne tipps geben

-
Danke, dann versuch ich das ganze erstmal zu Ordnen.
Grundsätzlich wollte ich erstmal die Funktionalität beschreiben, indem ich ein kleines Bild von einem Level gemacht habe, wie es
später mal aussehen soll.
Hier erstmal die Bilder:
Bild 1
Bild 2Grundsätzlich wollte ich ein Startmenü erstellen, mit dem man das Spiel starten, Optionen treffen und das Spiel beenden kann. Beim Spielstart soll dann das Level geladen werden und man soll die Spielfigur #1 steuern können. Diese kann springen und laufen.
Pull stellen einfach Wolken dar und ::1 soll einen Gegner darstellen. Grafik spielt ja im Moment keine Rolle, mir geht es hier nur um Funktionalität

Die Karte besteht natürlich aus Tiles. Wobei ich gelesen habe, dass man so bei Größeren Karten Probleme bekommen kann. Deshalb wird das Ganze noch in Areas aufgeteilt. In meinem Beispiel wäre Bild 1 == Area 1 und Bild 2 == Area 2. Des weiteren brauch ich dann noch eine Überklasse, die steuert welche Areas gerade sichtbar sind und nur diese gerendert werden. Für meine beweglichen Tiles wollte ich eine Entity Klasse, mit den Funktionen Reder und Update, als Framework erstellen. Von der ich dann meine Spieler- und Gengnerklassen ableiten kann; auch zb die Wolken. Das mit der Animation muss ich mir noch anschauen, aber das kann man dann natürlich alles über die Updatefunktionen regeln.
Generell steuere ich den Spielablauf dann über eine Klasse main, welche die Spielschleife enhält und auch Eingaben verarbeitet.
Allerdings weiß ich nicht genau wie ich das ganze Zeitmäßig steuern muss und sicherlich hab ich eh die Hälfte vergessen. Soweit ist meine Planung bisher fortgeschritten und ich wollte jetzt eben fragen, ob ihr einen Tipp habt, wie man das ganze eben am besten in Klassen aufteilen kann oder was man generell beachten sollte.mfg
tipfehler
-
tipfehler schrieb:
ob ihr einen Tipp habt, wie man das ganze eben am besten in Klassen aufteilen kann
Du hast doch schon eine ganze Menge genannt:
Spiel, Menü, Level, Spielfigur, Wolke, Gegner, Tile, Area, "Überklasse, die steuert welche Areas gerade sichtbar sind", Entity usw.
-
tipfehler schrieb:
Die Karte besteht natürlich aus Tiles. Wobei ich gelesen habe, dass man so bei Größeren Karten Probleme bekommen kann. Deshalb wird das Ganze noch in Areas aufgeteilt. In meinem Beispiel wäre Bild 1 == Area 1 und Bild 2 == Area 2. Des weiteren brauch ich dann noch eine Überklasse, die steuert welche Areas gerade sichtbar sind und nur diese gerendert werden.
Wieso meinst du, dass man deswegen Probleme bekommen kann? Du musst ja nicht alle Tiles rendern, sondern immer nur die sichtbaren. So, wie du es jetzt handhabst, müssen fast immer mindestens 2 (oder sogar 4) Areas gerendert werden, obwohl diese gar nicht ganz sichtbar sind. Oder hab ich dich falsch verstanden?
tipfehler schrieb:
Generell steuere ich den Spielablauf dann über eine Klasse main, welche die Spielschleife enhält und auch Eingaben verarbeitet.
Allerdings weiß ich nicht genau wie ich das ganze Zeitmäßig steuern muss und sicherlich hab ich eh die Hälfte vergessen. Soweit ist meine Planung bisher fortgeschritten und ich wollte jetzt eben fragen, ob ihr einen Tipp habt, wie man das ganze eben am besten in Klassen aufteilen kann oder was man generell beachten sollte.Ich hab mal ein Jump'n'Run programmiert, aber da war ich noch ziemlich in den Anfängen der Grafikprogrammierung. Ich hatte damals Klassen für die Spielfigur, Gegner, abgeschossene Waffen, Tiles, und eine Oberklasse für die Welt (mit Tile-, Waffen- und Gegner-Arrays). Spielfigur, Gegner und Waffen waren von einer gemeinsamen Klasse abgeleitet, die z.B. Kollisionsabfragen etc. handhabte.
Eventuell lohnt es sich, eine zentrale Klasse (wie z.B. Welt oder sogar noch höher, mit mehreren Welten als Member) zu erstellen.Ach ja, noch etwas, das ich nicht ganz verstehe: Sind bei dir die Tiles nicht rasterförmig angeordnet? Weil auf deinen Screenshots überlappen sich die Tiles. Oder sind diese jeweils aus 4 kleineren Tiles zusammengesetzt?
-
Ich glaube da herausgelesen zu haben, dass du alles (Spielstatusverwaltung etc.) in eine Hauptschleife packen willst. Das endet nach einiger Zeit sehr schnell (bei einem Projekt von einer gewissen Größe) in nem 1000+ Zeilen langen Labyrinth aus if()s und switch()'s .
Es ist generell , ich will nicht sagen unbedingt 100% notwendig -aber zumindest -, gewaltig hilfreich abstrahierend denken zu können. Ich weiss nicht genau wie man sich das antrainieren kann, aber ein kleines Beispiel:
Du wirst das im Moment wohl etwa so machen (wenn du es so machst wie ich denke, dass du es machst):
class Main //weiss btw nicht ob das so gut ist { public: void run() { //blabla while(running) { if(gamestate == MAIN_MENU) { //tu dies und das } else if(gamestate == INGAME) { if(spieler_drückt(OBEN)) { spielfigur->jump(0,-50); } else if(blabla) // if,if,if,if,if } else if(gamestate = blablub) //else if else if else if { } } zeichne_alles(); } };Wie gesagt, das endet irgendwann im Chaos, aber ich denke, am Anfang hat das jeder von uns so gemacht.
Du solltest versuchen alle Bestandteile deiner Spielewelt erst einmal in möglichst große "Obergruppen" zu packen, welche dann später als Vorlagen (abstrakte Klassen) für mehr spezifische Objekte (Animierte und statische Sprites, Background Ambients und Soundeffekte, Gamestates etc etc) dienen.
Um etwas konkreter zu werden:
Alle Dinge die mal auf deinen Bildschirm gezeichnet werden (Ob es Tiles, irgendwelche statischen Sprites oder GUI ist), haben doch etwas gemeinsam, richtig?
Um noch genauer zu werden, bei SDL braucht z.B. jedes Element ein SDL_Surface, in dem deine Bitmaps gespeichert werden, und wahrscheinlich auch eine Position.
Eine Methode zum Zeichnen selbstverständlich auch.class SceneElement { public: virtual void draw() = 0; //Statische Sprites werden anders gezeichnet als //z.B. animierte Sprites, weshalb du das wohl //später in einer erbenden Klasse definierst. protected: SDL_Surface *m_bitmap; SDL_Surface *m_target_surface; //Irgendwohin muss ja gezeichnet werden SDL_Rect *m_position; };Wenn du gut überschaubaren, leicht zu veränderten (meist "Modul"-basierten) Code schreibst, werden fast alle Bestandteile deiner Spielwelt ( ob sichtbar[sprites] oder nicht sichtbar[Spielzustandmanager]) zunächst als abstrakte "Schablonen" exisiteren.
Konkretere und "anwendbare" Klassen erben dann von deinen abstrakten Klassen.
class AnimatedSprite : public SceneElement { public: void draw(); void add_animation(Animation *anim); //Wie Animation aussieht, überlegst //du dir wohl lieber selbst private: std::vector<Animation > m_animation_steps; };Das vereinfachende daran ist nun, dass du nicht für jedes einzelne Bildschirmelement einen eigenen "Manager" brauchst, der alles verwaltet (z.b. einen für Hintergrundbilder, für statische Sprites, usw), sondern einfach eine große Verwaltungsklasse hast, welche SceneElements annimmt. Da alle deine zu zeichnenden Elemente davon erben, funktioniert sowas:
class SceneManager { public: void add_element(SceneElement *elem); //m_elems.push_back(elem); void draw_all(); //for(blabla) m_elems[i]->draw(); private: std::vector<SceneElement*> m_elems; };//In irgendeiner Spielklasse void Spielklasse::init() { m_scene_manager.add_element(new StaticSprite("bla\bla.bmp",50,50)); } void Spielklasse::render() { m_scene_manager.draw_all(); }Und so weiter und sofort. Abstrahieren ist halt wichtig. Das machst du dann für Spielzustände, Sound, usw genauso. Wenn du gut denken kannst, musst du das nicht mal richtig durchplanen. Ich mach das jedenfalls meistens während ich schon tippe.
Es wird dir viel einfacher Fallen, im Laufe der Entwicklung neue Features zu implementieren und alte abzuändern, als es dir mit dem Chaos der "Hauptschleife" gelungen wäre.
-
Hmm so bräuchte der SceneManager das RenderDevice. Ist das nicht unschön?
Über solche Dinge hab ich mir auch schon den Kopf zerbrochen...MfG
-
ja, ist eigentlich unschoen, normalerweise sollte der renderer (oder rendermanager oder wie man es nennen will) sich drum kuemmern. aber ich glaube fuer den anfang ist das schon ok so.
alles auf einmal schafft man eh nicht zu lernen, lieber was einfaches fertig bekommen