Encore un autre article sur quand utiliser les méthodes Update et FixedUpdated.
TD; LR: Ayant, assez facilement, recréé le problème du mélange et de la correspondance des étapes temporelles, je me suis convaincu que je devrais mettre tout l’état du jeu dans les méthodes FixedUpdate.
Avant d’entrer dans le fond de cet article, j’ai voulu clarifier pourquoi je m’intéresse à l’unité en premier lieu:
- Je n’ai PAS beaucoup d’intérêt à jouer ou à créer des jeux vidéo
- J’ai un intérêt à créer des outils utiles (je suis développeur Web depuis DE NOMBREUSES années)
- Je ne suis PAS un des premiers à adopter
- Unity est une solution BIEN ÉTABLIE pour créer des expériences 3D multiplateformes
Avec tout cela à l’esprit, construire des solutions pratiques de Réalité augmentée (RA) alimentée par le Web avec Unity est quelque chose que je dois apprendre.
En ce qui concerne l’apprentissage de Unity, je N’AI PAS particulièrement trouvé les tutoriels officiels de Unity utiles. J’AI trouvé le cours Udemy Learn Unity 3D pour les débutants Absolus excellent.
Je naviguais à travers les matériaux et je me suis retrouvé accroché à la différence de leçon entre Update et FixedUpdate. En faisant des recherches un peu plus, le nœud du problème était que je ne comprenais pas la justification suivante.
Update(); Used Utilisé pour les mises à jour régulières telles que : Déplacement d’objets non physiques
FixedUpdate();… Utilisé pour les mises à jour régulières telles que: Ajustement des objets de physique (Corps rigide)
Tutoriels officiels Unity—Update et FixedUpdate—Unity
Un peu plus de recherches ont été effectuées :
En conclusion, mettez toute votre logique de jeu dans Update ou FixedUpdate. Ne pas mélanger et assortir les étapes temporelles à moins que vous ne soyez prêt à mordre la balle et à accepter un bégaiement. De plus, il est fortement intéressant d’envisager de mettre tous les états du jeu dans FixedUpdate, en utilisant la mise à jour exclusivement pour l’entrée de l’utilisateur, les effets visuels et l’interpolation entre les états du jeu. Bien que cela nécessite un changement dans la structure de vos jeux, il s’agit d’une structure de conception éprouvée avec de nombreux avantages.
— KinematicSoup —Timesteps et Réalisation de mouvements fluides dans Unity
Un clip vidéo dans l’article illustre le problème du mélange et de la correspondance des timesteps.
Avant de suivre ce conseil, je voulais recréer moi-même le problème du mélange et de la correspondance des temps.
La version finale du projet que j’ai utilisé pour écrire cet article est disponible en téléchargement.
Mise à jour par rapport à FixedUpdate
Nous devons commencer par une compréhension de base de la différence entre les méthodes Update et FixedUpdate. Pour illustrer, nous créons un objet de jeu vide appelé Setup et ajoutons le composant de script suivant :
Assets/Setup.cs (incomplet)
Notre sortie de console après 3 secondes ressemblait à:
Observations :
- La mise à jour est appelée avant chaque rendu ; la fréquence (fréquence d’images) varie en fonction de la complexité du rendu et du périphérique hôte. Les ordinateurs puissants peuvent atteindre des fréquences d’images supérieures à 150 images par seconde; mon ordinateur de développement fonctionnait à environ 50 images par seconde. En dessous de 30 fps, est considéré comme une expérience médiocre.
- FixedUpdate est appelé avant chaque mise à jour physique interne (déplacement de choses dues à la physique, par exemple la gravité). L’intervalle de temps fixe de Unity est par défaut de 0,02; entraîne l’appel de FixedUpdate 50 fois par seconde.
Simuler une fréquence d’images lente
Afin de simuler une fréquence d’images lente (10 images/s), nous mettons à jour la configuration.script cs comme suit :
Assets/Setup.cs (incomplet)
Notre sortie de console après 3 secondes ressemblait à:
Observations :
- Définir vSyncCount sur 0 désactive l’unité de synchronisation des rendus et des taux de rafraîchissement de l’écran.
- La fréquence d’images réelle peut être inférieure à la
TARGET_FRAME_RATE
en raison des limitations du périphérique hôte et de la complexité du rendu.
Animation manuelle
Afin d’observer l’effet des différentes animations, nous commençons par placer un cube fixe pour référence.
We add our first animated GameObject (Sphere) in front of it with the following script component.
Assets/Sphere.cs (incomplete)
Running it with the normal frame rate:
Running it with 10fps frame rate:
Observations:
- Évidemment, nous avons un problème. Nous ne voulons pas que la vitesse d’animation dépende de la fréquence d’images.
- Le problème est que nous réglons la VITESSE à 0,1 unité / trame; nous voulons que la vitesse soit mesurée en unités / seconde.
La solution consiste à fournir la VITESSE en unités d’unités / seconde; 0,1 unité / trame * 50 images / seconde = 5 unités / seconde. Ensuite, nous utilisons le Temps.deltaTime pour connaître l’heure depuis le dernier appel à mettre à jour. Ensuite, la distance parcourue est la VITESSE * deltaTime.
Actifs/Sphère.cs(incomplet)
Avec ce correctif en place, nous obtenons la même animation indépendamment de la fréquence d’images (mais avec 10 images par seconde, elle est saccadée comme prévu).
Après avoir utilisé la fréquence d’images réduite pour illustrer la nécessité de fournir une vitesse en unités / seconde, nous pouvons commenter les lignes en configuration.cs qui simule une fréquence d’images lente.
Animation en physique
Au lieu d’animer manuellement un objet de jeu, nous pouvons l’animer en lui appliquant la physique. On peut animer un cylindre (se déplaçant à droite de 5 unités / seconde) en:
- Créer un Plan (appelé Plan)
- Créer un Cylindre (appelé Cylindre)
- Ajouter un composant de Corps rigide au Cylindre (et figer la rotation dans toutes les directions)
- Créer un matériau physique, Glissant, sans frottement et l’appliquer à la fois au Cylindre et au Plan
- Démarrer le Cylindre avec une vitesse initiale à l’aide d’un composant de script
Actifs / Cylindre.cs
Avec cela en place, nous pouvons voir que la sphère et le cylindre se déplacent vers la droite au même rythme.
Observations :
- La position de la Sphère est mise à jour immédiatement avant le rendu (manuellement dans la méthode de mise à jour)
- La position du Cylindre est mise à jour dans la mise à jour physique interne.
Animation avec Animation
Une troisième façon d’animer un GameObject est avec une animation (évidemment). Nous pouvons animer une capsule (en essayant de se déplacer à droite de 5 unités / seconde) en:
- Créant une capsule (appelée Capsule)
- Créant un contrôleur d’animation (également Capsule) et en ajoutant en tant que composant à la Capsule GameObject.
- Création d’une animation (également Capsule).
- Dans le contrôleur d’animation, créez un état (Start) avec son mouvement pour être l’animation de la capsule.
- Enfin, nous animons la position pour que la position horizontale de la capsule soit de 5 unités en 1 seconde.
Avec cela en place, nous pouvons voir que la sphère, le cylindre, la capsule se déplacent (presque) vers la droite au même rythme.
Observations:
- Je ne sais pas pourquoi, mais la capsule s’est déplacée légèrement plus vite que prévu; les problèmes ont duré un certain temps et n’ont pas compris pourquoi.
- La position de la capsule peut être configurée pour être mise à jour avant le rendu (par défaut) ou pendant la mise à jour physique.
Implication d’une fréquence d’images rapide
Sur des ordinateurs puissants, on peut atteindre des fréquences d’images allant jusqu’à 150 images par seconde. Sur ces ordinateurs avec les mises à jour physiques par défaut 50 fois par seconde (0,02 seconde entre les mises à jour), les éléments mis à jour avant chaque rendu sont mis à jour plus fréquemment que ceux mis à jour dans les mises à jour physiques. Cette divergence est la source de problèmes de mélange et d’appariement des pas de temps.
Bien que je ne puisse pas augmenter la fréquence d’images de ma machine de développement (limitée à environ 50 images par seconde), je peux ralentir artificiellement les mises à jour physiques à 10 mises à jour par seconde (0.1 seconde entre les mises à jour) en utilisant les paramètres du projet.
Comme vous pouvez le voir, en mélangeant et en faisant correspondre les étapes temporelles, nous avons recréé le problème (mouvement incohérent entre les éléments du jeu).
Pour corriger, nous pouvons modifier l’animation de la Capsule pour mettre à jour les mises à jour physiques, et également mettre à jour le composant script de la Sphère comme suit:
Assets/Sphere.cs
Avec cela, toutes les animations sont constamment mises à jour avant chaque mise à jour physique.
Enfin, nous renvoyons notre mise à jour physique à 50 images par seconde (ou toutes les 0,02 seconde); obtenir des mises à jour cohérentes et opportunes.
Conclusions
Ayant, assez facilement, recréé le problème du mélange et de la correspondance des étapes temporelles, je me suis convaincu que je devrais mettre tout l’état du jeu dans les méthodes FixedUpdate.