La détection de collision ralentit le dessin de l'écran

8

J'ai récemment poursuivi le développement de jeux comme passe-temps et j'ai décidé que pour apprendre les avantages et les inconvénients du développement de jeux, je devais créer un jeu et tout rendre moi-même (sans utiliser de moteur de jeu). Cela s'est révélé assez compliqué, mais je fais de grands progrès. J'ai cependant rencontré un problème qui, je pense, pourrait être lié à la façon dont les téléphones Android rendent leurs graphiques et j'aurai besoin de clarifications à ce sujet.

Le problème

Mon jeu contient une série de boules dans un canon; lorsque l'utilisateur appuie sur l'écran, le canon lance les balles et le moteur (que j'implémente) gère les mises à jour des informations de localisation et la détection des collisions à partir de là. Maintenant, avant d'avoir implémenté la détection de collision, mon jeu s'est déroulé de manière très fluide et réactive, mais lorsque j'ai dit au moteur de ne tirer le cordon que s'il se trouve dans les limites et de le "rebondir" sur le mur sinon, il semblerait que le moteur la boucle prend désormais beaucoup plus de temps à s'exécuter.

Ce serait bien, si ce n'était de la latence qu'il fournit à l'expérience utilisateur. Par exemple, lorsque l'écran est touché maintenant , il faut environ 2 secondes pour que la balle s'affiche comme se déplaçant sur l'écran, et parfois elle n'apparaît pas du tout . Auparavant, la réaction était instantanée.

De plus, lorsque je commente la partie détection de collision de mon moteur physique, elle reprend son comportement réactif habituel.

Ce que je pense est à l'origine de ce comportement

Remarque: j'ai rétracté cette hypothèse (voir «Informations de débogage» ci-dessous)

Je pense que puisque je n'ai pas de limiteur d'image implémenté pour mon jeu, et qu'il rend aussi vite que le matériel le permet, qu'il dessine tant de vieilles images (dans un tampon, peut-être?) À l'écran qui il est occupé à dessiner alors qu'il devrait mettre à jour la physique. Bien que mon débogage jusqu'à présent n'ait pas indiqué que c'est le cas, je n'arrive pas à parvenir à une autre conclusion.

Du code

Notez que ce code va être assez déroutant pour comprendre ne pas savoir ce que tout fait. Je l'ai simplement inclus au cas où quelqu'un voudrait avoir du code avec lequel travailler. Les variables sont clarifiées sous l'extrait.

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());
            }
        }
    }
}

Ici, les variables sont définies comme:

  • controlest une référence à mon contrôleur de jeu. Il regroupe la majorité du code du jeu.

  • beads est une référence au tableau 2D qui contient actuellement les billes sur la carte (à l'exception de celle qui se déplace)

  • delta est l'écart de temps entre les appels précédents au moteur physique et l'appel en cours

Voir les commentaires dans le code pour toute autre explication.

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;
}

La méthode outwithVerticalBounds(float, Board)est de fonctionnalité équivalente, mais dans la direction y.


Ma question

Qu'en est-il de la détection des collisions qui empêcherait le rendu d'écran de manière si drastique? Je sais que c'est une opération très intensive, mais mon débogage a montré que les mises à jour physiques se terminent en même temps que les tirages.

Informations de débogage

Dernière mise à jour: 29 janv. 2013 16:27 EST

Voici une agrégation des informations de débogage que j'ai obtenues jusqu'à présent. Je vais mettre à jour cela au fil du temps:

  • La update()méthode au sein de mon moteur, ne prend, en moyenne, que .018 mspour s'exécuter. Habituellement, le délai monte jusqu'à 0.020 msquand j'appuie sur l'écran pour libérer la perle.

  • Après avoir comparé les heures des tirages et les mises à jour du jeu, il semblerait que j'avais raison: elles se produisent simultanément . Ainsi, cela ne pouvait pas être le problème, non?

  • Le FPSjeu est grosso modo 87, il pointe de façon aléatoire (à l'extrémité inférieure) 60 FPS, mais cette pointe n'est pas liée à la libération de la perle. Il n'y a aucun FPSinconvénient à le faire. Cela a du sens puisque la seule partie qui augmente sa complexité après la libération du cordon est l' update()appel, le dessin se fait toujours aussi vite que possible.

  • Après de nouveaux tests, il est devenu évident que ce n'est pas le cas que l'écran est en retard sur la physique. J'ai testé cela avec un simple drapeau booléen dans lequel l'arrière-plan de l'écran devenait blanc lorsque je le touchais, et cela se produit immédiatement . Ainsi, il doit y avoir une autre cause pour que le cordon ne se dessine pas. Je mettrai à jour bientôt.

Information supplémentaire

Voici quelques informations supplémentaires qui devraient vous aider à comprendre ma situation:

  • Je teste cela sur un Google Nexus 7.

  • Il y a pas mal de perles sur la carte qui sont mises à jour en même temps (environ 30), mais une seule d'entre elles bouge.

  • Habituellement, après que le cordon commence à se déplacer (après le délai initial et s'il tire réellement), il continue à se déplacer de manière très fluide.

  • Il est important de noter que j'ai d'autres éléments d'interface utilisateur à l'écran qui se mettent à jour en réaction à l'événement tactile. Par exemple, la perle chargée dans le canon devient une nouvelle perle lorsque l'écran est touché (signifiant qu'elle a été libérée), mais la perle mobile n'est tout simplement pas tirée.

Squagem
la source
Pensez-vous que votre débogage qui montre les mises à jour de la physique en ligne avec les tirages pourrait être inexact? Avez-vous effectué un autre profilage avec ce code?
MichaelHouse
J'ai fait un débogage approfondi en utilisant des sorties vers la console (LogCat), mais rien de plus compliqué que cela. Il se peut que mes instructions de débogage soient incorrectes, je vais les examiner maintenant.
Squagem
Il est également intéressant de savoir si le FPS (Frames Per Second) change lors de l'ajout du cas de délimitation, ou que le problème n'est pas lié à la vitesse d'exécution du programme.
Qqwy
J'ai modifié ma question pour répondre aux points que vous avez soulevés.
Squagem

Réponses:

8

Franchement, je suis plutôt gêné d'annoncer la solution à mon problème car j'ai passé de nombreuses heures à le chercher, et c'était si simple et aurait pu être évité si facilement avec un peu moins de négligence de ma part. Du bon côté, j'ai fini par trouver quelques autres morceaux de code que je peux maintenant optimiser pour des performances encore meilleures!

La solution

Le canon qui lançait la perle était en dessous de la limite inférieure de ma zone jouable.

C'était trompeur parce que la limite inférieure de ma zone de jeu est un peu au-dessus du bas de l'écran réel du téléphone. Donc, fondamentalement, le moteur physique le faisait rebondir et le quatrième très légèrement (invisible à l'inspection humaine) pendant environ 5 secondes avant d'être affiché à l'écran.

J'ai déplacé le canon de 50 pixels plus haut et cela fonctionne comme prévu maintenant.


Merci à tous pour votre aide! Je ne serais pas arrivé ici sans vos suggestions réfléchies.

Squagem
la source
3
+1 pour une question bien formatée et +1 pour y répondre vous
RoughPlace
Oups, j'ai oublié cette question! Merci les gars :)
Squagem