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:
control
ist 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 ms
die Ausführung. Normalerweise springt die Verzögerung auf0.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
FPS
Spiel ist grob87
, es spitzt sich zufällig zu (am unteren Ende)60 FPS
, jedoch hängt diese Spitze nicht mit der Freisetzung der Perle zusammen.FPS
Dies hat keine Nachteile. Dies ist sinnvoll, da der einzige Teil, der seine Komplexität erhöht, nachdem die Perle freigegeben wurde, derupdate()
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.
Antworten:
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.
quelle