Pong (Allegro) hat schwere Performance-Probleme



  • Ich bin dabei in Allegro ein Pong zu schreiben, auser der Ballphysik ist es eigentlich auch schon fertig. Es hat aber eine extrem schlechte Performance, auf meinem 2x 2Ghz Nootebook habe ich eine 50% CPU Auslastung und auf etwas älteren Rechnern ruckelt es gar. Ich hab keine Idee wie ich das Problem lösen kann.

    Da ich das Programm warscheinlich sowieso komplett neu schreiben werden muss habe ich auch schon überlegt auf eine andere Grafikbibliothek umzusteigen. Kennt ihr vieleicht eine bessere als Allegro mit ähnlichem Umfang und die auch so einfach zu Bedienen und verstehen ist (am besten Objektorientiert)?

    Hier mal der Sourcecode:

    #include <iostream>
    #include <rechteck.h>
    #include <winalleg.h>
    #include <allegro.h>
    #include <alfont.h>
    
    using namespace std;
    
    class pongBall {
    
        int x, y, length, height, screenx, screeny, color;
        bool visible;
    
        public:
    
        int speedx, speedy;
    
        pongBall(int bildschirmx, int bildschirmy, int posx = 0, int posy = 0, int laenge = 0, int hoehe = 0, int geschwindigkeit = 0, int farbe = 0x000000) {
    
            if(posx == 0 && posy == 0 && laenge == 0 && hoehe == 0) {
                visible = false;
            }
            else {
                x = posx;
                y = posy;
                visible = true;
            }
            color = farbe;
            length = laenge;
            height = hoehe;
            speedx = geschwindigkeit;
            speedy = geschwindigkeit;
            screenx = bildschirmx;
            screeny = bildschirmy;
        }
    
        void print(BITMAP* bitmap) {
                rectfill(bitmap, x, y, x + length, y + height, color);
        }
    
        void setPosition(int posx, int posy) {
            x = posx,
            y = posy;
        }
    
        int getPositionX() {
            return x;
        }
    
        int getPositionY() {
            return y;
        }
    
        void setSize(int laenge, int hoehe) {
            length = laenge;
            height = hoehe;
        }
    
        int getSizeX() {
            return length;
        }
    
        int getSizeY() {
            return height;
        }
    
        void overprint(BITMAP* bitmap, int farbe = 0x000000) {
                rectfill(bitmap, x, y, x + length, y + height, farbe);
        }
    
        void setColor(int farbe) {
            color = farbe;
        }
    
        int getColor() {
            return color;
        }
    
        bool collide(rechteck recht2) {
    
            if( (recht2.getPositionX() <= (x + length)) && ((recht2.getPositionX() + recht2.getSizeX()) >= x) && (recht2.getPositionY() <= (y + height)) && ((recht2.getPositionY() + recht2.getSizeY()) >= y) ) {
                return true;
            }
            else {
                return false;
            }
    
        }
    
        short wand() {
    
            if((y <= 0) || ((y + height) >= screeny)) {
                return 3;
            }
            else if(x <= 0) {
                return 1;
            }
            else if((x + length) >= screenx) {
                return 2;
            }
            else {
                return 0;
            }
        }
    
    };
    
    int main() {
    
    	//Bildschrimauflösung einlesen
        int x = GetSystemMetrics(SM_CXSCREEN);
        int y = GetSystemMetrics(SM_CYSCREEN);
    
    	//Allegro und Alfont initialisieren
        allegro_init();
        install_keyboard();
        alfont_init();
        set_color_depth(16);
        set_gfx_mode(GFX_AUTODETECT, x, y, 0, 0);
    
        BITMAP *buffer;
        buffer = create_bitmap(x, y);
    
        ALFONT_FONT *myfont;
        myfont = alfont_load_font("digital.ttf");
        alfont_set_font_size(myfont, 30);
    
        rechteck schlaeger1(0, 0, 10, 40, 0xFFFFFF, true);
        rechteck schlaeger2(x - 10, 400, 10, 40, 0xFFFFFF, true);
        pongBall ball(x, y, x/2, y/2, 15, 15, 4, 0xFFFFFF);
    
        int punkte1 = 0, punkte2 = 0;
    
        while(!key[KEY_ESC]) {
    
            clear(buffer);
    
    		//Schläger 1 bewegen
            if(key[KEY_DOWN]) {
                schlaeger1.setPosition(0, schlaeger1.getPositionY() + 6);
            }
            else if(key[KEY_UP]) {
                schlaeger1.setPosition(0, schlaeger1.getPositionY() - 6);
            }
    
    		//Schläger 2 bewegen
            if(key[KEY_S]) {
                schlaeger2.setPosition(x - schlaeger2.getSizeX(), schlaeger2.getPositionY() + 6);
            }
            else if(key[KEY_W]) {
                schlaeger2.setPosition(x - schlaeger2.getSizeX(), schlaeger2.getPositionY() - 6);
            }
    
    		//Kolisionsabfrage mit  den Schlägern und dann mit den Wänden
            if(ball.collide(schlaeger1) || ball.collide(schlaeger2)) {
                ball.speedx *= -1;
                ball.speedy *= -1;
            }
            else if(ball.wand() == 1) {
                ball.setPosition(x/2, y/2);
                punkte2++;
            }
            else if(ball.wand() == 2) {
                ball.setPosition(x/2, y/2);
                punkte1++;
            }
            else if(ball.wand() == 3) {
                ball.speedy *= -1;
            }
    
            alfont_textprintf_centre_aa(buffer, myfont, x/2, 5, 0xFFFFFF, "%d   :   %d", punkte1, punkte2); //Punkte ausgeben
    
            ball.setPosition(ball.getPositionX() + ball.speedx, ball.getPositionY() + ball.speedy); //Position des Balles neu setzen
    
    		//Schläger und Ball in den Buffer zeichnen
            schlaeger2.print(buffer);
            schlaeger1.print(buffer);
            ball.print(buffer);
    
    		//Buffer auf Bildschirm ausgeben
            blit(buffer, screen, 0, 0, 0, 0, x,  y);
    
            Sleep(5);
    
        }
    
        return 0;
    }
    END_OF_MAIN();
    

    Das rechteck Objekt ist mit dem pongBall Objekt Ident außer das die Funktionen collide und wand fehlen.

    Hoffe ihr könnt mir helfen!

    mfg
    zigarrre



  • Das Performance-Problem liegt ziemlich sicher nicht an Allegro, mit der Bibliothek kann man wesentlich aufwaendigere Grafiken relativ Fluessig machen. Das sleep in der Mainloop muesst z. B. nicht sein.
    Aber dein groesster Performancefresser sind wohl die Zeichenoperationen: rectfill wird vermutlich pixel fuer pixel arbeiten (sprich pixel fuer pixel einfaerben), und genau das ist ein Killer fuer aktuelle Hardware, die ist sowas nicht gewohnt. Verwende mal echte Bitmaps, ie du einfach blittest, statt mit fillrecht zu arbeiten. Wirst sehen dass das die Sache beschleunigt. Trotzdem sollten die paar Pixel eigentlich kein Problem sein, ehrlich gesagt hab ich k.A. wo's bei dir aneckt.

    Ansonsten: SDL und vor allen Dingen SMFL werden heutzutage fuer C++ sehr gern benutzt, schau dir die mal an!



  • Das Sleep brauch ich zur Geschwindigkeitssteuerung. Mit einem Timmer wäre es warscheinlich besser aber die hab ich nicht ganz verstenden.

    Ich wärd mir aber mal SFML anschauen, da das auch gleich Netzwerkfunktionalität eingebaut hat und mein Pong Multiplayer übers Netzwerk bieten soll. Kenn vieleicht jemand ein gutes (Möglichst deutsches) Tutorial für SFML?



  • es gibt doch die rest funktion bei allegro, vermutlich hat die ne bessere performance.



  • zigarrre schrieb:

    Das Sleep brauch ich zur Geschwindigkeitssteuerung. Mit einem Timmer wäre es warscheinlich besser aber die hab ich nicht ganz verstenden.

    Ich wärd mir aber mal SFML anschauen, da das auch gleich Netzwerkfunktionalität eingebaut hat und mein Pong Multiplayer übers Netzwerk bieten soll. Kenn vieleicht jemand ein gutes (Möglichst deutsches) Tutorial für SFML?

    Sleep als Kontrolle über Geschwindigkeit ist schlichtweg scheisse, hast ja schon eingesehen. Und timing is gar net so schwer. Ich dachte auch immer das kapiere ich nie. Hier ein einfachen Worten:

    1.) Zeit am Anfang deines Frames abfragen
    2.) Zeit am Ende deines Frames abfragen oder beim nächsten Durchlauf.
    3.) Zeit des jetzigen Frames speichern
    4.) Im nächsten Frame die Zeit des vorherigen (3.) abfragen und von der Zeit die in im jetzigen Frame herrscht abziehen, das ergibt das Delta.
    Das Delta ist die Zeit die seit dem letzten Frame vergangen ist.

    Als Code mit SDL:

    void NLWindowGL::enterLoop()
    {
        u32 lastTick = 0;
        u32 ticks = 0;
        u32 delta = 0;
        bool mouseBState = false;
    
        // ATTENTION: Infinite Loop!
        while (true)
        {
            /************************************************************************/
            /* Timing                                                               */
            /************************************************************************/
            ticks = SDL_GetTicks();        
            delta = ticks-lastTick;
            lastTick = ticks;
    
            /************************************************************************/
            /* Input                                                                */
            /************************************************************************/
            SDL_Event evt;
            while (SDL_PollEvent(&evt))
            {         
                switch (evt.type)
                {
                    case SDL_KEYDOWN:
                    {
                        m_keyEvent(evt.key.keysym.sym, true);
                        break;
                    }
                    case SDL_KEYUP:
                    {
                        m_keyEvent(evt.key.keysym.sym, false);
                        break;
                    }
                    case SDL_MOUSEBUTTONDOWN:
                    case SDL_MOUSEBUTTONUP:
                    {
                        mouseBState = (evt.button.state == SDL_PRESSED);
                        u8 key = evt.button.button;
                        m_keyEvent(key, mouseBState);
                        break;
                    }
                    case SDL_MOUSEMOTION:
                    {
                        u8 key = evt.button.button;
                        m_mousepos = NLVector2f(evt.motion.x, evt.motion.y);
                        m_mouseEvent(evt.motion.x, evt.motion.y, key, mouseBState);
                        break;
                    }
                    case SDL_QUIT:
                    {
                        bool quit = false;
                        if (m_quitEvent.size() == 0)
                        {
                            quit = true;
                        }
                        if (m_quitEvent.emit() == true)
                        {
                            quit = true;
                        }
                        if ( quit )
                        {
                            SDL_Quit();
                            return;
                        }
                        break;
                    }
                }
            }
    
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    
            /************************************************************************/
            /* Render-Event                                                         */
            /************************************************************************/   
            SystemController().getRenderManager().renderObject();
            m_renderEvent.emit(delta);
    
            /************************************************************************/
            /* OpenGL-Debugging                                                     */
            /************************************************************************/
    #       if defined(_DEBUG) && NL_PERFORM_OPENGLCHECK == 1
            u32 err = glGetError();
            while (err != GL_NO_ERROR && err != m_prevGLError)
            {
                m_prevGLError = err;
                std::stringstream ss;
                ss << "[OpenGL] " << gluErrorString(err);
                NLError(ss.str().c_str());
                err = glGetError();
            }
    #        endif
    
            /************************************************************************/
            /* Framecounter                                                         */
            /************************************************************************/
            m_frameCounter.update(delta);
    
            /************************************************************************/
            /* Swapping the buffers                                                 */
            /************************************************************************/
            SDL_GL_SwapBuffers();        
        }
    }
    

    Willst Du jetzt etwas bewegen musst Du nur das Delta mit der zahl multiplizieren, um die deine Einheit weiterbewegt wird.
    Pseudo-Code:

    spaceship.position.x = 0.5 * delta;
    

    Hoffe das war verständlich und sorry für den Haufen Code bin grade zu müde das vernünfig zu kürzen, sollte aber verständlich sein. Ist halt meine Main-Loop.
    rya.



  • Ich werde auf jeden Fall die Grafikbibliothek wechseln, da Allegro ja sehr veraltet ist. Was ist denn da besser SDL oder SFML?



  • Kenn vieleicht jemand ein gutes (Möglichst deutsches) Tutorial für SFML?

    Auf der Entwicklerseite gibt es ser gute Tutorials zu jeden Thema.

    Was ist denn da besser SDL oder SFML?

    Ich kenne SDL nicht, kann SFML aber sehr empfehlen. Sehr schönes und einfaches Design.

    MfG,
    ScRaT



  • Aber die sind auf Englisch, gibts nichts Deutsched für SFML? Und in welcher Reihenfolge sollte ich die am besten duchmachen um die Dinge auch zu verstehen?



  • So hab jetzt einen Einstigspunkt in die Tutorials gefunden (hab bei "Opening a Window angefangen und dann immer mit dem am ende Empfohlenen weitergemacht).

    Zuerst hatte ich das Problem das er die Dateien "GL/gl.h" und "GL/glu.h" nicht fand. Das hab ich aber gelöst indem ich sie mit "apt-get install libgle-dev" und libglu-dev nachinstaliert habe (benutze Ubuntu). Jetzt habe ich aber noch ein Problem: Wenn ich ein Fenster erstelle funktioniert das auch, aber sobald ich dann das Behandeln von Events hinzufüge wird das Fenster nicht mehr angezeigt und im Vollbildmodus hängt sich gar Gnome auf sodas ich per [alt] + [strg] [f1] in eine tty-Shell wechseln und den Prozess killen muss. Habs auch schon mit dem Beispiel code auf der Tutorial-Webseite versucht, aber selbes Problem.


Anmelden zum Antworten