android boucle de jeu vs la mise à jour dans le thread de rendu

Je suis en train de faire un jeu android et je suis en train de ne pas obtenir de la performance, je voudrais. J'ai une boucle de jeu dans son propre thread qui met à jour la position d'un objet. Le thread de rendu la traversée de ces objets et de les dessiner. Le comportement actuel est ce qui semble être agitée/mouvement irrégulier. Ce que je ne peux pas expliquer, c'est qu'avant j'ai mis la mise à jour de la logique dans son propre thread, je l'ai eu dans le onDrawFrame méthode, juste avant le gl appels. Dans ce cas, l'animation était parfaitement lisse, elle ne devient saccadée/irrégulier spécifiquement lorsque j'essaie de limiter ma mise à jour en boucle via le Fil de discussion.sommeil. Même quand j'permettre la mise à jour du thread pour aller berserk (pas de sommeil), l'animation est fluide, uniquement lorsque le Thread.le sommeil participe-t-il sur la qualité de l'animation.

J'ai créé un squelette de projet pour voir si je pouvais recréer la question, voici la mise à jour de boucle et de la onDrawFrame méthode dans le moteur de rendu:
mise à Jour de Boucle

    @Override
public void run() 
{
    while(gameOn) 
    {
        long currentRun = SystemClock.uptimeMillis();
        if(lastRun == 0)
        {
            lastRun = currentRun - 16;
        }
        long delta = currentRun - lastRun;
        lastRun = currentRun;

        posY += moveY*delta/20.0;

        GlobalObjects.ypos = posY;

        long rightNow = SystemClock.uptimeMillis();
        if(rightNow - currentRun < 16)
        {
            try {
                Thread.sleep(16 - (rightNow - currentRun));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Et voici mon onDrawFrame méthode:

        @Override
public void onDrawFrame(GL10 gl) {
    gl.glClearColor(1f, 1f, 0, 0);
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
            GL10.GL_DEPTH_BUFFER_BIT);

    gl.glLoadIdentity();

    gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
    gl.glTranslatef(transX, GlobalObjects.ypos, transZ);
    //gl.glRotatef(45, 0, 0, 1);
    //gl.glColor4f(0, 1, 0, 0);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

    gl.glVertexPointer(3,  GL10.GL_FLOAT, 0, vertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, uvBuffer);

    gl.glDrawElements(GL10.GL_TRIANGLES, drawOrder.length,
              GL10.GL_UNSIGNED_SHORT, indiceBuffer);

    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
}

J'ai regardé à travers réplique de l'île de la source et il fait de sa logique de mise à jour dans un thread séparé, ainsi que de la limitation des avec Fil.le sommeil, mais son jeu est très lisse. Quelqu'un a une idée ou quelqu'un a vécu ce que je parle?

---EDIT: 1/25/13---

J'ai eu le temps de penser et d'avoir lissé ce moteur de jeu considérablement. Comment j'ai réussi ce pourrait être blasphématoire ou insultant pour les programmeurs, n'hésitez pas à corriger l'une quelconque de ces idées.

L'idée de base est de garder un motif de mise à jour, de dessiner... mise à jour, de dessiner... tout en gardant le temps delta relativement de la même façon (souvent hors de votre contrôle).
Mon premier cours de l'action était de synchroniser mon convertisseur de telle manière qu'il fit seulement après avoir été informé qu'il était autorisé à le faire. Cela ressemble à quelque chose comme ceci:

public void onDrawFrame(GL10 gl10) {
        synchronized(drawLock)
    {
        while(!GlobalGameObjects.getInstance().isUpdateHappened())
        {
            try
            {
                Log.d("test1", "draw locking");
                drawLock.wait();
            } 
            catch (InterruptedException e) 
            {
                e.printStackTrace();
            }
        }
    }

Quand j'ai fini ma logique de mise à jour, j'appelle drawLock.notify(), libérant le thread de rendu à dessiner ce que je viens de mettre à jour. Le but de cette opération est d'aider à établir le schéma de mise à jour, de dessiner... mise à jour, de dessiner... etc.

Une fois que j'ai mis en place, il est beaucoup plus lisse, bien que j'avais toujours des sauts occasionnels dans le mouvement. Après quelques tests, j'ai vu que j'avais plusieurs mises à jour ont lieu entre les appels de ondrawFrame. C'était à l'origine une image pour montrer le résultat de deux (ou plus) des mises à jour, un plus grand saut que la normale.

Ce que j'ai fait pour résoudre ce a été de limiter le temps delta à une certaine valeur, dire 18ms, entre deux onDrawFrame appels et de stocker le plus de temps dans un reste. Ce reste sera distribué aux temps de deltas au cours de la prochaine quelques mises à jour si elles pouvaient gérer. Cette idée empêche tous soudaine de longs sauts, essentiellement le lissage d'un temps de spike sur plusieurs images. En faisant cela m'a donné d'excellents résultats.

L'inconvénient de cette approche est que pour un peu de temps, la position des objets ne seront pas précises avec le temps, et sera en fait accélérer pour rattraper cette différence. Mais c'est plus lisse et le changement de vitesse n'est pas très visible.

Enfin, j'ai décidé de réécrire mon moteur avec les deux idées ci-dessus à l'esprit, plutôt que de rafistoler le moteur que j'avais faites à l'origine. J'ai fait quelques optimisations pour la synchronisation de thread que peut-être quelqu'un pourrait commenter.

Mes threads en cours d'interagir comme ceci:

-mise à Jour du thread mises à jour du tampon courant (double système de tampon afin de mettre à jour et de tirer en même temps) et ensuite donner ce tampon pour le moteur de rendu si l'image précédente a été tirée.

-Si l'image précédente n'a pas encore dessiner, ou est le dessin, la mise à jour du thread attendre jusqu'à ce que le thread de rendu notifie qu'il a dessiné.

-thread de Rendu attend jusqu'à ce que notifié par mise à jour du thread une mise à jour a eu lieu.

-Lorsque le thread de rendu dessine, il définit une "dernière variable" pour indiquer laquelle des deux buffers, ce dernier a attiré et informe également sur la mise à jour thread si elle a été en attente sur le précédent de la mémoire tampon pour être tiré.

Peut-être un peu compliquée, mais ce qui est fait est permettant pour que les avantages du multithreading, en ce qu'elle peut effectuer la mise à jour de l'image n, tandis que l'image n-1 est le dessin, tout en empêchant la mise à jour de plusieurs itérations par image si le moteur de rendu est de prendre beaucoup de temps. Pour expliquer plus en détail, ce multiple-scénario de mise à jour est assurée par la mise à jour de filetage de verrouillage s'il détecte que le lastDrawn tampon est égale à celle qui a été juste mis à jour. Si elles sont égales, ce qui indique à la mise à jour du thread que le cadre avant n'a pas encore été établi.

Jusqu'à présent, j'obtiens de bons résultats. Laissez-moi savoir si quelqu'un a des commentaires, serait heureux d'entendre vos pensées sur quelque chose que je suis en train de faire, de bonne ou de mauvaise.

Grâce

InformationsquelleAutor user1578101 | 2012-12-29