AS3: Quelle est la précision de la getTimer() la méthode et la classe Timer?
Je suis en train de faire un jeu (un shmup) et j'ai commencé à remettre en question l'exactitude des compteurs dans ActionScript. Bien sûr, ils sont assez précis quand vous voulez à la fois, les choses de l'ordre de quelques secondes ou dixièmes de s., mais il semble fonctionner assez mal lorsque vous obtenir plus fine de la plages de. Il est donc assez difficile de faire des choses comme avoir un vaisseau spatial de tir d'une centaine de lasers par seconde.
Dans l'exemple suivant, j'ai testé combien de temps (en moyenne), les intervalles entre 1000 minuterie tiques destinés à 30ms. Encore une fois, les résultats sont ~35-36 ms. En diminuant le temps, j'ai trouvé le sol de la minuterie de retard à ~16-17ms. Cela me donne un max de fps de ~60, ce qui est très visuel, mais aussi les moyens, je ne peux pas tirer plus de 60 lasers par seconde :-(. J'ai couru ce test quelques fois au 100 et 1000 boucles, mais pour le 30ms test et la 1ms tester les résultats n'ont pas changé. J'ai l'impression d'un champ de texte à la fin parce que l'aide de la fonction trace() et à lancer le fichier swf dans le mode de débogage semble affecter négativement le test. Donc, ce que je me pose, c'est:
- Est ce test, un décent mesure de la classe Timer, ou mes résultats sont douteux?
- Ces résultats de changer de façon spectaculaire sur d'autres machines?
Je comprends cela dépend de la getTimer() la méthode la précision, mais les discussions que j'ai trouver sur ce sujet généralement le centre autour de getTimer()'s précision sur des intervalles plus grands.
paquet { import flash.d'affichage.Sprite; import flash.les événements.TimerEvent; import flash.texte.TextField; import flash.utils.getTimer; import flash.utils.Minuterie;
public class testTimerClass extends Sprite
{
private var testTimer:Timer = new Timer(30, 1000);
private var testTimes:Array = new Array();
private var testSum:int = 0;
private var testAvg:Number;
private var lastTime:int;
private var thisTime:int;
public function testTimerClass()
{
testTimer.addEventListener(TimerEvent.TIMER, step);
testTimer.addEventListener(TimerEvent.TIMER_COMPLETE, printResults);
lastTime = getTimer();
testTimer.start();
}
private function step(event:TimerEvent):void
{
thisTime = getTimer();
testTimes.push(thisTime - lastTime);
lastTime = thisTime;
}
private function printResults(event:TimerEvent):void
{
while (testTimes.length > 0)
{
testSum += testTimes.pop();
}
testAvg = testSum / Number(testTimer.repeatCount);
var txtTestResults:TextField = new TextField();
txtTestResults.text = testAvg.toString();
this.addChild(txtTestResults);
}
}
}
Je suppose que la meilleure route à prendre serait de simplement dessiner plusieurs lasers dans le même cadre avec différentes positions et éviter d'avoir plus d'un objet Timer.
edit: j'ai utilisé de la scène.frameRate pour modifier le rendu de frameRate et a couru le test sur plusieurs fréquences d'images, mais il n'y a pas eu de changement.
OriginalL'auteur jorelli | 2009-06-18
Vous devez vous connecter pour publier un commentaire.
Tinic Uro (Flash Player ingénieur) a écrit un blog intéressant post sur ce problème il y a quelques temps.
Vous savez, je n'ai pas vraiment apprécier ce qu'il parlait, jusqu'à ce que j'ai couru mon test dans un navigateur vs dans la version autonome de Flash player. La raison c'est qu'il parle tout à propos de taux de trame, et dans mon esprit je pensais "oh, c'est super et tout, mais je ne parle pas d'une cadence réelle, je parle de la vieille". Je n'ai pas pensé dans ma tête que, même si elles sont indépendantes l'une de l'autre, ils sont encore tous les deux de prendre leurs signaux de synchronisation de l'environnement, de sorte qu'ils ont la même fréquence de plafond.
C'est exactement ça.
OriginalL'auteur Luke
Intead de l'utilisation de la classe timer à tous, je voudrais mettre mon code de mise à jour et enterframe eventlistener.
Ensuite utiliser getTimer(), afin de savoir combien de temps a passé depuis la dernière mise à jour, et puis un peu de peu de maths pour calculer le mouvement, laser "frai", etc. De cette façon, le jeu doit exécuter la même, peu importe si vous arriver à 60 im /s ou 10 images par seconde.
Cela empêche également bizarre le comportement de jeu si le FPS chute temporaire, ou si le jeu est en cours d'exécution sur une machine lente.
Pour la plupart, le calcul est assez simple, et quand il n'est pas, habituellement, vous pouvez "couper les coins ronds" et toujours obtenir un résultat assez bon pour un jeu.
Pour la simple mouvement, vous pouvez simplement multiplier le mouvement de décalage avec le temps depuis la dernière mise à jour. Pour l'accélération, vous avez besoin d'une equation du second degré, mais pourrait simplifier être multipliant à nouveau.
En réponse à jorelli commentaire ci-dessous:
La détection de collision problème peut être résolu par un meilleur code, qui n'est pas seulement de vérifier l'état actuel, mais aussi ce qui s'est passé entre l'état précédent et l'actuel.
Je n'ai jamais eu de problèmes avec le clavier. Peut-être que vous devriez essayer cette chouette petite classe:
http://www.bigroom.co.uk/blog/polling-the-keyboard-in-actionscript-3
OriginalL'auteur Jacob Poul Richardt
J'ai juste essayé de l'exécution de votre code d'exemple, exactement comme-est, sauf comme un script d'image, et où je suis assis Minuterie fonctionne exactement comme vous le souhaitez. Avec un 30ms de la minuterie, la moyenne est livré sur 33-34, et avec un 3ms minuterie il s'agit autour de 3.4 ou 3.5. Avec un pas de 1 ms minuterie-je obtenir entre 1,4 et 1,6 plus d'un millier d'essais. Il fonctionne de cette manière dans le Flash dans le navigateur.
Ainsi que de l'exactitude, de voir Tinic du blog dans la réponse de Luc. Mais pour la limite supérieure de la fréquence, si vous avez des événements pas plus vite que 16ms à part avec seulement l'exemple de code que vous avez posté, soit quelque chose de bizarre, ou peut-être que c'est la limite supérieure de la vitesse de votre navigateur est de donner Flash, synchronisation des messages. Si vous êtes l'obtention de ces résultats dans votre jeu, je pense que vous avez simplement du code synchrone que le blocage des événements de la minuterie.
Une chose de plus - je sais que c'est pas ce que vous avez demandé, mais il faudrait vraiment être plus sage de traiter votre jeu de logique dans un ENTER_FRAME gestionnaire. Il n'importe pas de savoir si le code de frayer les lasers s'exécute toutes les 30ms ou tous les 3ms, l'écran ne reçoit redessiné une fois par image (sauf si vous êtes forçant à se mettre à jour plus souvent, vous ne devriez probablement pas). Donc, tout ce qui se passe entre l'écran se rafraîchit est juste une surcharge qui abaisse l'ensemble de votre framerate, car avec un peu d'ingéniosité, il devrait être possible d'atteindre les mêmes résultats que vous obtiendrez à partir d'un minuteur qui a exécuté plus fréquemment. Par exemple, au lieu de pondre un laser de tous les 3ms, vous pouvait pondre 10 lasers de toutes les 30ms, et se déplacer à chacun une certaine distance le long de sa trajectoire de vol, comme s'il avait été créé 3 ou 6 ou 9ms plus tôt.
Un autre moyen naturel pour exécuter votre logique d'images des événements serait de faire une boucle de jeu que "théoriquement" fonctionne tous les T millisecondes. Puis, dans votre
ENTER_FRAME
gestionnaire, tout simplement effectuer une itération de cette boucle F/T fois, où F est le nombre de ms qui se sont écoulées depuis la dernière image de l'événement. Donc si vous voulez que le jeu théoriquement mise à jour toutes les 5 ms, et vous souhaitez que l'écran de mise à jour à 30FPS, il vous suffit de publier à 30FPS, et dans votreENTER_FRAME
gestionnaire vous souhaitez appeler votre jeu principal de la boucle de 5 à 7 fois de suite, en fonction de combien de temps il avait été depuis la dernière image. À l'écran, ce qui vous donnera le même résultat que si vous aviez utilisé un 5ms événement de minuterie, et il sera, renoncer à une grande partie de la surcharge.Oui, c'est pas vraiment Flash de la faute, mais c'est encore quelque chose que vous avez à vivre avec. Comme pour les images, tu fais de la bonne manière si loin que ça va, mais je pense vraiment que vous obtiendrez de meilleures performances en laissant le rendu de Flash. Même si toutes choses étaient égales par ailleurs, c'est toujours une question de faire le compositing en AS3 vs de le faire en C, après tout. (YMMV bien sûr, le profilage > de la théorie...)
L'exécution de plusieurs cycles de mise à jour semble tellement évident maintenant! Merci, je suis de 120 lasers par seconde facilement maintenant. Cela devrait être suffisant lasers pour le moment 😛
OriginalL'auteur fenomas
BitmapData.faites défiler et BitmapData.copyPixels sont le moyen le plus rapide pour le rendu en flash pour l'instant, sauf sur quelques systèmes, à l'aide de clips d'animations avec l'accélération gpu est légèrement plus rapide. Chaque quad est rendu en tant que distincte de la texture OpenGL, donc ce n'est pas ce que vous attendez d'un ordinaire de l'accélération GPU de l'application. Je sais, parce que je profilé deux manières, à mon jeu. Une chose que vous pouvez faire pour améliorer le temps de réponse est d'appeler votre jeu à jour à partir de l'entrée des gestionnaires d'événements. De cette façon, vous entendez correctement chronométré sons, même lorsque votre jeu est framerate est plus faible, et l'application va se sentir plus réactif.
OriginalL'auteur Tim Kerchmar
Je dirais que vous êtes très chanceux pour obtenir ce genre de FPS comme il est, et la majorité de vos utilisateurs (en supposant que votre public est de l'internet au sens large) sera plus que probablement pas ce genre de framerate.
Je suis d'accord que les capacités de flash player sont probablement pas suffisantes pour ce que vous essayez d'atteindre.
Bien sûr, chaque application a besoin de sa propre profilage, mais je serais assez réticent à l'idée de faire votre travail hors de la liste d'affichage et de copier les choses à l'écran comme une image bitmap. La FP, le rendu est évidemment assez fortement optimisé, et de le faire de cette façon, vous évitez tous ses optimisations, ou, au mieux, de vous faire votre propre optimisations ralentissement de la non-code natif.
OriginalL'auteur Ryan Guill