[Rà‰SOLU] Intervalle de temps pendant la pause

CoharsCohars Membre
avril 2011 modifié dans Apple Developer Programs #1
Bonjour !
Je cherche à  mesurer le temps que dure une partie (de mon jeu), et en temps réel. Je définie donc une date au début du jeu, et je mesure la durée avec "intervalSinceNow". Seulement voilà , si le jeu est en pause, le temps passe toujours, j'aimerais que ce temps ne soit pas compter. (J'ai un peu de mal à  expliquer mon problème mais je pense que vous m'avez compris.)

J'ai chercher du côté de
dateByAddingTimeInterval:
Mais je ne vois pas vraiment comment faire.

Merci.

Réponses

  • zoczoc Membre
    02:00 modifié #2
    Le plus simple c'est sans doute de compter le temps passé en pause et de faire la soustraction  ;)
  • CoharsCohars Membre
    02:00 modifié #3
    Oui en effet c'était la meilleure chose à  faire, j'avais peur de me lancer dans quelques chose de trop compliquer alors qu'il existait bien plus simple. Mais en fait non, j'enregistre la durée de pause avec les NSUserDefaults (que je commence à  bien manipuler au passage) et tout va bien.

    Merci.

    Une petite question, on m'avait conseillé d'utiliser abs() pour avoir une valeurs toujours positive d'un NSTimeInterval (en l'occurrence), mais abs transforme en entier, ça existe pour les float ?
  • DrakenDraken Membre
    02:00 modifié #4
    Penses à  vérifier si ton système fonctionne quand le joueur ferme le jeu alors qu'il est en mode pause.

    Dans la mesure où le temps vas toujours du passé vers le futur, ton intervalle sera toujours positif.

  • CoharsCohars Membre
    02:00 modifié #5
    "Penses à  vérifier si ton système fonctionne quand le joueur ferme le jeu alors qu'il est en mode pause."
    ah... ça ne fonctionne pas. ça veut dire qu'il ne compte pas le temps pendant la pause ?
    Je ne comprend pas pourquoi ça ne marche.
    Je défini ma date dans le onEnter, et je prendre le timeIntervalSinceNow dans le onExit (de la "scene" (j'utilise cocos2D) pause), donc que le jeu suis en background ou non l'intervalle devrait être le même non ?


    "Dans la mesure où le temps vas toujours du passé vers le futur, ton intervalle sera toujours positif."

    Dans le onEnter j'ai :
    maDate = [[NSDate alloc] init];

    et dans le onExit j'ai :
    NSTimeInterval interval = [maDate timeIntervalSinceNow];

    donc comme maDate est antérieure au moment où je récupère l'intervalle, elle est toujours négative. (c'était l'objet de mon dernier post).

    Mais peut importe, pour d'autre chose j'utilise la racine du carré de mes variables quand je veux leur valeurs absolue. Il existe pas un abs() qui renvoie un float ?

    Merci !
  • DrakenDraken Membre
    02:00 modifié #6
    Si ton jeu utilise une boucle de jeu, tu peux aussi mesurer le temps écoulé entre deux frames d'affichage, pour l'additionner à  un compteur de temps. Et désactiver le système en mode "pause".



  • CoharsCohars Membre
    02:00 modifié #7
    ça c'est la méthode compliquée non ? ^^ .

    Merci, je verrai tout ça demain, la nuit porte conseils !
  • DrakenDraken Membre
    02:00 modifié #8
    Non, c'est la méthode simple ! Mais tu as raison, il se fait tard. On verra ça demain.

  • laudemalaudema Membre
    02:00 modifié #9
    Bonjour,
    dans 1302388915:

    NSTimeInterval interval = [maDate timeIntervalSinceNow];

    Si l'on admet que now = [NSDate date] pourquoi ne pas utiliser

    timeIntervalSinceDate:
    <br />NSTimeInterval duree = [[NSDate date] timeIntervalSinceDate:maDate];<br />
    
    ?

    Return Value
    The interval between the receiver and anotherDate. If the receiver is earlier than anotherDate, the return value is negative.

    hth
  • AliGatorAliGator Membre, Modérateur
    02:00 modifié #10
    Alors des réponses en vrac :

    1) C'est une TRES mauvaise idée que de faire la racine carrée du carré de ta valeur pour prendre la valeur absolue.
    Il vaut mieux à  la limite faire un "if (x<0) return -x else return x;" que un "return sqrtf(x*x)"
    En terme de temps processeur, une multiplication prend déjà  pas mal de temps, une racine carrée n'en parlons pas c'est l'une des opérations les plus coûteuses ! A éviter à  tout prix dès qu'on peut faire autrement.

    2) Du coup pour répondre à  ta question, oui il existe un équivalent à  "abs" pour les float, c'est "fabs". Il suffit d'aller dans la page du manuel de la fonction C "abs" " donc "man abs" dans le terminal ou dans Google " pour voir dans la doc la liste des fonctions similaires, dont fabs.
    MAIS dans ton cas pourquoi se compliquer la vie encore une fois ? Tu sais que ta valeur sera toujours négative, pourquoi ne pas juste mettre un "-" devant pour la rendre positive ? Pourquoi vouloir se compliquer avec des racines de carrés de machin et perdre 50 cycles CPU là  où une simple inversion de signe suffit ?


    3) @Draken : La solution de mesurer la durée entre 2 frames d'affichage et l'ajouter risque fortement (pour ne pas dire "va forcément") ajouter une dérive à  la valeur qui va se cumuler à  chaque frame, à  la fin ta valeur risque d'avoir dérivé de beaucoup et s'être beaucoup éloigné de la réalité ! Donc ce n'est pas forcément la méthode la plus simple ni la plus adaptée. Il vaut mieux toujours éviter de faire pour ce genre de choses une infinité d'additions successives, mais préférer un seul calcul absolu.

    4) @laudema c'est une solution, oui, mais autant utiliser [tt]-[startDate timeintervalSinceNow][/tt] qui retournera la même chose mais qui évitera d'instancier un objet NSDate autorelease pour rien de ton côté.


    A mon avis le plus simple comme solution c'est :
    - de prévoir une variable "NSTimeInterval cumulTime" et une variable "NSDate* startTimeSinceLastPause".
    - Au moment où tu démarres ton jeu, tu mets cumulTime à  0 et startTimeSinceLastPause à  [NSDate date].
    - Au moment où tu mets ton jeu en pause, tu calcules [tt]cumulTime -= [startTimeSinceLastPause timeintervalSinceNow];[/tt] (c'est "-=" mais comme timeintervalSinceNow va te renvoyer un nombre négatif, en fait tu vas bien "ajouter une valeur positive" donc cumuler le temps passé dans cette variable), et tu stockes même cette valeur dans les NSUserDefaults.
    - Au moment de sortir de pause, tu remet startTimeSinceLastPause à  [NSDate date]

    --> Le temps écoulé pendant le jeu vaudra [tt]cumulTime - [startTimeSinceLastPause timeintervalSinceNow][/tt]

    C'est à  dire qu'à  chaque fois que tu mets en pause, tu mémorises/cumules le temps écoulé jusque là , et tu ne te sers de NSDate que pendant le temps que le chrono s'écoule depuis la dernière pause. cumulTime représente le temps cumulé entre le début du jeu et la dernière mise en pause, cette valeur cumule la somme des durées de toutes les périodes "play/pause" depuis le début du jeu, et startTimeSinceLastPause ne calcule que le temps en train de s'écouler depuis la dernière pause (et pas depuis le début du jeu) comme ça quand tu manipules ce NSDate tu n'as pas à  te soucier de prendre en compte les pauses qui ont été faites dans ton jeu ni à  savoir combien de temps elles ont duré.
  • devulderdevulder Membre
    02:00 modifié #11
    Hello,

    Une solution serait de faire d'utiliser un NSTimer qui appelerait une méthode

    toute les seconde, et d'incrémenter une valeur contenant le nombres de secondes jouées.

    Avec également une variable flag mis en cas de pause du jeu et qui permet quitter la méthode sans incrémenter

    genre:

    -(void)monCompteurTemps<br />{<br /> if (pause) return;<br /> <br /> nbSecsPlayed++;<br />}<br />
    

  • AliGatorAliGator Membre, Modérateur
    02:00 modifié #12
    @devulder ta solution a le même problème que celle de Draken elle souffre du problème de jigue/dérive puisque tu proposes le même concept de faire des accumulations multiples :(
    Encore plus avec un NSTimer dont le temps de déclenchement n'est pas garanti (il ne se déclenche qu'à  chaque tour de RunLoop maximum, donc pas forcément au temps exact où on l'a demandé à  la milliseconde près).
    Alors certes sur une partie qui dure quelques secondes ou même quelques minutes, ça tiendra, mais sur du long terme...
  • laudemalaudema Membre
    avril 2011 modifié #13
    Ali,

    Pour les timeIntervals il y a NSProcessInfo et la méthode d'instance systemUptime qui donne le timeInterval depuis la mise en route de la machine (évite d'instancier une NSDate, j'aurais dû y penser...).[Edit iOS 4 only]
    Pour consulter une page de man Xcode offre ça dans sa dernière ligne du menu Help sans avoir à  quitter l'environnement de travail.
  • AliGatorAliGator Membre, Modérateur
    02:00 modifié #14
    Yep bien vu Laudema, c'est également une méthode pour calculer le temps qui peut même être plus efficace que timeintervalSinceNow vu qu'on ne manipule que des double (NSTimeInterval) directement avec ça, sans passer par des NSDate intermédiaires :) Donc pour le besoin ici présent c'est tout à  fait adapté !
  • DrakenDraken Membre
    avril 2011 modifié #15
    Si la boucle de jeu est pilotée par CADisplayLink, ce qui est fortement recommandé pour obtenir un  affichage propre, on peut connaà®tre le temps écoulé depuis la précédente frame, grâce à  sa propriété timestamp.

    CADisplayLink est un objet très utile, permettant de synchroniser la boucle de jeu avec la fréquence de rafraà®chissement de l'écran.

    En provenance de la doc Apple :
    timestamp
    The time value associated with the last frame that was displayed. (read-only)

    @property(readonly, nonatomic) CFTimeInterval timestamp
    Discussion
    The target should use the value of this property to calculate what should be displayed in the next frame.

    Availability
    Available in iOS 3.1 and later.
    Declared In
    CADisplayLink.h

  • CoharsCohars Membre
    avril 2011 modifié #16
    dans 1302428079:

    Alors des réponses en vrac :

    1) C'est une TRES mauvaise idée que de faire la racine carrée du carré de ta valeur pour prendre la valeur absolue.
    Il vaut mieux à  la limite faire un "if (x<0) return -x else return x;" que un "return sqrtf(x*x)"
    [...]
    MAIS dans ton cas pourquoi se compliquer la vie encore une fois ? Tu sais que ta valeur sera toujours négative, pourquoi ne pas juste mettre un "-" devant pour la rendre positive ? Pourquoi vouloir se compliquer avec des racines de carrés de machin et perdre 50 cycles CPU là  où une simple inversion de signe suffit ?


    C'est bien ce que je fais  . J'utilise les racines carré (du carré) dans une formule pour la rotation des sprites qui reviens assez souvent. Je pensais justement que ça prenais moins de ressources que les if, else et compagnie, mais ça prend juste moins de lignes :p .

    Donc merci pour le fabs, et la petite astuce de recherche dans google.

    dans 1302428079:

    A mon avis le plus simple comme solution c'est :
    - de prévoir une variable "NSTimeInterval cumulTime" et une variable "NSDate* startTimeSinceLastPause".
    - Au moment où tu démarres ton jeu, tu mets cumulTime à  0 et startTimeSinceLastPause à  [NSDate date].
    - Au moment où tu mets ton jeu en pause, tu calcules [tt]cumulTime -= [startTimeSinceLastPause timeintervalSinceNow];[/tt] (c'est "-=" mais comme timeintervalSinceNow va te renvoyer un nombre négatif, en fait tu vas bien "ajouter une valeur positive" donc cumuler le temps passé dans cette variable), et tu stockes même cette valeur dans les NSUserDefaults.
    - Au moment de sortir de pause, tu remet startTimeSinceLastPause à  [NSDate date]

    --> Le temps écoulé pendant le jeu vaudra [tt]cumulTime - [startTimeSinceLastPause timeintervalSinceNow][/tt]

    C'est à  dire qu'à  chaque fois que tu mets en pause, tu mémorises/cumules le temps écoulé jusque là , et tu ne te sers de NSDate que pendant le temps que le chrono s'écoule depuis la dernière pause. cumulTime représente le temps cumulé entre le début du jeu et la dernière mise en pause, cette valeur cumule la somme des durées de toutes les périodes "play/pause" depuis le début du jeu, et startTimeSinceLastPause ne calcule que le temps en train de s'écouler depuis la dernière pause (et pas depuis le début du jeu) comme ça quand tu manipules ce NSDate tu n'as pas à  te soucier de prendre en compte les pauses qui ont été faites dans ton jeu ni à  savoir combien de temps elles ont duré.


    Donc tu me conseil de calculer le temps de jeu plutôt que le temps de pause. ça parait tellement plus cohérent et logique  ??? je m'en veux de ne pas y avoir pensé. Merci, je vais mettre tout ça en application :) .

    EDIT : ça marche à  merveille ! Merci !
  • AliGatorAliGator Membre, Modérateur
    02:00 modifié #17
    Cool :) Je l'avais pas testé mais en effet ça me paraissait plus logique, ravi que ça fonctionne.
    Pour la racine carrée du carré, je te conseille de la supprimer de ton code partout.
    - Si tu sais que la valeur x est positive ou négative, utilise directement x ou -x
    - Si tu veux la valeur absolue, utilise fabs


    De la même manière pour continuer dans l'idée, si tu peux te passer de la sqrtf dans tous les autres calculs il ne faut pas hésiter, car c'est une fonction vraiment coûteuse.
    Par exemple pour savoir si le point (x,y) est à  une distance de l'origine inférieure à  D, plutôt que de vérifier si [tt]sqrtf(x*x+y*y) < D[/tt] (pythagore / calcul de distance dans un repère orthogonal), il faut plutôt vérifier si [tt](x*x+y*y)<D*D[/tt] cela sera beaucoup moins coûteux comme calcul car tu évites le calcul de la racine carrée. Surtout si D est une constante et que le compilateur va remplacer D*D par la valeur de ce produit directement (et donc ne pas calculer cette valeur à  l'exécution, mais à  la compilation, vu qu'elle est constante)
    Les FPU des ordinateurs sont maintenant assez optimisés pour les calculs de multiplications, mais la racine carrée ça reste encore coûteux (tout comme la division d'ailleurs bien que cette dernière le soit un peu moins que sqrt quand même)
Connectez-vous ou Inscrivez-vous pour répondre.