SFMl-Schießen,Hauptmenü?



  • Hi!
    Bin ziemlicher Neuling was SFMl angeht und bin grad dabei mein kleines eigenes Ballerspiel zu schreiben 😛 ABer hab dazu 2 Fragen:

    1.) Wie gesagt, ist ein 2D.-Shooter und einen Schuss zu machen ist einfach...aber wie mach ich das, dass ich ein und den selben Sprite mehrmals gleichzeitig auf dem Bildschirm habe? Also mehr als nur einen Schuss aufeinmal über den Bildschirm fliegen lassen kann? Oder muss ich für jeden neuen Schuss einen neuen Sprite anlegen?

    2.) Ich wollte auch ein klassisches Hauptmenü mit "Start" "Exit" etc. einbauen...den Code fürs Hauptmenü hab ich soweit, aber wenn ich das dann ans Spiel anhängen will, dann hab ich immer "multiple deklaration von App,Input und Event" ... App is mein Fenster, Input die Inputs wie Maus und Tastatureingaben.
    Meine Aufteilung:
    main.cpp:
    inkluded main.h und menue.h, enthält die Spielschleife

    main.h:
    die Includes von sfml,deklaration von App,Input und Event

    menue.h:
    deklaration von void Menue(); (Mein Hauptmenü-Funktion)

    menue.cpp:
    Schleife fürs Hauptmenü

    Hat wer ne Lösung? Vllt. teil ich auch was einfach unsinnig auf 😃
    Oder sollte ich fürs Hauptmenü ein eigenes Fenster erzeugen und das dann schließen, sobald das Spiel losgeht?

    Viel gerede für 2 Fragen 😉
    Hoffe es kann wer helfen!
    mfg
    Finn



  • Das ist jetzt mehr aus der Kristallkugel. Aber ich denke, dass du wirklich "unsinnig" aufgeteilt hast.

    Folgender Denkansatz:

    Du besitzt genau eine Hauptschleife, welche sich um die Ereignisse etc. kümmert und diese leitet die Eingaben (Tastendrücke, Maus, etc.) an ein gerade aktiviertes "Display" weiter. Ebenso wird nur das aktive "Display" gezeichnet.

    Displays können sein: Hauptmenu, Untermenüs, die Spieldarstellung, End-Credits ...

    Eine abstrakte Basisklasse für diese "Displays" macht somit Sinn.

    Pseudo:

    class IDisplay
    {
        virtual bool isActive() = 0; // Wahr, wenn Display aktiv
        virtual void render() = 0; // Zeichnet das Display
        virtual void processEvent(const TheEventType & theEvent) = 0;
            /* Verarbeitet Ereignisse */
    };
    

    So könnte man die "Displays" hübsch in einer Liste verwalten.

    Grüße... Heiko



  • Finn schrieb:

    wie mach ich das, dass ich ein und den selben Sprite mehrmals gleichzeitig auf dem Bildschirm habe?

    Zeichnen.
    Position ändern.
    Zeichnen.
    ...

    Finn schrieb:

    "multiple deklaration von App,Input und Event" ... App is mein Fenster, Input die Inputs wie Maus und Tastatureingaben.

    Zeig mal Code und Fehler, kann mich grade nicht da reindenken.

    Finn schrieb:

    Oder sollte ich fürs Hauptmenü ein eigenes Fenster erzeugen und das dann schließen, sobald das Spiel losgeht?

    Nee



  • Problem 2 wird meist mir Gamestates gelöst.

    Ein Gamestate ist eine Klasse und hat unter anderem eine Funktion zum zeichnen und eine Funktion zum verarbeiten der Eingabe. Dein Menu und das Spiel selber sind je ein Gamestate. In deinem Hauptprogramm hast du nun eine gewisse Anzahl Gamestates und davon ist ein Gamestate aktiv. Die allgemeine zeichen/input Funktion ruft immer die jeweilige Funktion des aktiven Gamestates auf.

    Beim starten ist dann z.B. der Gamestate für das Intro aktiv. Sobald das Intro zuende ist, wird der Gamestate für dein Menu aktiv. Wenn du dort auf starten klickst, wird der Gamestate für dein eigentliches Spiel aktiv usw.



  • Erst mal bissel (richtig!) mit Objektorientierter Programmierung beschäftigen und solche Probleme erübrigen sich von selbst.



  • Hay danke für die vielen Antworten 🙂 Also mit dem Menü kann ich mir jetzt schon echt was vorstellen drunter! Danke!
    Aber @Amnboss der Rabiator:
    Damit bewege ich ja nur ein einzelnes Sprite über den Bildschirm...ich möchte aber, dass man z.B: die Maustaste gedrückt halten kkann und dann hauts pro sekunde so und so viele schüsse raus! Und ich weiß nicht, wie ichs das machen soll, dass dann mehr als nur eine Kugel übern Bildschirm fliegt!

    Danke ihr habt mir schon wirklich geholfen! Setze mich gleich ran 😃
    mfg
    Finn



  • Finn schrieb:

    Damit bewege ich ja nur ein einzelnes Sprite über den Bildschirm...ich möchte aber, dass man z.B: die Maustaste gedrückt halten kkann und dann hauts pro sekunde so und so viele schüsse raus! Und ich weiß nicht, wie ichs das machen soll, dass dann mehr als nur eine Kugel übern Bildschirm fliegt!

    Wie Amboss das schon sagte: Zeichnen, verschieben, zeichnen, verschieben. Dazu brauchst du in der Tat nur ein Sprite.
    Wenn du ein Sprite zeichnest, dann wird es intern in ein OpenGL GL_QUAD umgesetzt, das die Größe des Sprites und als Textur das Image hat. Das Sprite kannst du danach verschieben und nochmal zeichnen, das ergibt wieder ein anderes, vom ersten unabhängiges GL_QUAD. OpenGL zeichnet nachher sämtliche GL_QUADs auf den Bildschirm.



  • Wett hat denn gesagt, dass ich mit OpenGL arbeite? :-o Oder ist das bei allen Libs so?



  • Aber mit der Aufteilung stimmt irgendwas nicht...hier meine files:

    main.h:

    /////////////////////////////////
    #include <SFML/System.hpp>//////
    #include <SFML/Window.hpp>/////
    #include <SFML/Graphics.hpp>//
    /////////////////////////////
    //Create the main window
    sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Game");
    //Handling events
    sf::Event Event;
    //Handling input
    const sf::Input& Input = App.GetInput();
    //Handling mouseinput
    unsigned int MouseX = Input.GetMouseX();
    unsigned int MouseY = Input.GetMouseY();
    

    main.cpp:

    #include "main.h"
    #include "menue.h"
    
    // MainLoop
    

    menue.h:

    void Menue();
    //Deklarationen fürs Menü
    

    menue.cpp:

    #include "menue.h"
    #include "main.h"
    
    void Menue()
    {
        //das Hauptmenü
    }
    

    Und angezeigt wird, dass alles, was in main.h deklariert wurde, in menue.cpp "redifined" würde...

    Entweder ein kleiner Denkfehler, oder einfach totaler Schrott? 😃



  • 1. Globale Variablen sind böse. Versuch, diese möglichst zu umgehen.
    2. Halte dich an die ODR (One Definition Rule). Du darfst in Headerdateien, die in mehrere Implementierungsdateien eingebunden werden, mit ein paar wenigen Ausnahmen keine Definitionen haben, sondern nur Deklarationen. Schau dir mal das Schlüsselwort extern an (wobei du es besser gleich sauber ohne globale Variablen löst).



  • Aber wenn ich die Variablen nicht global deklariere, wie kann ich dann auf diese zugreifen? Wenn sie in main.cpp stehen komm ich mit menue.cpp ja net ran :-o

    EDIT: Hab mir grad bei msdn extern angeguckt, aber hab net wirklich verstanden was das bringen soll 😕



  • Hier ein bisschen (kompilierbarer) Quelltext. In ähnlicher Form hatte ich das schonmal als SDL-Grundgerüst hier im Forum gepostet. "Aus gegebenen Anlass hin" habe ich das mal auf SFML gemünzt - mit SFML wollte ich mich eh schon mal beschäftigen.

    Die Lösung ist nicht optimal, dafür sollte dich das in die richtige Richtung schubsen.

    Solltest du Sprachmittel (noch) nicht verstehen, so lese dir diese bitte selbständig in einem Buch oder Online-Referenz an.

    ** context.hpp **

    #if !defined(HM_GAME_CONTEXT_HPP__INCLUDED)
    #define HM_GAME_CONTEXT_HPP__INCLUDED
    
    // +++ Header only +++
    
    #include <SFML/Graphics.hpp>
    #include <string>
    
    namespace game {
    namespace app { // Spezieller Namensraum für die Applikations-Schicht
    
    class Context
    /* Der Kontext ist das direkte Bindeglied zwischen plattformspezifischen
    Funktionalitäten und der Anwendungslogik. Er aquiriert die notwendigen
    Resourcen (Grafiken, Fenster, etc.). */
    {
    private:
        // ------------------------------------------------------------------------
        //  Attribute
        // ------------------------------------------------------------------------
        bool running_;
        sf::RenderWindow screen_;
    
        /* TODO: Nachfolgende Grafiken SOLLTEN in einen Resourcen-Manager ausgelagert
        werden! */
        sf::Image gunImage_;
        sf::Image bulletImage_;
    
        /* TODO: Nachfolgende Sprites SOLLTEN in einen separaten View ausgelagert
        werden! */
        sf::Sprite gunSprite_;
        sf::Sprite bulletSprite_;
    
    public:
        // ------------------------------------------------------------------------
        //  Konstruktoren, Destruktor und Zuweisungsoperator
        // ------------------------------------------------------------------------
        Context()
            : running_(true)
            {
                // Videomode und Fenstereinstellungen festlegen
                sf::VideoMode vm(800, 600, 32);
                std::string caption("Game-Example");
                // Resource "Fenster" aquirieren
                screen_.Create(vm, caption);
    
                /* TODO: Nachfolgende Grafiken SOLLTEN in einen Resourcen-Manager
                ausgelagert werden. */
                gunImage_ = sf::Image(20, 20, sf::Color(255, 255, 255));
                bulletImage_ = sf::Image(4, 2, sf::Color(255, 180, 180));
    
                /* TODO: Nachfolgende Sprites SOLLTEN in einen separaten View
                ausgelagert  werden! */
                gunSprite_.SetImage(gunImage_);
                bulletSprite_.SetImage(bulletImage_);
    
                /* ++ Hier sollten auf jeden Fall noch Fehlerüberprüfungen
                stattfinden. ++ */
            }
    
        /* Kopierkonstruktor, Destruktor und Zuweisungsoperator werden automatisch
        generiert.
    
        TODO: Kontext sollte nicht kopierbar sein. */
    
        // ------------------------------------------------------------------------
        //  Hauptschleife
        // ------------------------------------------------------------------------
        void mainloop()
            {
                sf::Event event;
                while(running_) {
                    while(screen_.GetEvent(event)) onEvent(event);
                    onUpdate();
                    onRedrawScene();
                }
            }
    
        void onEvent(const sf::Event & event)
            /* Verarbeiten der SFML-Ereignisse. */
            {
                switch(event.Type) {
                case sf::Event::Closed:
                    running_ = false;
                    break;
                default:
                    /* nichts */;
                }
            }
    
        void onUpdate()
            /* Aktuallisieren der Objekte */
            {
            }
    
        void onRedrawScene()
            /* Zeichnen des Anzeigebereiches */
            {
                screen_.Clear();
    
                screen_.Draw(gunSprite_);
                screen_.Draw(bulletSprite_);
    
                screen_.Display();
            }
    
    };
    
    } // -- namespace app --
    } // -- namespace game --
    
    #endif
    

    ** main.cpp **

    #include "context.hpp"
    
    int main()
        {
            game::app::Context context;
            context.mainloop();
        }
    

    ⚠ Meiner Meinung nach ist die Spieleprogrammierung eines der ungünstigsten Felder, mit denen man Programmieren erlernen kann. Zumindest die Grundlagen[1] (und das sind nicht wenige) sollte man beherrschen - alles andere führt nur (zumindest bei mir war es so) zum Frust. Was wirklich hilft, sind Bücher, Quelltexte und Bücher.

    Das soll dich aber nicht davon abhalten, dein Ziel weiter zu verfolgen. 👍

    • Zu deiner Frage mit OpenGL (lass dich nicht verwirren!): SFML verwendet intern OpenGL - ja, OpenGL kann auch prima 2d. Das braucht dich aber im Moment nicht weiter zu beschäftigen.
    • Das Schlüsselwort extern muss dich im Moment auch nicht beschäftigen.
    • Sieh ersteinmal zu, dass du die Sache mit den Geschossen hintereinander bekommst. Danach kannst du dir Gedanken über ein Menü oder sonstige Spielereien machen.

    Grüße... Heiko
    ----
    [1]: Funktionen, Referenzen, Zeiger, virtuelle Methoden, Vererbung, Polymorphie, MVC, ...



  • Finn schrieb:

    Wett hat denn gesagt, dass ich mit OpenGL arbeite? :-o Oder ist das bei allen Libs so?

    Du arbeitest mit SFML, das nutzt OpenGL. War nur zur Verdeutlichung erwähnt.

    EDIT:
    bwbg hat das unter seinem Code gut zusammengefasst.



  • Wow also der Code von bwbg is dann doch ein bisschen was anderes als das, was ich habe 😃 Ich glaub ich fang mit dem Spiel nochmal neu an...und plane das vorher auch mal durch, bevor ich anfange^^ Sollte anfangs nur so zum bisschen rumprobieren sein, aber das reizt mich jetzt schon, das zu Ende zu bringen! 🙂
    Vielen Dank für die Posts!
    grüße,
    FInn


Log in to reply