Modifier un NSTimer....
Salut tout le monde,
le petit problème du jour :
- j'ai une animation d'éléments CoreGraphics (méthode drawRect) en boucle,
- je voudrais la faire accélérer toutes les x secondes,
- je suis parti sur un NSTimer,
- il ne faut pas que l'animation soit bloquée pendant les interactions utilisateurs.
Problème, une fois créé, on ne peut pas modifier l'interval d'un timer.
Donc, comment palier ce problème ?
Merci.
le petit problème du jour :
- j'ai une animation d'éléments CoreGraphics (méthode drawRect) en boucle,
- je voudrais la faire accélérer toutes les x secondes,
- je suis parti sur un NSTimer,
- il ne faut pas que l'animation soit bloquée pendant les interactions utilisateurs.
Problème, une fois créé, on ne peut pas modifier l'interval d'un timer.
Donc, comment palier ce problème ?
Merci.
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Genre:
seconde = seconde +1;
Distance = ratio * seconde;
Et remettre a 0 seconde selon 1 ou plusieurs critères ...
J'ai utilisé la méthode de NseaProtector, ça me va pour le moment, on verra pour la suite.
Ok, cela redéfinit autrement le problème. Cependant :
C'est faux, voir deux posts au-dessus.
C'est la bonne technique à adopter, surtout si tu as plusieurs animations a gérer sur l'écran. Tu ne vas pas créer un timer spécifique pour chaque animation. Imagine un jeu vidéo où chaque ennemi posséderais son propre timer !
Il est préférable d'avoir un seul timer donnant une "ligne temporelle unique", et de l'utiliser pour calculer les déplacements et les vitesses/accélérations de chaque animation.
Par exemple tu prend un timer calibré à 60 fois par seconde, pour coà¯ncider avec la fréquence de rafraà®chissement de l'écran.
Quoi que. Une question pour les connaisseurs, l'écran de l'iPhone est-il rafraà®chis à 60 Hz comme un LCD classique, ou est-ce différent ?
C'est une utopie, cela ne sera pas respecté au run-time.
Exemple :
On peut raisonnablement espérer quel framerate avec une application Core Graphics pas trop gourmande, sur iPhone ?
On ne raisonne pas comme cela. On place l'appli en tant que client, en demandant une exécution dans un certain "délai", et le scheduler fait le reste. En tant que programmeur, on s'adapte à chaque étape. Essaie une simple application présentant une horloge, tu verras que c'est tout simple à condition de se dire : "bon quand j'arrives là , j'interroge le système pour savoir où il en est" plutôt que d'essayer de se dire "bon à cette étape le système en sera exactement là ". Bref, c'est pas toi le chef en ce qui concerne la gestion de l'iPhone.
De plus n'oublions le phénomène de persistence rétinienne, dans le domaine visuel, 60 images par seconde cela ne sert à rien qu'à faire des calculs intermédiaires inutiles.
Sur mac, pour avoir un timer précis (séquenceur) j'utilise un thread comme ceci. (Je dis cela parce que les timers ne sont pas forcement ce qu'il y'a de mieux comme référence temps.)
Les timers sont installés sur la runloop de ton thread (par exemple la runloop de ton thread principal, si tu ne fais pas une appli multihread, runloop qui est créée et lancée automatiquement au lancement de ton appli ça fait partie des choses que fait NSApplicationMain). Quand tu crées un timer, tu le schedule sur la RunLoop, il va donc s'installer tout seul sur ta runloop en tant que RunLoopSource, et la prochaine fois que la RunLoop détecte qu'un des timers qu'elle a comme source doit être déclenché, elle le déclenche.
Faire un thread séparé avec une boucle while qui fait des usleep revient exactement à reproduire le schéma de la runloop qui vérifie ses inputsources et déclenche les timers quand il y a besoin.
Dans tous les cas, lorsque l'on a besoin de faire une horloge, quelle que soit la méthode choisie, de par le fait de gérer les problématiques temps réel, il faut appliquer les règles qui s'imposent. En particulier il faut calculer le temps par rapport à un temps de référence et non supposer qu'il s'est passé N secondes (ou millisecondes) depuis le dernier appel, car ça ce n'est jamais vérifiable. Puisque dans les applis temps réel que ce soit une runloop et un timer ou un thread et une boucle while avec usleep ou des interruptions par alarm() ou autre, dans tous les cas le temps écoulé en général est relativement proche de celui demandé, mais jamais pile poil exact, et donc il ne faut pas s'y fier au risque de créer une dérive.
J'ai réussi à faire ce que je voulais en "détruisant" un timer puis en en créant un autre avce le nouvel Interval.
Ma deuxième application avance bien grâce à vous.
Merci.
J'aime bien ce que tu dis, comme d'habitude c'est bien étayé... Sauf que, le timer dans la runloop peut-être gelé par un event ou une méthode gourmand et donc être suffisamment imprécis pour que cela se remarque. Pour avoir essayé, mon thread est très au dessus d'un timer en terme de régularité. Maintenant, je reconnais que se baser sur une interruption machine ou un compteur "machine" se serait surrement mieux, mais je ne sais pas sur quoi me baser ? Je crois qu'il existe un temps écoulé depuis l'allumage de la machine ? Est-ce différent sur mac et sur iPhone ?
http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-part-6_25.html
Voici une séquence de code prise dans la routine de dessin d'une application temps réel, piloté par un timer à 60 hz. Elle calcule le temps écoulé depuis la dernière séquence d'affichage.
 static NSTimeInterval lastDrawTime=0;
NSTimeInterval est un double. A moins que gcc fasse une initialisation automatique des variables statiques ?
"Unless they have an explicit initializer, all objects with static duration are given implicit initializers"the effect is as if the constant 0 had been assigned to their components. This is in fact widely used"it is an assumption made by most C programs that external objects and internal static objects start with the value zero."
Il n'est donc pas nécessaire d'initialiser une variable static.