Kollisionserkennung verlangsamt das Zeichnen des Bildschirms


8

Ich habe kürzlich die Spieleentwicklung als Hobby betrieben und beschlossen, dass ich ein Spiel erstellen und alles selbst rendern sollte (ohne die Verwendung einer Spiel-Engine), um die Vor- und Nachteile der Spieleentwicklung zu lernen. Dies hat sich als ziemlich kompliziert erwiesen, aber ich mache große Fortschritte. Ich bin jedoch auf ein Problem gestoßen, von dem ich glaube, dass es mit der Art und Weise zusammenhängt, wie Android-Telefone ihre Grafiken rendern, und das zu diesem Thema noch geklärt werden muss.

Das Problem

Mein Spiel enthält eine Reihe von Bällen in einer Kanone; Wenn der Benutzer auf den Bildschirm drückt, startet die Kanone die Kugeln und der Motor (den ich implementiere) übernimmt von dort aus die Aktualisierungen der Standortinformationen und die Kollisionserkennung. Bevor ich die Kollisionserkennung implementiert hatte, lief mein Spiel sehr reibungslos und reaktionsschnell. Als ich der Engine jedoch sagte, sie solle die Perle nur dann ziehen, wenn sie sich innerhalb der Grenzen befindet, und sie ansonsten von der Wand "abprallen", scheint es, dass die Engine Die Ausführung der Schleife dauert jetzt erheblich länger.

Dies wäre in Ordnung, wenn nicht die Latenz wäre, die es für die Benutzererfahrung bietet. Wenn der Bildschirm jetzt berührt wird , dauert es beispielsweise ca. 2 Sekunden, bis der Ball als sich auf dem Bildschirm bewegend angezeigt wird, und manchmal wird er überhaupt nicht angezeigt . Zuvor war die Reaktion sofort.

Wenn ich den Kollisionserkennungsbereich meiner Physik-Engine auskommentiere, nimmt sie ihr übliches Reaktionsverhalten wieder auf.

Was ich denke, verursacht dieses Verhalten

Hinweis: Ich habe diese Annahme widerrufen (siehe 'Debugging-Informationen' unten).

Ich denke, da ich keinen Frame-Limiter für mein Spiel implementiert habe und dieser so schnell rendert, wie es die Hardware zulässt, zeichnet er so viele alte Frames (vielleicht in einem Puffer?) Auf den Bildschirm, dass Es ist mit Zeichnen beschäftigt, während die Physik aktualisiert werden soll. Obwohl mein bisheriges Debuggen nicht darauf hingewiesen hat, dass dies der Fall ist, kann ich anscheinend keine andere Schlussfolgerung ziehen.

Etwas Code

Beachten Sie, dass dieser Code ziemlich verwirrend sein wird, wenn Sie nicht wissen, was alles funktioniert. Ich habe es einfach eingefügt, falls jemand etwas mit Code zu tun haben möchte. Die Variablen werden unter dem Auszug erläutert.

PhysicsEngine.updateBeadPositions (float) :

private void updateBeadPositions(float delta){

    //Update all of the beads currently on the board.
    beads = control.getBoard().getValues();

    temp_x = 0.0f;
    temp_y = 0.0f;

    //For each row...
    for(Bead[] row : beads){

        //For each bead...
        for(Bead bead : row){

            //If this bead exists...
            if(bead != null){

                temp_y = (float) (bead.getYCoordinate() * bead.getYVelocity() * delta);

                //If the coordinates are within the bounds of the game
                if(outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    bead.setYCoordinate(temp_y);
                }
            }
        }
    }

    //If the cannon Bead has been set...
    if(control.getCannon().getReleased() != null){

        //Update the cannon bead
        if(control.getCannon().getReleased().getXVelocity() == PhysicsEngine.VELOCITY_STATIC && control.getCannon().getReleased().getYVelocity() == PhysicsEngine.VELOCITY_STATIC){

            control.getCannon().getReleased().setXCoordinate(control.getCannon().getX());
            control.getCannon().getReleased().setYCoordinate(control.getCannon().getY() - Cannon.PIVOT_Y_OFFSET);
        }
        else{

            temp_x = control.getCannon().getReleased().getXCoordinate() + (control.getCannon().getReleased().getXVelocity() * delta);
            temp_y = control.getCannon().getReleased().getYCoordinate() + (control.getCannon().getReleased().getYVelocity() * delta);

            //TODO: Commented out collision checkers!

            //If the horizontal coordinates are within the bounds of the game
            if(!outwithHorizontalBounds(temp_x, control.getBoard())){

                //If the vertical coordinates are within the bounds of game
                if(!outwithVerticalBounds(temp_y, control.getBoard())){

                    //Set the X coordinate equal to the distance * the time differential (delta).       
                    control.getCannon().getReleased().setXCoordinate(temp_x);

                    //Set the X coordinate equal to the distance * the time differential (delta).
                    control.getCannon().getReleased().setYCoordinate(temp_y);
                }
                //Otherwise...
                else{

                    //Bounds off the wall in the y direction
                    control.getCannon().getReleased().setYVelocity(-1.0f * control.getCannon().getReleased().getYVelocity());
                }
            }
            //Otherwise...
            else{

                //Bounce off the wall in the x direction (flip the x velocity)
                control.getCannon().getReleased().setXVelocity(-1.0f * control.getCannon().getReleased().getXVelocity());
            }
        }
    }
}

Hier sind die Variablen definiert als:

  • controlist ein Verweis auf meinen Gamecontroller. Es packt den größten Teil des Spielcodes.

  • beads ist ein Verweis auf das 2D-Array, das die Perlen auf der Platine enthält (mit Ausnahme derjenigen, die sich bewegt).

  • delta ist die Zeitdifferenz zwischen vorherigen Aufrufen der Physik-Engine und dem aktuellen Aufruf

Weitere Erklärungen finden Sie in den Kommentaren im Code.

PhysicsEngine.outwithHorizontalBounds (float, Board) :

private boolean outwithHorizontalBounds(float x, Board board){

    //If the horizontal values are within the bounds...
    if(x > (board.getRight() - bead_radius)){

        return true;
    }

    if(x < (board.getLeft() + bead_radius)){

        return true;
    }

    //Otherwise, it is not.
    return false;
}

Die Methode outwithVerticalBounds(float, Board)hat eine äquivalente Funktionalität, jedoch in y-Richtung.


Meine Frage

Was ist mit der Kollisionserkennung, die dazu führen würde, dass das Rendern des Bildschirms so drastisch verhindert wird? Ich weiß, dass es eine sehr intensive Operation ist, aber mein Debugging hat gezeigt, dass die Physik-Updates gleichzeitig mit den Draws abgeschlossen werden.

Debugging-Informationen

Letzte Aktualisierung: 29. Januar 2013, 16:27 Uhr EST

Hier ist eine Zusammenfassung der Debugging-Informationen, die ich bisher erhalten habe. Ich werde dies im Laufe der Zeit aktualisieren:

  • Die update()Methode in meiner Engine benötigt im Durchschnitt nur .018 msdie Ausführung. Normalerweise springt die Verzögerung auf 0.020 ms, wenn ich auf den Bildschirm tippe, um die Perle freizugeben.

  • Nach dem Vergleich der Ziehungszeiten und der Spielaktualisierungen scheint es, dass ich richtig lag: Sie treten gleichzeitig auf . Das könnte also nicht das Problem sein, oder?

  • Das FPSSpiel ist grob 87, es spitzt sich zufällig zu (am unteren Ende) 60 FPS, jedoch hängt diese Spitze nicht mit der Freisetzung der Perle zusammen. FPSDies hat keine Nachteile. Dies ist sinnvoll, da der einzige Teil, der seine Komplexität erhöht, nachdem die Perle freigegeben wurde, der update()Aufruf ist. Das Zeichnen erfolgt immer noch so schnell wie möglich.

  • Nach weiteren Tests hat sich herausgestellt , dass dies nicht der Fall , dass der Bildschirm hinter der Physik hinkt. Ich habe dies mit einem einfachen booleschen Flag getestet, bei dem der Bildschirmhintergrund weiß wird, wenn ich ihn berühre, und dies geschieht sofort . Es muss also eine andere Ursache dafür geben, dass die Perle nicht zieht. Ich werde bald aktualisieren.

Ergänzende Informationen

Hier sind einige ergänzende Informationen, die Ihnen helfen sollen, meine Umstände zu verstehen:

  • Ich teste dies auf einem Google Nexus 7.

  • Es gibt einige Perlen auf der Karte, die gleichzeitig aktualisiert werden (ungefähr 30), aber nur eine davon bewegt sich.

  • Normalerweise bewegt sich die Perle, nachdem sie sich zu bewegen beginnt (nach der anfänglichen Verzögerung und wenn sie tatsächlich zieht), auf sehr sanfte Weise weiter.

  • Es ist wichtig zu beachten, dass ich andere Elemente der Benutzeroberfläche auf dem Bildschirm habe, die als Reaktion auf das Berührungsereignis aktualisiert werden. Zum Beispiel wird die in die Kanone geladene Perle zu einer neuen Perle, wenn der Bildschirm berührt wird (was bedeutet, dass sie freigegeben wurde), aber die mobile Perle wird einfach nicht gezeichnet.


Denken Sie, dass Ihr Debugging, das die Physik-Updates in Übereinstimmung mit den Draws anzeigt, möglicherweise ungenau ist? Haben Sie mit diesem Code andere Profile erstellt?
MichaelHouse

Ich habe einige umfangreiche Debugging mit Ausgaben an der Konsole (LogCat) durchgeführt, aber nichts ist komplizierter als dies. Es kann vorkommen, dass meine Debug-Anweisungen falsch sind. Ich werde sie jetzt überprüfen.
Squagem

Interessant ist auch, ob sich der FPS (Frames Per Second) beim Hinzufügen des Begrenzungsfalls ändert oder ob das Problem nicht damit zusammenhängt, wie schnell das Programm ausgeführt wird.
Qqwy

Ich habe meine Frage bearbeitet, um die von Ihnen angesprochenen Punkte zu beantworten.
Squagem

Antworten:


8

Ehrlich gesagt ist es mir ziemlich peinlich, die Lösung für mein Problem anzukündigen, da ich viele Stunden damit verbracht habe, danach zu suchen, und es war so einfach und hätte mit etwas weniger Nachlässigkeit in meinem Namen so leicht vermieden werden können. Positiv zu vermerken ist, dass ich ein paar andere Codeteile gefunden habe, die ich jetzt für eine noch bessere Leistung optimieren kann!

Die Lösung

Die Kanone, mit der die Perle abgefeuert wurde, befand sich unterhalb der unteren Grenze meines spielbaren Bereichs.

Dies war irreführend, da sich die untere Grenze meines Spielbereichs etwas über dem unteren Rand des tatsächlichen Bildschirms des Telefons befindet. Im Grunde genommen prallte die Physik-Engine sie etwa 5 Sekunden lang leicht und viert (für die menschliche Inspektion unsichtbar) zurück, bevor sie auf dem Bildschirm gerendert wurde.

Ich habe die Kanone 50 Pixel höher bewegt und sie funktioniert jetzt wie vorgesehen.


Vielen Dank für Ihre Hilfe! Ohne Ihre nachdenklichen Vorschläge wäre ich nicht hierher gekommen.


3
+1 für eine gut formatierte Frage und +1 für die Beantwortung selbst
RoughPlace

Hoppla, habe diese Frage vergessen! Danke Jungs :)
Squagem
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.