Niveau 3: Input, on bouge enfin! --- Comment déplacer un objet.

Dans la page précédente, je vous ai expliqué qu'il existe deux façons de lire les entrées. Je vous ai brièvement présenté la première méthode, mais avant de poursuivre avec la seconde, qui utilise le New Input System, nous allons d'abord apprendre à déplacer nos personnages. 

Deux choix, deux objectifs

Dans Unity, il existe deux façons de déplacer un objet :

  1. La première consiste à recalculer la position de l'objet à chaque frame.
  2. La deuxième consiste à utiliser le composant RigidBody de l'objet, ce qui permet au moteur physique de calculer la vitesse.

Pour l'instant, nous allons nous concentrer sur la première méthode, à savoir recalculer nous-mêmes la position de l'objet.

Préparation de notre scène

Pour tester notre code, nous allons avoir besoin d'une grande surface. Créez un plane et agrandissez-le. Un scale de 25 sur tous les axes devrait suffire. N'oubliez pas d'ajouter un matériau texturé à votre plane, cela nous aidera à observer le mouvement plus clairement.

Ensuite, créez une sphère. Cette sphère représentera notre personnage. Ajoutez également un matériau avec une texture pour pouvoir plus facilement observer comment elle se déplace.

Comment modifier la position ?

Notre objectif est de simuler un déplacement en modifiant la propriété position du composant transform.

Nous allons donc ajouter un Vector3 à notre composant transform.position. Voici un exemple de code :

using UnityEngine;

public class Move : MonoBehaviour
{
	public Vector3 vitesse;

    void Start()
    {
        transform.position += vitesse;
    }

    void Update()
    {

    }
}

La position d'un objet dans l'inspecteur comporte trois valeurs correspondant aux directions d'un espace 3D. C'est pourquoi nous déclarons une variable de type Vector3.

Maintenant, modifions la variable vitesse dans l'inspecteur.

Une fois vos modifications effectuées, appuyez sur Play. Votre sphère se déplace. Si vous augmentez encore la valeur d'un des axes du Vector3, le déplacement sera d'autant plus grand, selon les axes que vous avez modifiés. Maintenant, déplacez le code dans la méthode Update.

using UnityEngine;

public class Move : MonoBehaviour
{
	public Vector3 vitesse;

    void Start()
    {

    }

    void Update()
    {
	  transform.position += vitesse;
    }
}

Cette fois, la sphère se déplacera à chaque frame.

Remarque :Je vous rappelle que la méthode Update s'exécute en boucle très rapidement, en fonction des capacités de votre ordinateur. En général, votre machine va exécuter environ 60 frames par seconde, ce qui signifie que si votre vector a pour valeurs X: 1, Y: 0, Z: 0, vous allez vous déplacer de 60 mètres par seconde sur l'axe des X ! C'est beaucoup trop rapide, et votre sphère a probablement disparu une fois que vous avez lancé Play.

Solution incorrecte

Afin d'obtenir une vitesse "normale", vous pouvez réduire la valeur à un nombre très petit. Par exemple, choisissez les valeurs X: 0.1, Y: 0, Z: 0. Cette fois, la sphère se déplacera lentement sur l'axe des X. Cependant, gardez à l'esprit que la vitesse d'exécution de la méthode Update dépend de l'ordinateur du joueur. Cela signifie que la vitesse sera variable en fonction du PC utilisé, ce qui n'est donc pas la meilleure solution.

La bonne solution : Time.deltaTime

La solution idéale consiste à multiplier notre variable vitesse par Time.deltaTime. Cette variable particulière représente le nombre de secondes écoulées depuis la dernière frame.

Si votre ordinateur est lent, la méthode Update s'exécutera moins rapidement, ce qui augmentera le temps entre deux frames. Cela aura pour effet d'augmenter la valeur de Time.deltaTime, qui, multipliée à vitesse, fera que la sphère se déplacera plus loin entre deux frames.

À l'inverse, si l'ordinateur est rapide, le temps entre les frames sera court, ce qui réduira la valeur de Time.deltaTime, et l'objet se déplacera moins loin entre les frames.

Ainsi, au bout d'un certain temps, les deux objets auront parcouru la même distance. En d'autres termes, un ordinateur rapide effectuera de nombreux petits déplacements, tandis qu'un ordinateur lent en effectuera moins, mais avec des distances plus grandes pour compenser.

Voici le code à tester :

using UnityEngine;

public class Move : MonoBehaviour
{
	public Vector3 vitesse;

    void Start()
    {

    }

    void Update()
    {
	  transform.position += vitesse * Time.deltaTime;
    }
}

Maintenant, tous les joueurs auront la même vitesse, indépendamment des capacités de leurs machines.  

Les terribles "bugs"

Amusons-nous un peu... Ajoutez un mur sur le trajet de la sphère en créant un cube. Sur votre sphère et votre mur, ajoutez un composant de type RigidBody et désactivez la gravité. Modifiez la masse du cube pour la mettre à 10 000 ou bloquez sa position. Cela évitera que la sphère repousse le mur pendant son déplacement.

Normalement, lorsque vous lancez Play, tout fonctionne bien. La sphère s'arrête sur le mur. Maintenant, augmentez la vitesse de manière significative. Par exemple, j'ai réglé la vitesse à X: 40, Y: 0, Z: 0.

Cette fois, la sphère traverse le mur !

Si vous pensez que cela est un bug, détrompez-vous. Prenons un moment pour comprendre pourquoi cela se produit.

Nous déplaçons notre objet en modifiant la valeur du transform, ce qui revient à "téléporter" l'objet. Lorsque l'objet se déplace dans un autre objet, Unity repositionne normalement l'objet en fonction de la collision. Cependant, si la vitesse est trop élevée, cela équivaut à de plus grands "sauts" lors de la téléportation, ce qui peut faire que l'objet se retrouve derrière un obstacle et ne le touche donc pas. Unity ne peut pas deviner qu'il y avait un objet entre la position initiale et la position finale, ce qui permet à l'objet de traverser le mur.

Ce problème peut être plus accentué sur un ordinateur lent, car l'objet effectue des déplacements plus grands avec chaque "saut".

Heureusement, il existe plusieurs solutions à ce problème, mais nous ne les aborderons pas dans ce chapitre, car elles nécessitent l'apprentissage de nouveaux concepts comme le système de rayons. Sachez simplement que si vous rencontrez ce problème, cela signifie probablement que votre personnage se déplace trop rapidement via le transform. 

FixedUpdate

Jusqu'ici, nous avons utilisé la méthode Update pour déplacer un objet au fil du temps, mais ce n'est pas l'idéal. En général, il est préférable d'utiliser la méthode FixedUpdate.

Cette méthode fonctionne de manière similaire à Update, mais sa vitesse d'exécution dépend de la configuration du moteur physique. Lorsque vous utilisez des éléments physiques dans votre jeu, comme la gravité ou les collisions, la physique est calculée un certain nombre de fois par seconde. Par défaut, ce nombre est de 50 frames par seconde. 

En déplaçant votre personnage dans la méthode FixedUpdate, vous synchronisez le déplacement avec le moteur physique, ce qui permet d'éviter de nombreux problèmes. Vous pouvez observer l'un de ces "bug" en examinant de près la collision entre la sphère et le mur.

Si vous effectuez le déplacement dans Update, vous remarquerez que la sphère semble constamment se repositionner et se déplace de manière saccadée. 

En déplaçant le code dans FixedUpdate, comme ceci :

using UnityEngine;

public class Move : MonoBehaviour
{
	public Vector3 vitesse;

    void Start()
    {

    }

    void Update()
    {

    }

    void FixedUpdate()
    {
	transform.position += vitesse * Time.deltaTime;
    }
}

Le problème est résolu. Mais pourquoi ? La méthode Update s'exécute plus fréquemment, avant les calculs du moteur physique qui gère les collisions. Vous avez donc deux frames distinctes : Update déplace la sphère et affiche le résultat, puis Unity détecte la collision, recalcule la position et affiche le résultat.

En utilisant FixedUpdate, le déplacement et la détection des collisions sont effectués sur la même frame. Unity calcule d'abord le déplacement, puis la collision, puis recalcule la position et affiche le résultat, tout cela sur la même frame, ce qui empêche la sphère de se repositionner constamment.

Time.deltaTime dans FixedUpdate : est-ce obligatoire ?

Maintenant que vous utilisez FixedUpdate, il n'est plus nécessaire d'utiliser Time.deltaTime. En effet, tous les joueurs auront un maximum de 50 FPS (ou un autre nombre, selon vos paramètres). Votre jeu tournera donc de manière synchronisée avec le moteur physique, ce qui évite des variations de vitesse dues à des différences de performance.

Cependant, si votre jeu ralentit (par exemple, si la scène est trop lourde), cela pourrait provoquer des variations de vitesse. Dans ce cas, il n'y a pas de solution unique : vous devrez tester et choisir ce qui convient le mieux pour votre projet. Pour ma part, je préfère tout de même utiliser Time.deltaTime dans cette méthode, car les FPS oscillent souvent légèrement. Et cela permet au joueur d'estimer plus facilement le comportement du jeu lorsqu'un tel événement se produit. 

Évidemment, le meilleur choix serait d'optimiser son jeu pour éviter les ralentissements, mais ce n'est pas toujours facile. 

En conclusion

Nous avons vu que nous pouvons simuler un déplacement en modifiant le transform d'un objet, et qu'il est préférable de déplacer notre code dans la méthode FixedUpdate pour synchroniser le déplacement avec le moteur physique. Nous avons également appris que la variable Time.deltaTime permet d'obtenir le nombre de secondes écoulées entre deux frames, et qu'elle peut être utilisée pour rendre la vitesse constante, indépendamment du nombre de FPS. 

Dans la prochaine page, nous explorerons la deuxième méthode de déplacement, qui utilise le moteur physique.

À bientôt !

Cette page ne contient pas de Fichier à Télécharger.

Les cours vous ont aidé et vous souhaitez à votre tour nous aider ?

- - - Vous pouvez partager le site avec vos connaissances, ainsi que le Discord. - - -

- - - Participer à la vie active du site et du Discord. - - -

- - - Faire un petit don pour nous aider à payer le serveur avec le lien ci-dessous. - - -

Buy Me a Coffee at ko-fi.com