Designfrage: Jump and Run



  • Hallo,
    Ich versuche mich gerade an einen Jump and Run mit SFML und C++ als Sprache.

    Allerdings bin ich recht früh auf Designfragen gestoßen bei denen ich nicht weiß wie ich meine Code organisieren soll.

    Ich liste jetzt einfach mal ganz frech meine Ideen auf wie ich die jeweiligen Klassen organisieren möchte und wo mein Problem liegt. Dabei hoffe ich das ihr mir eine kleine Hilfestellung geben könnt wie man es evtl besser strukturieren kann bzw eleganter lösen könnte.

    btw: Habe C++ als Hobby erlernt, wäre auch dankbar wenn ihr mir da grobe Fehler aufzeigen könntet.

    (Code aufs wesentliche reduziert)
    Fall 1:

    //Animation enthält Sprites und animiert sie.
    class Animation
    {
    public:
    protected:
    	Animation() : iteraor(-1) { }
    private:
    	std::vector<sf::Sprite> animation;
        int iterator        //Verweist auf momentane Sprite
        sf::Clock clock;    //Schaltet nach einer bestimmten Zeitschwelle auf nächstes sprite
    };
    
    class Jump : Animation {  } //ähnelt Run
    class Walk : Animation {  } //ähnelt Run
    //Startet die jeweilige Animation aber nur wenn keine Run Aktion atm ausgeführt wird
    class Run
    {
    public:
    	Run() :is_active(false) { }
    private:
        bool is_active;
    	Animation *run_left;
    	Animation *run_right;
    };
    
    class Player : Physic
    {
    public:
    	void jump();
    	void walk();
    	void run();
            void draw();
    private:
    	Jump *jump;
    	Walk *walk;
    	Run  *run;
    };
    

    Frage 1:
    Wie soll ich die Sprites bzw die Animation verwalten?
    -Soll ich sie wie oben in eine "Animationsklasse" laden die die Sprites verwaltet? Nachteil: ich muss die Sprites von Animation bis runter in Player runterreichen da nur Player seine aktuelle Position weiß und sie dort setzen.
    -Soll Animation nur die Spritenummer zurückgeben, dessen Sprite angezeigt werden soll, an Player. Dadurch muss ich aber die Sprites zentral in Player speichern.
    -Andere Ideen? Bzw Wie kann ich am besten Grafische ausgabe von der Logik trennen?

    Frage 2:
    Die Eigenschaften von Player: Run etc.
    -Wenn ich sie wie oben im Code im

    Run  *run;
    

    integriere habe ich folgendes Problem:
    1. Dadurch dürfen die Klassen nicht abstrakt sein da ich sonst nicht darauf zugreifen kann. Dadurch kann man aber auch außerhalb der Player Klasse einfach so ein Run Objekt erstellen was ich eigentlich nicht möchte.
    - Ich könnte natürlich der Player Klasse Run vererben und dadurch Run abstrakt machen und kann dennoch auf Run zugreifen. Aber dann müsste ich meiner Klasse Player ja von etlichen Klassen erben.
    -Oder ganz anders?

    Frage 3:
    **Wann vererbe ich einer Klasse eine Eigenschaft und wann integriere ich einen Typ z.B wie oben in Klasse Player.
    **
    Frage 4:
    **Wie trennt man am besten die Logik von der Grafik? gibts da so Standartwege wie man so etwas machen KANN.
    **
    Frage 5:
    Ist so nen Jump n Run für den Anfang noch zu schwer?
    Habe zwar schon vor den Projekt einige kleine Spielereien gemacht mit SFML, Ping Pong etc pp. Wenn ja was wär der Schritt davor?
    Habe eigentlich grundlegende Erfahrung in C++ und schon nen paar Bücher durch. (kein Wolf :), den dicken Stroustroup: Einführung in die Programmierung und Effective C++ ). Aber da ich noch nie wirklich mit jemanden zusammen programmiert habe (eher nur für mich selbst) weiß ich natürlich nicht wirklich wo ich genau stehe...

    Frage 6:
    Jemand interesse, der auch gerade mit Grafikprogrammierung anfängt in SFML evtl eine Art kleine Lerngruppe zu bilden und an ein kleines Projekt ranzugehen? (Ideen Programmiererfahrungen etc austauschen) Zu zweit ists sicher leichter...
    oder auch gern andere Projekte... PS(bin 20);

    MFG Lyie 🙂



  • Lyie schrieb:

    Ich versuche mich gerade an einen Jump and Run mit SFML und C++ als Sprache.

    Gute Wahl 🙂

    Lyie schrieb:

    class Jump : Animation
    

    Warum Vererbung? Wie werden die Klassen eingesetzt, du scheinst keine virtuellen Funktionen zu haben. Könnte man auch Aggregation ( Animation ist ein Member von Jump ) haben?

    Lyie schrieb:

    Frage 1:
    Wie soll ich die Sprites bzw die Animation verwalten?

    Überleg dir, welche Eigenschaften die Animationsklasse braucht (z.B. Position, aktuelles Frame). Diese könntest du dann an eine entsprechende Funktion

    void Animation::Animate(sf::Sprite& sprite, sf::Vector2f position, unsigned int frame)
    

    weitergeben. Es gibt viele Möglichkeiten. Vielleicht bringt dir ja das etwas (siehe auch SVN-Beispiel), wobei ich zugeben muss, dass die Features noch nicht ganz ausgereift sind.

    Lyie schrieb:

    Frage 2:
    Die Eigenschaften von Player: Run etc.

    Im Fall, dass Run auswechselbar sein soll, könntest du dir das Design-Pattern Strategy anschauen. Sonst kannst du aber ganz normal ein Member-Objekt erstellen. Vermeide einfach manuelle Speicherverwaltung wo möglich.

    Lyie schrieb:

    Frage 3:
    Wann vererbe ich einer Klasse eine Eigenschaft und wann integriere ich einen Typ z.B wie oben in Klasse Player.

    Vererbung benutzt du zu oft. Sie stellt eine sehr starke Kapselung dar und bringt entsprechende Abhängigkeiten im Code mit sich. Versuche zuerst, ein Design mit Aggregation zu lösen.

    Lyie schrieb:

    Frage 4:
    Wie trennt man am besten die Logik von der Grafik? gibts da so Standartwege wie man so etwas machen KANN.

    Viele Wege. Die Separation ist grundsätzlich kein Muss, aber sie hat einige Vorteile. Wenn du Grafik und Logik separieren möchtest, sollte das Logik-Objekt Spieler (mit Physik-, Kollisions-, Gesundheitsdaten) so wenig grafische Informationen wie möglich halten, bzw. davon abstrahieren. Also nur über wenige Schnittstellen mit dem Grafik-Objekt kommunizieren, und diese möglichst von SFML frei halten.

    Eine Möglichkeit besteht auch darin, die Informationen ganz auszulagern. Eine Renderer-Klasse hat dann Überladungen zu verschiedenen Logik-Objekten, also

    void Draw(const Player& player);
    void Draw(const Enemy& enemy);
    void Draw(const Tile& tile);
    

    So hast du den ganzen grafikbezogenen Code an einem Ort, wodurch du leicht die Darstellung für alle Objekte gleichzeitig ändern kannst. Ich mach das in meinem Jump'n'Run momentan auch so. Nachteil ist, dass z.B. Sprites jedes Frame neu erstellt werden, allerdings braucht es recht viel, damit das zum Performance-Problem wird.

    Eine Zwischenlösung wäre eine Map, die Logikobjekte über eine ID auf grafische Objekte abbildet. Beim Zeichnen wird dann der entsprechende Eintrag in der Map gesucht.

    Lyie schrieb:

    Frage 5:
    Ist so nen Jump n Run für den Anfang noch zu schwer?

    Hängt davon ab, wie viel du machen willst. Wenn du Flexibilität und viele Spielelemente wie Lifte, diverse Gegner, Schalter etc. anbieten willst, stell dich auf viel Arbeit ein. Auch Kollisionsabfrage ist nicht trivial, zumindest wenn du mehr als nur rechteckige Tiles haben willst.

    Ich würde zuerst etwas Kleineres versuchen, um etwas Erfahrung mit Spiellogik, Design und solchen Dingen zu sammeln sowie die C++-Kenntnisse zu vertiefen. Kommt halt darauf an, was dir gefällt: Snake mit Zusatzfeatures, Breakout, simpler Spaceshooter, ...



  • Je nachdem wie dein Spiel genau aussieht, würde sich allgemein Model-View-Controller als Architektur-Pattern anbieten.


Anmelden zum Antworten