Calcul du framerate réel d’une animation
Parfois, avec Flash, il faut savoir réinventer la roue. Par exemple, lorsque l’on veut coder un moteur d’animation qui s’intègre au sein d’un système de rendu isométrique complexe, on aimerait à la foi pouvoir disposer d’un framerate le plus élevé possible, tout en jouant les animations au framerate dans lequel elles ont été réalisées.
Pour se faire, il faut obligatoirement passer par l’indispensable case du calcul du framerate en cours. Il existe peut-être des mondes merveilleux ou la valeur que l’on a entrée dans le champ « Nombre d’images par secondes » de l’IDE Flash est tout le temps vraie, mais il ne s’agit pas du notre.
Voyons différentes approches pour calculer un framerate.
La méthode couplée : Timer
et ENTER_FRAME
package net.tynambule.exp { import flash.events.TimerEvent; import flash.utils.Timer; import flash.events.Event; import flash.text.TextField; import flash.display.Sprite; /** * Calcul du framerate : * Méthode du timer */ [SWF(backgroundColor="#ffffff", frameRate="100", width="100", height="100")] public class FramePerSecondCounter extends Sprite { private var _fpsDisplayer : TextField; private var _fpsUpdater : Timer; private var _framesCount : uint; public function FramePerSecondCounter() { // On crée et on affiche un textfield pour afficher nos FPS _fpsDisplayer = new TextField(); this.addChild(_fpsDisplayer); // On initialise un compteur et un timer _fpsUpdater = new Timer(1000); _fpsUpdater.addEventListener(TimerEvent.TIMER, onTimer); stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); _fpsUpdater.start(); } private function onEnterFrame(e : Event) : void { _framesCount ++; } private function onTimer(e : TimerEvent) : void { _fpsDisplayer.text = _framesCount + "fps"; _framesCount = 0; } } }
L’avantage de cette méthode, c’est qu’elle donne une valeur aussi réaliste que possible. Le désavantage, c’est qu’elle est couteuse en performances (puisque l’on utilise un ENTER_FRAME
, qui est toujours un évènement qu’il vaut mieux éviter quand c’est possible – même si c’est rarement possible, surtout dans ce cas), et en plus, notre valeur est mise à jour une fois par seconde seulement et n’est pas disponible durant la première seconde d’écoulement de l’application.
Méthode de l’estimation en fonction de l’écart
package net.tynambule.exp { import flash.utils.getTimer; import flash.events.Event; import flash.text.TextField; import flash.display.Sprite; /** * Calcul du framerate : * Méthode de l'estimation en fonction de l'écart */ [SWF(backgroundColor="#ffffff", frameRate="100", width="100", height="100")] public class FramePerSecondCounter extends Sprite { private var _fpsDisplayer : TextField; private var _lastFrame : int = -1; public function FramePerSecondCounter() { // On crée et on affiche un textfield pour afficher nos FPS _fpsDisplayer = new TextField(); this.addChild(_fpsDisplayer); // On lance l'évènement ENTER_FRAME stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e : Event) : void { var now : uint = getTimer(); if(_lastFrame != -1) _fpsDisplayer.text = (1000 / (now - _lastFrame)) + "fps"; _lastFrame = now; } } }
Cette méthode permet d’avoir un FPS mis à jour image par image, disponible dès la deuxième image de l’animation. Désavantage : on fait une opération relativement complexe sur un évènement ENTER_FRAME
.
Méthode du calcul du FPS global depuis le début de l’animation
package net.tynambule.exp { import flash.utils.getTimer; import flash.events.Event; import flash.text.TextField; import flash.display.Sprite; /** * Calcul du framerate : * Méthode du calcul du FPS global depuis le début de l'animation */ [SWF(backgroundColor="#ffffff", frameRate="100", width="100", height="100")] public class FramePerSecondCounter extends Sprite { private var _fpsDisplayer : TextField; private var _framesCount : uint; public function FramePerSecondCounter() { // On crée et on affiche un textfield pour afficher nos FPS _fpsDisplayer = new TextField(); this.addChild(_fpsDisplayer); // On lance l'évènement ENTER_FRAME stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e : Event) : void { _framesCount ++; // On ne met à jour qu'une fois chaque 50 frames pour prendre moins de temps if(_framesCount % 50 == 0) { _fpsDisplayer.text = (_framesCount / (getTimer() / 1000)) + "fps"; } } } }
Cette méthode est relativement peu couteuse (quoique dépendante du taux de rafraichissement désiré pour la valeur de FPS), mais n’a une précision que très limitée, puisque son temps d’adaptation est proportionnel au nombre d’images déjà jouées. Elle peut être intéressante pour des benchmarks très courts, tant que l’on garde cette méthode d’évaluation pour toutes les mesures, et que l’on fasse chaque mesure dans un temps prédéterminé égal.
La méthode de la mesure sur une période sans timer
package net.tynambule.exp { import flash.utils.getTimer; import flash.events.Event; import flash.text.TextField; import flash.display.Sprite; /** * Calcul du framerate : * Méthode du calcul du FPS sur une durée sans timer */ [SWF(backgroundColor="#ffffff", frameRate="100", width="100", height="100")] public class FramePerSecondCounter extends Sprite { private var _fpsDisplayer : TextField; // Temps en miliseconde entre deux mises à jour du compteur private const REFRESH_DELAY : uint = 5000; private var _lastThreshold : uint = 0; private var _framesCount : uint; public function FramePerSecondCounter() { // On crée et on affiche un textfield pour afficher nos FPS _fpsDisplayer = new TextField(); this.addChild(_fpsDisplayer); // On lance l'évènement ENTER_FRAME stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); } private function onEnterFrame(e : Event) : void { _framesCount ++; var now : uint = getTimer(); var delay : uint = now - _lastThreshold; if(delay > REFRESH_DELAY) { _fpsDisplayer.text = (_framesCount / (delay / 1000)) + "fps"; _framesCount = 0; _lastThreshold = now; } } } }
Cette méthode me parait être la moins gourmande, et garde une bonne précision. En plus, elle a l’indéniable avantage d’être personnalisable : plus le délai de rafraichissement est long, moins souvent l’on fait un calcul « complexe » (la relativité est une chose merveilleuse). C’est la méthode pour laquelle j’ai finalement opté.
Allez, salut !
Cool ton petit FramePerSecondCounter! Si ça ne te dérange pas je vais l’utiliser pour tester les perfs de mes scènes papervision3D. Tu passeras le bonjour à Blaggy de ma part si tu le croises dans les bureaux d’Ankama
C’est fait pour, n’hésite pas.
Je lui transmet ton bonjour ! :p
Merci beaucoup de partager, ca m’a été utile
merci !