Boucle de jeu lisse Android

J'ai des problèmes avec un défilement sans heurts dans OpenGL (test sur SGS2 et ACE)
J'ai créé des applications simples: seule la vitesse fixe de défilement horizontal des images, ou une seule image (joueur) en mouvement par accélérateur, mais son mouvement n'est pas lisse 🙁
J'ai essayé beaucoup de code, mais pas de satisfaction …

D'abord, j'ai essayé de travailler avec GLSurfaceView.RENDERMODE_CONTINUOUSLY et j'ai mis tout le code sur onDrawFrame:

  • Passage entre Android Navigation Drawer image et Up caret lors de l'utilisation de fragments
  • Problèmes d'installation du plugin ADT Eclipse 3.7 Ubuntu 11.10
  • Où est le code appelé lorsque vous appelez getApplicationContext ()?
  • L'animation spinner personnalisée n'est pas assez lisse: framesCount et frameDuration error
  • Eclipse LogCat est généré par OpenGLRenderer
  • EXCEPTION DE NIVEAU SUPÉRIEUR INEXPECTÉE: com.android.dex.DexException: plusieurs fichiers dex définissent
  • public void onDrawFrame(GL10 gl) { updateGame(gl, 0.017f); drawGame(gl); } 

    C'est le plus simple et absolument lisse! – mais dépend de la vitesse du matériel (= inutile)

      public void onDrawFrame(GL10 gl) { frameTime = SystemClock.elapsedRealtime(); elapsedTime = (frameTime - lastTime) / 1000; updateGame(gl, elapsedTime); drawGame(gl); lastTime = frameTime; } 

    C'est le meilleur de tous, mais ce n'est pas aussi lisse que le précédent, parfois flick

    Deuxièmement, j'ai essayé GLSurfaceView.RENDERMODE_WHEN_DIRTY , dans onDrawFrame, je n'ai que des objets de dessin et ce code dans un thread distinct:

      while (true) { updateGame(renderer, 0.017f); mGLSurfaceView.requestRender(); next_game_tick += SKIP_TICKS; sleep_time = next_game_tick - System.currentTimeMillis(); if (sleep_time >= 0) { try { Thread.sleep(sleep_time); } catch (Exception e) {} } else { Log.d("running behind: ", String.valueOf(sleep_time)); } } 

    Ce n'est pas lisse et ce n'est pas un problème avec "courir derrière"

    Mon objectif est le mouvement de l'image en douceur comme dans le premier exemple de code ci-dessus.

    L'erreur possible est ailleurs, alors je regarde. S'il vous plaît, quelqu'un peut-il m'aider?
    Est-il préférable d'utiliser RENDERMODE_WHEN_DIRTY ou RENDERMODE_CONTINUEMENT?

    Je vous remercie.

    One Solution collect form web for “Boucle de jeu lisse Android”

    Je me suis battu avec exactement le même problème pendant plusieurs jours. La boucle s'allume sans aucune référence de temps de l'Android, mais dès que cela inclut tout type de «synchronisation temporelle», les facteurs externes hors du contrôle de développement Android entraînent de graves discontinuités pour le résultat final.

    Fondamentalement, ces facteurs sont les suivants:

    • EglSwapInterval n'est pas implémenté dans Android, il est donc difficile de connaître le moment où le matériel expose le tirage final de l'écran (synchronisation de l'écran du matériel)
    • Thread.sleep n'est pas précis. Le fil peut dormir plus ou moins que demandé.
    • SystemClock.uptimeMillis () System.nanoTime (), System.currentTimeMillis () et d'autres mesures liées au chronométrage ne sont pas précis (c'est précis).

    Le problème est indépendant de la technologie de dessin (dessin, openGL 1.0 / 1.1 et 2.0) et la méthode de la boucle de jeu (pas de temps fixe, interpolation, pas de temps variable). Comme vous, j'essayais de Thread.sleep, des interpolations folles, des minuteries, etc. Peu importe ce que vous ferez, nous n'avons pas le contrôle de ces facteurs.

    Selon plusieurs questions et réponses sur ce site, les règles de base pour produire des animations continues en douceur sont les suivantes:

    • Réduisez au minimum le GC en supprimant toutes les demandes de mémoire dynamique.
    • Rendez les cadres aussi rapidement que le matériel peut les traiter (40 à 60fps est correct dans la plupart des périphériques Android).
    • Utilisez des étapes de temps fixes avec des étapes d'interpolation ou de temps variables.
    • Optimisez la physique de mise à jour et tracez des routines à exécuter en temps constant relatif sans variance élevée des pics.

    Bien sûr, vous avez fait beaucoup de travaux antérieurs avant de publier cette question en optimisant votre updateGame () et drawGame () (sans GC appréciable et temps d'exécution constant relatif) afin d'obtenir une animation en douceur dans votre boucle principale comme vous l'avez mentionné: " Simple et absolument lisse ".

    Votre cas particulier avec stepTime variable et pas d'exigences spéciales pour être en parfaite synchronisation avec les événements realTime (comme la musique), la solution est simple: "lisser la variable Time Time".
    La solution fonctionne avec d'autres systèmes de boucles de jeux (temps de temps fixe avec rendu variable) et facilite le port du concept (lisse la quantité de déplacement produite par le updateGame et l'horloge temps réel sur plusieurs images).

      // avoid GC in your threads. declare nonprimitive variables out of onDraw float smoothedDeltaRealTime_ms=17.5f; // initial value, Optionally you can save the new computed value (will change with each hardware) in Preferences to optimize the first drawing frames float movAverageDeltaTime_ms=smoothedDeltaRealTime_ms; // mov Average start with default value long lastRealTimeMeasurement_ms; // temporal storage for last time measurement // smooth constant elements to play with static final float movAveragePeriod=40; // #frames involved in average calc (suggested values 5-100) static final float smoothFactor=0.1f; // adjusting ratio (suggested values 0.01-0.5) // sample with opengl. Works with canvas drawing: public void OnDraw(Canvas c) public void onDrawFrame(GL10 gl){ updateGame(gl, smoothedDeltaRealTime_ms); // divide 1000 if your UpdateGame routine is waiting seconds instead mili-seconds. drawGame(gl); // Moving average calc long currTimePick_ms=SystemClock.uptimeMillis(); float realTimeElapsed_ms; if (lastRealTimeMeasurement_ms>0){ realTimeElapsed_ms=(currTimePick_ms - lastRealTimeMeasurement_ms); } else { realTimeElapsed_ms=smoothedDeltaRealTime_ms; // just the first time } movAverageDeltaTime_ms=(realTimeElapsed_ms + movAverageDeltaTime_ms*(movAveragePeriod-1))/movAveragePeriod; // Calc a better aproximation for smooth stepTime smoothedDeltaRealTime_ms=smoothedDeltaRealTime_ms +(movAverageDeltaTime_ms - smoothedDeltaRealTime_ms)* smoothFactor; lastRealTimeMeasurement_ms=currTimePick_ms; } // Optional: check if the smoothedDeltaRealTIme_ms is too different from original and save it in Permanent preferences for further use. 

    Pour un plan de temps temporel fixe, un updateGame intermédié peut être implémenté pour améliorer les résultats:

     float totalVirtualRealTime_ms=0; float speedAdjustments_ms=0; // to introduce a virtual Time for the animation (reduce or increase animation speed) float totalAnimationTime_ms=0; float fixedStepAnimation_ms=20; // 20ms for a 50FPS descriptive animation int currVirtualAnimationFrame=0; // useful if the updateGameFixedStep routine ask for a frame number private void updateGame(){ totalVirtualRealTime_ms+=smoothedDeltaRealTime_ms + speedAdjustments_ms; while (totalVirtualRealTime_ms> totalAnimationTime_ms){ totalAnimationTime_ms+=fixedStepAnimation_ms; currVirtualAnimationFrame++; // original updateGame with fixed step updateGameFixedStep(currVirtualAnimationFrame); } float interpolationRatio=(totalAnimationTime_ms-totalVirtualRealTime_ms)/fixedStepAnimation_ms; Interpolation(interpolationRatio); } 

    Testé avec toile et dessin openGlES10 avec les périphériques suivants: SG SII (57 FPS), SG Note (57 FPS), onglet SG (60 FPS), émulateur lent sans fil Android 2.3 (43 FPS) fonctionnant sous Windows XP (8 FPS). La plate-forme de test dessine environ 45 objets + 1 arrière-plan énorme (texture de l'image source 70MP) se déplaçant le long d'un chemin spécifié dans les paramètres physiques réels (km / h et G), sans pointes ni flick entre plusieurs périphériques (puits, 8 FPS sur l'émulateur Ne semble pas bien, mais son débit à vitesse constante comme prévu)

    Vérifiez Les graphiques pour savoir comment android rapporte l'heure. Certaines fois, Android rapporte un grand temps de delta et juste la boucle suivante, elle est petite que la moyenne, ce qui signifie un décalage sur la lecture de la valeur RealTime.

    Entrez la description de l'image ici

    Avec plus de détails: Entrez la description de l'image ici

    Comment limiter l'encrychage lors de l'utilisation de GLSurfaceView d'Android.RENDERMODE_CONTINUEMENT?

    System.currentTimeMillis vs System.nanoTime

    Est-ce que la méthode System.currentTimeMillis () renvoie vraiment l'heure actuelle?

    coAndroid est un fan Android de Google, tout sur les téléphones Android, Android Wear, Android Dev et Android Games Apps.