Introduction

Physics ticks and rendered frames

Un concept clé à comprendre dans Godot est la distinction entre les ticks de physique (parfois appelés itérations ou trames de physique), et les trames rendues. La physique se déroule à un rythme fixe (défini dans ProjectSettings.physics/common/physics_fps), qui est par défaut de 60 ticks par seconde.

However, the engine does not necessarily render at the same rate. Although many monitors refresh at 60 Hz (cycles per second), many refresh at completely different frequencies (e.g. 75 Hz, 144 Hz, 240 Hz or more). Even though a monitor may be able to show a new frame e.g. 60 times a second, there is no guarantee that the CPU and GPU will be able to supply frames at this rate. For instance, when running with V-Sync, the computer may be too slow for 60 and only reach the deadlines for 30 FPS, in which case the frames you see will change at 30 FPS (resulting in stuttering).

Mais il y a un problème ici. Que se passe-t-il si les tics de la physique ne coïncident pas avec les images ? Que se passe-t-il si la fréquence des tics physiques est déphasée par rapport à la fréquence des images ? Ou pire, que se passe-t-il si le taux de tics de la physique est plus bas que le taux de trame rendu ?

Ce problème est plus facile à comprendre si l'on considère un scénario extrême. Si vous définissez le taux de tics de la physique à 10 tics par seconde, dans un jeu simple avec un taux d'images rendues de 60 IPS. Si nous traçons un graphique des positions d'un objet en fonction des images rendues, vous pouvez voir que les positions semblent "sauter" tous les 1/10e de seconde, au lieu de donner un mouvement régulier. Lorsque la physique calcule une nouvelle position pour un nouvel objet, celui-ci n'est pas rendu dans cette position pour une seule image, mais pour 6 images.

../../../_images/fti_graph_fixed_ticks.png

Ce saut peut être observé dans d'autres combinaisons de tics / fréquence d'images sous forme de glitchs, ou de gigue, causés par cet effet d'escalier dû à l'écart entre le temps de tics de la physique et le temps d'image rendu.

Que peut-on faire pour éviter que les images et les tics ne soient pas désynchronisés ?

En vérouillant les tics et la fréquence d'images ensemble ?

La solution la plus évidente est de se débarrasser du problème en s'assurant qu'il y a un tic physique qui coïncide avec chaque image. C'était l'approche utilisée sur les anciennes consoles et les ordinateurs à matériel fixe. Si vous savez que tous les joueurs utiliseront le même matériel, vous pouvez vous assurer qu'il est suffisamment rapide pour calculer les tics et les images à 50 IPS, par exemple, et vous serez sûr que tout le monde sera satisfait.

Cependant, les jeux modernes ne sont souvent plus conçus pour un seul type de matériel. Vous aurez souvent à planifier de développer des jeux pour ordinateurs, téléphones et autres, qui présentent tous d'énormes variations de performances, ainsi que des taux de rafraîchissement d'écran différents. Nous devons trouver une meilleure façon de gérer ce problème.

Adapter le taux de tics physique ?

Au lieu de concevoir le jeu à une fréquence de tics physique fixe, nous pourrions permettre à la fréquence de tics d'évoluer en fonction du matériel de l'utilisateur. Nous pourrions par exemple utiliser un taux de tic fixe qui fonctionne pour ce matériel, ou même varier la durée de chaque tic physique pour correspondre à une durée d'image particulière.

Cela fonctionne, mais il y a un problème. La physique (et la logique de jeu, qui est souvent aussi exécutée dans _physics_process) fonctionne mieux et de manière plus cohérente lorsqu'elle est exécutée à une vitesse de tics prédéterminée fixe. Si vous essayez d'exécuter un jeu de course physique qui a été conçu pour 60 TPS (tics par seconde) à 10 TPS par exemple, la physique se comportera de manière complètement différente. Les commandes peuvent être moins réactives, les collisions / trajectoires peuvent être complètement différentes. Vous pouvez tester votre jeu de manière approfondie à 60 TPS, puis constater qu'il est défaillant sur les machines des utilisateurs lorsqu'il fonctionne à un taux de tic par seconde différent.

Cela peut rendre l'assurance qualité difficile avec des bugs difficiles à reproduire, notamment dans les jeux AAA où les problèmes de ce type peuvent être très coûteux. Cela peut également être problématique pour les jeux multijoueurs à des fins d'intégrité compétitive, car l'exécution du jeu à certains taux de tics peut être plus avantageuse que d'autres.

Verrouiller la fréquence des tics, mais utiliser l'interpolation pour lisser les images entre les tics physiques

C'est devenu l'une des approches les plus populaires pour régler le problème. Elle est prise en charge par Godot 3.5 et les versions ultérieures en 3D (bien qu'elle soit facultative et désactivée par défaut).

Nous avons établi que l'arrangement physique/logique de jeu le plus souhaitable pour la cohérence et la prévisibilité est un taux de tic physique qui est fixé au moment de la conception du jeu. Le problème est la divergence entre la position physique enregistrée et l'endroit où nous "voulons" qu'un objet physique soit représenté sur une image pour donner un mouvement fluide.

La réponse s’avère simple, mais peut être un peu difficile à comprendre au début.

Au lieu de seulement garder en mémoire la position actuelle d'un objet physique dans le moteur, on garde à la fois de la position actuelle de l'objet et de la position précédente lors du tic physique précédent.

Pourquoi avons-nous besoin de la position précédente (en fait, de toute la transformation, y compris la rotation et la mise à l'échelle) ? En utilisant un peu de magie mathématique, nous pouvons utiliser l'interpolation pour calculer ce que serait la transformation de l'objet entre ces deux points, dans notre monde idéal de mouvement continu et fluide.

../../../_images/fti_graph_interpolated.png

Interpolation linéaire

Le moyen le plus simple d'y parvenir est l'interpolation linéaire, ou lerping, que vous avez peut-être déjà utilisée auparavant.

Considérons uniquement la position, et une situation où nous savons que la coordonnée X du tic physique précédent était de 10 unités, et que la coordonnée X du tic physique actuel est de 30 unités.

Note

Bien que les mathématiques soient expliquées ici, vous n'avez pas à vous soucier des détails, car cette étape sera effectuée pour vous. Sous le capot, Godot peut utiliser des formes plus complexes d'interpolation, mais l'interpolation linéaire est la plus facile en termes d'explication.

La fraction d'interpolation physique

Si les tics de notre physique se produisent 10 fois par seconde (pour cet exemple), que se passe-t-il si notre image rendue a lieu à 0,12 seconde ? Nous pouvons faire quelques calculs pour déterminer où l'objet doit se trouver pour obtenir un mouvement fluide entre les deux tics.

Tout d'abord, nous devons calculer à quelle distance du tic physique nous voulons que l'objet se trouve. Si le dernier tic physique a eu lieu à 0,1 seconde, nous sommes à 0,02 seconde (0,12 - 0,1) d'un tic-tac dont nous savons qu'il prendra 0,1 seconde (10 tics par seconde). La fraction de la durée du tic est donc :

fraction = 0.02 / 0.10
fraction = 0.2

On appelle ça la fraction d'interpolation physique, qui est calculée pour vous par Godot. Elle peut être récupérée sur n'importe quelle image en appelant Engine.get_physics_interpolation_fraction.

Calcul de la position interpolée

Une fois que nous avons la fraction d'interpolation, nous pouvons l'insérer dans une équation d'interpolation linéaire standard. La coordonnée X serait donc :

x_interpolated = x_prev + ((x_curr - x_prev) * 0.2)

Donc en substituant notre x_prev par 10, et x_curr par 30 :

x_interpolated = 10 + ((30 - 10) * 0.2)
x_interpolated = 10 + 4
x_interpolated = 14

Décomposons ça :

  • Nous savons que le X part de la coordonnée du tic précédent (x_prev) qui est de 10 unités.

  • Nous savons qu'après le tic complet, la différence entre le tic actuel et le tic précédent aura été ajoutée (x_curr - x_prev) (ce qui représente 20 unités).

  • La seule chose que nous devons faire varier est la proportion de cette différence que nous ajoutons, en fonction de l'avancement du tic physique.

Note

Bien que cet exemple interpole la position, la même chose peut être faite avec la rotation et l'échelle des objets. Il n'est pas nécessaire de connaître les détails car Godot fera tout cela pour vous.

Transformations lissées entre les tics physique ?

Tout cela montre qu'il devrait être possible d'obtenir une estimation lisse de la transformation des objets entre le tic physique actuel et le précédent.

Mais attendez, vous avez peut-être remarqué quelque chose. Si nous interpolons entre le tick actuel et le précedent, nous ne sommes pas en train d'estimer la position de l'objet maintenant, nous sommes en train d'estimer la position de l'objet dans le passé. Pour être exact, nous estimons la position de l'objet entre 1 et 2 ticks dans le passé.

Dans le passé

Qu'est-ce que cela signifie ? Ce système fonctionne, mais cela signifie que nous introduisons effectivement un délai entre ce que nous voyons à l'écran et l'endroit où les objets devraient se trouver.

En pratique, la majorité ne remarquera pas ce délai, ou plutôt, il n'est typiquement pas insupportable. Il existe déjà des délais importants dans les jeux vidéos, toutefois nous ne les remarquons typiquement pas. L'effet le plus important peut se manifester par un délai dans l'entrée, ce qui peut affecter les jeux avec des temps de réponse rapide. Dans de telles situations, vous pouvez désactiver l'interpolation physique et changer de schéma, ou utiliser un taux de tic élevé, puisque ceci atténue les délais.

Pourquoi regarder dans le passé ? Pourquoi ne pas prédire l'avenir ?

Il y a une alternative à ce schème : plutôt que d'interpoler entre le tic précédent et le tic actuel, nous utilisons les mathématiques pour extrapoler*vers le futur. Nous essayons de prédire où l'objet *sera, plutôt que de démontrer d'où il vient. Ceci est possible, et sera peut-être offert comme option dans le futur, mais il existe d'importants inconvénients :

  • Il se peut que la prédiction ne soit pas correcte, surtout lorsqu'un objet entre en collision avec un autre durant le tic physique.

  • Là où une prédiction était incorrecte, l'objet peut être extrapolé vers une position "impossible", telle que dans un mur.

  • Si la vitesse de déplacement est lente, ces prédictions incorrectes ne seront probablement pas problématiques.

  • Lorsqu'une prédiction était incorrecte, l'objet peut devoir sauter ou revenir rapidement sur le chemin corrigé. Ceci peut être visuellement discordant.

Fixed timestep interpolation

Dans Godot, ce système est souvent désigné "interpolation physique", mais vous pouvez également le voir appelé "interpolation à intervalles fixes", puisqu'il s'agit d'une interpolation entre des objets déplacés à des intervalles de temps fixes (des ticks physiques par seconde). Dans certains contextes le second terme est plus approprié puisqu'il est utilisé pour interpoler des objets qui ne sont pas affectés par la physique.

Astuce

Bien que l'interpolation physique soit typiquement un bon choix, il existe des exceptions où vous choisirez de ne pas utiliser le système d'interpolation (ou vous l'utiliserez de façon limitée). Les jeux multijoueurs en ligne sont un exemple d'une telle exception. Les jeux multijoueurs reçoivent souvent des tics ou de l'information temporelle des autres joueurs ou d'un serveur, et ceux-ci ne coïncideront pas nécessairement aux tics physiques locaux, alors une technique d'interpolation personnalisée peut être une meilleure option.