2009-07-29 8 views
2

Je développe un jeu 2D simple en Java, tout fonctionne bien. Pour trouver le FPS actualiser/redessiner/mettre à jour, j'ai utilisé currentTimeMillis pour trouver la différence.currentTimeMillis de Java renvoie la (les) valeur (s) négative (s)

Le problème est que currentTimeMillis retourne parfois des valeurs négatives, et la Thread.sleep jetteront exception (java.lang.IllegalArgumentException: délai d'attente est négatif)

Ce que je faisais était de mettre un certain temps dans mon jeu et while currentTimeMillis < = -1 vérifiez à nouveau jusqu'à ce qu'il soit terminé, puis dormez.

Exemple de code

:

private void gameLoop(){ 
    // Find FPS 
    long FPS = 40; 
    long beginTime = System.currentTimeMillis(); 
    while(beginTime < -1){ 
     beginTime = System.currentTimeMillis(); 
    } 
    while(!done){ 
     // Sleep 
     try{ 
      beginTime += FPS; 
      long currTime = System.currentTimeMillis(); 
      while(currTime < -1){ 
       currTime = System.currentTimeMillis(); 
      } 
      difference = (beginTime - currTime); 
          // Should be (currTime - beginTime) 

      Thread.sleep(difference); 
     }catch (Exception e){ 
      e.printStackTrace(); 
     } 
     // RENDER GAME 
     renderGame(); 
    } 
    JOptionPane.showMessageDialog(null, "Game Over\nYou Died."); 
    System.exit(0); 
}// end gameLoop() 

Quand le jeu commence, cela fonctionne très bien, mais parfois je reçois encore l'exception. Y a-t-il un meilleur moyen? Je pense toujours que c'est étrange que ça retourne une valeur négative.

+0

Je l'ai beaucoup utilisé et je ne l'ai jamais rencontré. Sur quelle plateforme vous êtes? par exemple. Version OS et JVM et fournisseur. –

+0

Mac OS X Leopard, il donne parfois des valeurs négatives. Cela ne se produit pas dans Windows 7. – Millad

+0

vous testez "time <-1" et non "<= -1" ... mais j'ai toujours du mal à croire qu'il retourne des nombres négatifs ... –

Répondre

11

Le vrai problème n'est-il pas que beginTime-currTime est négatif?

difference = (beginTime - currTime); 
Thread.sleep(difference); 

Je note que vous ajoutez FPS (40) à beginTime. Mais si currentTime est supérieur à beginTime+FPS, vous allez avoir des problèmes.

Si vous essayez de planifier quelque chose à intervalles réguliers (ce que je pense que vous êtes), consultez Timer, ce qui vous permettra de le faire plus simplement/de manière fiable.

+0

Ah, oui bien sûr! Mais maintenant, le jeu est bien au-dessus de 200 FPS. Cela va jusqu'à 5000+. – Millad

1

Si currentTimeMillis retourne une valeur négative, alors quelque chose ne va pas avec votre machine virtuelle Java/OS, ou de la mémoire corrompue etc.

+2

Cela ou vous utilisez un ordinateur avec une JVM avant 1970. –

5

IMHO l'instruction suivante:

difference = (beginTime - currTime); 

devrait être:

difference = (currTime - beginTime); 

currTime est toujours supérieur à beginTime, donc la différence est toujours négative ou au moins égale à 0.

0

pour le calcul des valeurs fps je vous recommandons d'utiliser

System.nanoTime() 

il est beaucoup plus précis. l'inconvénient est qu'il ne vous donne que des valeurs réelles, ce qui n'a pas d'importance du tout lorsque vous faites des calculs fps.

1 milliseconde se compose de 1000000 nanosecondes.

La résolution de currentTimeMillis est généralement de seulement 16 ms.

+0

C'est ce que j'ai utilisé, mais le jeu est en retard: long count1 = System.nanoTime(); long count2 = System.nanoTime(); long diff = (compte2 - compte1); // en nanosecondes Avez-vous un échantillon? – Millad

+0

Cela dépend. nanoTime offre une précision plus élevée mais peut être moins fiable. C'est ce que j'ai trouvé: http://www.techper.net/2008/08/10/systemcurrenttimemillis-systemnanotime-and-their-resolution/ –

1

Il y a un problème conceptuel dans votre code: à un moment donné, vous ajoutez un taux de framerate (Frames par seconde, FPS) à un instant. Ou vous voulez vraiment ajouter 40 millisecondes, mais alors vous ne devriez pas nommer la variable FPS, car cela conduira à des malentendus.

Si l'on suppose FPS est vraiment trames par seconde, vous devez utiliser une autre valeur pour votre calcul:

long milliSecondsPerFrame = 1000/FPS; 

System.getCurrentTimeInMillis() ne reviendra plus des valeurs négatives (ou du moins pas avant août 17, 08 : 12: 55 - en l'an 292.278.944;)) *)

Ainsi, vous pouvez supprimer en toute sécurité les vérifications de currentTimeMillis() négatif pour les utilisations en temps réel.

Le nom de la variable beginTime entraîne un autre malentendu. Ce n'est pas l'horodatage d'une sorte de début. En fait, c'est le moment où vous attendez la prochaine mise à jour de l'image. Donc vous devriez le nommer différemment, peut-être 'nextFrameUpdateTime'. Cela indiquerait clairement que le calcul de la différence est en fait

difference = nextFrameUpdateTime - currentTime; 

est correcte et devrait retourner une valeur positive - tant que votre sûr, que vous ne manquez pas une mise à jour du cadre («vous êtes trop en retard'). Et je pense que c'est le problème: une différence négative indique simplement que la méthode renderGame() a pris plus de temps que la valeur secondPerFrame, donc à un certain moment pendant votre jeu vous avez manqué une mise à jour, le currentTime est plus grand que nextFrameUpdateTime et vous avez l'exception.

*) Testé avec

Date date = new Date(Long.MAX_VALUE); 
0

Il semble que cela a mieux fonctionné.

private void gameLoop(){ 
    // Find FPS 
    long nextFrameUpdateTime = System.currentTimeMillis(); 
    long milliSecondsPerFrame = 1000/60; 
    while(!done){ 
     // Sleep 
     try{ 
      long currentTime = System.currentTimeMillis(); 
      currentTime += milliSecondsPerFrame; 

      difference = (currentTime - nextFrameUpdateTime); 
      Thread.sleep(difference); 

     }catch (Exception e){ e.printStackTrace(); } 

     nextFrameUpdateTime = System.currentTimeMillis(); 
     renderGame(); 

    } // end While 
    JOptionPane.showMessageDialog(null, "Game Over\nYou Died."); 
    System.exit(0); 
}// end gameLoop() 

Nous vous remercions de votre aide à tous.

+0

Ce n'est pas correct, vous ne tenez pas compte du temps qu'il faut pour appeler renderGame. En fait, vous ajoutez ce temps à votre sommeil.Donc, après chaque image, vous dormez réellement pour combien de temps il a fallu appeler renderGame, plus milliSecondsPerFrame. – CodeGoat

+0

Je n'arrive pas à comprendre comment trouver le temps nécessaire pour appeler renderGame. Voulez-vous s'il vous plaît expliquer plus. Je me sens complètement perdu. – Millad

+0

J'ai posté une réponse séparée avec du code. – CodeGoat

-1

Si vous essayez de fixer un taux de trame spécifique, voici ce que ça devrait ressembler à:

long msPerFrame = 1000/60; 
long now = System.currentTimeMillis(); 
long next = now + msPerFrame; 
while(!done) 
{ 
    now = System.currentTimeMillis(); 
    if(now >= next) 
    { 
     next = now + msPerFrame; 
     renderGame(); 
    } 
    else 
    { 
     // no chance of negative, we know next > now 
     long diff = next - now; 
     try { Thread.sleep(diff); } catch(InterruptedException ex) { } 
    } 
} 

Ceci est juste un « assez proche » boucle de jeu à taux fixe, et devrait vous donner l'idée de base . Je dis assez proche parce que si renderGame() prend plus de temps que msPerFrame, le jeu va ralentir (comme les jeux NES quand il y avait trop à l'écran). Il existe de meilleurs moyens d'exécuter une boucle de jeu, comme utiliser un mouvement indépendant de la fréquence d'images ou utiliser le saut d'image pour gérer les ralentissements, mais c'est une bonne façon de le faire pour une première partie.

+0

Merci, cela fonctionne mieux. Oui c'est mon premier jeu, et je ne suis pas un développeur de jeux. Ca marche très bien, même si le fps saute ce que je suppose normal. – Millad

+0

Essayez de changer le sommeil pour juste dormir (1) au lieu de la diff. Il n'y a aucune garantie que le sommeil se réveille dans le temps que vous voulez, ce qui pourrait expliquer pourquoi il saute. L'utilisation de sleep (1) ne fera qu'abandonner le reste de la tranche de temps du thread. – CodeGoat

+0

Très bien, mais le jeu va courir très vite. C'est en fait bon avec la variable diff en sommeil. – Millad

Questions connexes