Delta-time et indépendance du framerate (cadence d'images)

1

Taggé

Contributeurs

Statistiques

13,287 visites, 13,900 vues

Outils

Partager

License

This tutorial is licensed under CC BY 4.0. Please refer to the license text if you wish to reuse, share or remix the content contained within this tutorial.

Published on 4 Jun, 2013. Last updated 25 Feb, 2019

Les jeux indépendants du framerate sont des jeux qui s'exécutent à la même vitesse quelque soit le framerate (la cadence d'images). Par exemple un jeu peut être exécuté à 30 FPS (Frame (image) par seconde) sur un ordinateur lent et 60 FPS sur une ordinateur rapide. Un jeu indépendant du framerate se déroule à la même vitesse sur les deux ordinateurs (les objets bougent à la même vitesse). D'un autre côté, un jeu dépendant du framerate se déroule à la moitié de la vitesse d'un ordinateur rapide sur un ordinateur lent donnant l'impression d'un effet "slow-motion" (ralenti).

Faire des jeux indépendants du framerate est important afin de rendre le jeu jouable et appréciable pour tout le monde, quelque soit la puissance de l'ordinateur utilisé. Les jeux qui ralentissent lorsque le framerate "pédale" peuvent sévèrement affecter le gameplay, frustrant les joueurs et les incitant à quitter et ne plus jouer !

Ce tutoriel décrit comment vous pouvez rendre votre jeu indépendant au framerate. Les mêmes techniques permettent aussi le time scaling (échelle de temps) qui permet ainsi des effets de ralenti délibérés et un moyen facile de mettre le jeu en pause.

L'expression système

dt

La clé de l'indépendance au framerate est l'expression système dt. dt est l'abréviation de delta-time (temps delta). Delta veut dire un changement en quantité donc delta-time veut dire un changement dans le temps. Il s'agit du temps, en secondes, depuis le dernier tick.

Par example à 100 FPS dt sera 0.01 (un centième de seconde), et à 10 FPS dt sera 0.1 (un dixième de seconde). En pratique, dt varie de tick en tick, donc il est improbable que la valeur reste la même sur des longues périodes de temps.

Notez que si vous ajoutez dt à une variable chaque tick, au final vous ajoutez 1 chaque seconde, car le temps entre chaque tick sur une durée de 1 seconde doit s’additionner à un total de 1! Cliquez ici pour un exemple qui montre ce principe. (Ajouter dt à la variable d'instance d'un objet est aussi un moyen pratique de faire un timer (minuterie) au sein d'un objet.)

Comment utiliser

dt

Typiquement un mouvement dépendant du framerate est réalisé à l'aide d'un event (événement) tel que celui-ci:

Chaque tick (une fois par frame) l'objet bouge de un pixel vers la droite. Notez qu'à 30 FPS cela veut dire 30 pixels par seconde, et à 60 FPS cela veut dire 60 pixels par seconde. Il s'agit de vitesses différentes dépendantes du framerate.

Rappelez-vous de l'exemple précédent que dt totalise toujours 1 chaque seconde. Donc si nous modifions l'event de cette manière:

...l'objet se déplacera vers la droite de 60 pixels chaque seconde à n'importe quel framerate. Puisque dt totalise 1 chaque seconde, 60 [] dt* totalise 60 chaque seconde. Cela signifie qu'à 30 comme à 60 FPS notre objet bouge à 60 pixels par seconde - la même vitesse quelque soit le framerate.

Utiliser

dt partout

Chaque fois que vous aurez à déplacer un objet à une vitesse constante, vous aurez besoin d'utiliser dt afin d'obtenir un mouvement indépendant du framerate. Par exemple, l'action Move forward (bouger en avant) de l'objet Sprite prends un certain nombre de pixels comme paramètre pour déplacer l'objet en avant. Si vous déplacez continuellement l'objet en avant, vous pouvez le "Move forward" de 60 [] dt* pixelse pour le déplacer à 60 pixels par secondes en direction de son angle actuel.

Les behaviors (comportements) utilisent déjà

dt

Tous les behaviors de Construct 2 utilisent dt dans leurs calculs internes de déplacement. Cela veut dire que n'importe quel objet déplacé par un behavior tel Platform ou 8 Direction ne requiert aucun traitement/formule particulier, ils prennent déjà dt en compte !

Notez que Physics est une exception. Par défaut ce behavior n'utilise pas dt, et est par conséquent dépendant du framerate. C'est parce que dt a généralement des petites variations aléatoires. ces variations peuvent faire que le même setup (la même configuration de projet/événement) dans un jeu basé sur la physique peut donner des résultats différents même si le jeu est joué exactement de la même manière deux fois d'affilée. Cela est souvent gênant pour les jeux basés sur la physique donc par défaut ce comportement est dépendant du framerate.

Cependant vous pouvez activer l'utilisation de dt en utilisant l'action Set Stepping Mode du comportement en début de layout (condition "On start of layout"), et choisir la valeur Framerate independent (indépendant du framerate).

Notez qu'en ce mode cela limite malgré tout le "timestep" maximum pour la physique à 1/30 (environ 33ms), car utiliser un très grand "timestep" peut causer de l'instabilité dans les simulations physiques.

Timescaling (Echelle de temps)

Une des caractéristiques vraiment sympa de Construct 2 est le timescaling. Cela vous permet de changer le taux auquel le temps s'écoule dans le jeu, aussi nommé time scale. Vous pouvez définir la propriété "time scale" à l'aide de l'action système Set Time Scale. Un "time scale" de 1 signifie une vitesse normale. 0.5 signifie moitié moins vite, et 2.0 signifie le double de la vitesse normale. Si vous fixez le "time scale" de votre jeu à 0.1 le jeu se déroulera dix fois plus lentement mais toujours de manière fluide, un joli effet de ralenti !

Le "timescaling" fonctionne en changeant la valeur retournée par dt. Cela signifie que les behaviors sont affectés ainsi que tout mouvement utilisant dt. Si vous n'utilisez pas dt dans vos calculs de mouvement (comme dans le tout premier évènement ci-dessus) le mouvement n'est pas affecté par "time scale" ! Ainsi pour utiliser le "time scaling", vous avez juste besoin d'utiliser dt de manière judicieuse dans tous vos mouvements.

Mettre en pause

Vous pouvez définir "time scale" à 0. Cela arrête tous les mouvements. C'est une manière simple de mettre votre jeu en pause. Remettez "time scale" à 1 et le jeu reprendra.

Vous pouvez remarquer que vous pouvez toujours effectuer des actions tel que tirer dans votre jeu en utilisant les contrôles. Vous pouvez vous en sortir en plaçant les évènements principaux de votre jeu dans un groupe et en l'activant/désactivant lorsque vous mettez ou enlevez la pause.

C'est aussi un bon moyen de tester si votre utilisation de dt est correcte. Si l'implémentation est correcte, mettre "time scale" à 0 stoppera tout dans votre jeu. Si votre implémentation contient des erreurs, certains objets continueront à bouger bien que le jeu soit supposé être en pause ! Dans ce cas, vérifiez comment les objets sont déplacés et assurez vous d'utiliser correctement dt.

D'autres sortes de mouvements

Il est important de réaliser que dt doit être utilisé pour toutes sortes de mouvements. Cela inclut les rotations et les accélérations.

Rotation

De même que plus tôt, l’événement suivant applique une rotation de 1 degré chaque tick sur le cochon (piggy):

Cela donne 30 degrés par seconde à 30 FPS et 60 degrés par seconde à 60 FPS. Une fois encore des vitesses (angulaires cette fois) différentes pour des framerate différents. Utiliser dt comme précédemment montré résout encore le problème. Ainsi le cochon se verra appliqué une rotation de 60 degrés par seconde quelque soit le framerate:

Accélération

L'accélération se produit de la même manière. Généralement cela ne s'applique que lorsque vous faites vos propres mouvements personnalisés à l'aide d'évènements.

Si vous avez un variable speed (vitesse), votre objet bougera à une vitesse de Object.Speed [] dt (vitesse de l'objet [] dt) pixels par tick. Ainsi la variable "speed" de votre objet contient une vitesse en pixels par seconde.

Supposons que vous souhaitiez accélérer le déplacement de l'objet de 100 pixels par seconde sur une durée de une seconde.

Vous avez simplement besoin d'ajouter 100 [] dt* à la variable "speed" de votre objet chaque tick et vous obtiendrez une accélération indépendante du framerate.

En d'autres mots, vous utilisez dt pour ajuster la position de l'objet ainsi que sa vitesse de déplacement.

Considérations avancées

Framerate minimum

A des framerates très bas, dt peut retourner une valeur importante. Par example à 5 FPS, dt est égal à 0.2. Un objet bougeant à 500 pixel par seconde se déplace donc à 100 pixels par tick. Cela peut causer des "téléportations" de l'objet à travers des murs ainsi que rater des collisions avec d'autres objets.

Un jeu est généralement injouable à un tel framerate, mais cela devient encore pire si cela entraîne l'instabilité. Pour aider un jeu à rester fiable même à très bas framerate, Construct 2 ne laisse pas dt retourner une valeur supérieure à 0.1. En d'autres mots, sous 10 FPS, dt reste à 0.1. Cela veut aussi dire qu'en dessous de 10 FPS le jeu se déroule constamment en ralenti (comme décrit précédemment comme l'un des soucis causé par les jeux dépendants du framerate), cependant, cela donne souvent de meilleurs résultats plutôt qu'une "téléportation d'objets".

Variations aléatoires

Comme mentionné pour le comportement "physics", dt a généralement de petites variations aléatoires, habituellement dues aux minuteries imparfaites des ordinateurs. Comme pour le comportement "physics" cela peut causer des variations aléatoires au sein de votre jeu. Cependant l'effet est généralement négligeable et bien moins remarquable qu'en utilisant de la physique. Il est recommandé de toujours utiliser dt dans vos jeux à moins qu'une précision exacte soit absolument requise (ce qui est plutôt rare).

Time scales des objets

Vous pouvez définir le "time scale" pour un objet en particulier à l'aide de l'action système Set object time scale (définir le "time scale" de l'objet). Cela vous permet, par exemple, d'avoir un jeu qui se déroule au ralenti avec un "time scale" de 0.3, mais quand même avoir le joueur agissant à pleine vitesse avec un "time scale" de 1. Vous pouvez y parvenir en fixant "time scale" à 0,3 et ensuite utiliser l'action Set object time scale afin de définir "time scale" pour l'objet joueur en particulier. L'expression système dt est seulement affectée par le "time scale" du jeu. Les objets ont leur propre expression dt (par exemple Joueur.dt) que vous devez utilisez à la place de l'expression système dt pour tout mouvement relatif à cet objet. Ainsi il y a deux valeurs pour dt: une pour le jeu et une autre pour le joueur. Puisqu'elles retournent des valeurs différentes, différentes parties du jeu peuvent s'exécuter à différentes vitesses.

Dans cet exemple pour ramener le joueur au temps du jeu utilisez l'action système Restore object time scale (restaurer "time scale" de l'objet).

Conclusion

Il est important de concevoir votre jeu en utilisant dt dès le départ. Cela améliore le gameplay, assurant que le rythme/déroulement du jeu ne ralenti jamais dans des parties particulièrement intenses du jeu.

En bonus, vous pouvez aussi utiliser le "time scaling" pour facilement mettre en pause le jeu et même contrôler les "time scales" individuels des objets.

N'oubliez pas que les behaviors (comportements) utilisent déjà dt (à l'exception de "Physics" où vous devez indiquer vous mêmes que vous souhaitez l'utiliser). Si vous utilisez des comportements pour contrôler tous les mouvements dans votre jeu, vous n'avez pas à vous soucier de dt du tout !

Cependant la plupart des jeux ont souvent des mouvements contrôlés par évènements et il est vital de se souvenir de les rendre indépendants au framerate.

  • 0 Comments

Want to leave a comment? Login or Register an account!