Address
304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

Unity MoveTowards presentation

Unity MoveTowards – Déplacer vos GameObjects

Sur Unity, la méthode statique MoveTowards de la structure Vector3 nous permet de déplacer notre GameObject avec un effet smooth vers une position cible en spécifiant une distance maximale à parcourir par trame.

Table des matières

Utilisation basique de MoveTowards

MoveTowards renvoie un Vector3 et a trois paramètres : une position de départ (généralement la position de votre GameObject), une position cible à atteindre, et enfin, une distance maximale à parcourir.

Le Vector3 retourné prend la position de départ et se rapproche de la position cible avec la distance maximale spécifiée.

Exemple avec 2 positions:

var position = Vector3.MoveTowards(Vector3.zero, new Vector3(0f, 5f, 0f), 1f); 
// position = new Vector3(0f, 1f, 0f)

Comment faire déplacer un objet vers un autre objet ?

MoveTowards est parfait pour cette tâche ; nous devons simplement l’implémenter dans une fonction Update :

using UnityEngine;

public class MoveCharacter : MonoBehaviour
{
    [SerializeField]
    private GameObject _targetGameObject;

    private float _speed = 3f;

    private void Update()
    {
        transform.position = Vector3.MoveTowards(transform.position, _targetGameObject.transform.position, Time.deltaTime * _speed);

        if (Vector3.Distance(transform.position, _targetGameObject.transform.position) < 0.001f)
        {
            // Notre GameObject a atteint la cible
        }
    }
}

Remarque : Cet exemple peut être amélioré en référençant directement le Transform de notre cible.

Time.deltaTime nous permet de synchroniser indépendamment des fps :

Unity MoveTowards avec Time.deltaTime

Accélération dans Unity

Pour obtenir une accélération dépendante de la trame, nous devons multiplier la vitesse à ajouter avant et après MoveTowards en la divisant par 2 :

using UnityEngine;

public class MoveCharacter : MonoBehaviour
{
    [SerializeField]
    private GameObject _targetGameObject;

    private float _speed = 3f;

    private void Update()
    {
        float vitesseIncrementale = 0.1f;

        _speed += vitesseIncrementale * Time.deltaTime * 0.5f;
        transform.position = Vector3.MoveTowards(transform.position, _targetGameObject.transform.position, Time.deltaTime * _speed);
        _speed += vitesseIncrementale * Time.deltaTime * 0.5f;
    }
}

Pour plus de détails sur les accélérations et Time.deltaTime en général, je recommande cette vidéo :

Youtube – Jonas Tyroller – Dear Game Developers, Stop Messing This Up!

Remplacer la vitesse par la durée avec MoveTowards

Pour accomplir un déplacement sur une durée définie, bien que MoveTowards soit une option viable, je recommande d’utiliser Lerp à la place, comme indiqué immédiatement après cette approche.
Au lieu d’entrer une distance, nous optons pour insérer une vélocité par trame (frame), en suivant ces étapes :

  1. Tout d’abord, nous évaluons la distance entre les deux points en utilisant Vector3.distance.
  2. Cela nous permet de calculer la distance parcourue par seconde : « distance / durée« .
  3. Enfin, cette distance est multipliée par Time.deltaTime pour obtenir une vélocité par trame (frame).
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class MoveByDuration : MonoBehaviour
{
    [SerializeField]
    private Vector3 _position;

    private void Start()
    {
        StartCoroutine(MovetowardsDuration(3f));

        // si vous préférez async
        // MoveAsync(3f);
    }

    private IEnumerator MovetowardsDuration(float duration)
    {
        float distance = Vector3.Distance(transform.position, _position);
        float distanceBySeconds = distance / duration;

        float startTime = 0;

        while (startTime < duration)
        {
            transform.position = Vector3.MoveTowards(transform.position, _position, distanceBySeconds * Time.deltaTime);
            startTime += Time.deltaTime;
            yield return null;
        }
    }

    // async
    private async void MoveAsync(float duration)
    {
        float distance = Vector3.Distance(transform.position, _position);
        float distanceBySeconds = distance / duration;

        float startTime = 0;

        while (startTime < duration)
        {
            transform.position = Vector3.MoveTowards(transform.position, _position, distanceBySeconds * Time.deltaTime);
            startTime += Time.deltaTime;
            await Task.Yield();
        }
    }
}

Dans ce contexte, je préfère utiliser la méthode Lerp. L’interpolation linéaire qu’elle effectue nous permet d’obtenir directement notre position en fonction du temps écoulé.

Pour cela, nous avons seulement besoin d’incrémenter un compteur de temps avec Time.deltaTime à chaque trame (frame), puis diviser ce compteur par la durée pour obtenir une valeur de temps entre 0 et 1.

using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class LerpTest : MonoBehaviour
{
    [SerializeField]
    private Vector3 _positionTarget;

    private void Start()
    {
        StartCoroutine(Lerp(3f));
    }

    private IEnumerator Lerp(float duration)
    {
        float start = 0;
        var startPosition = transform.position;

        while (start < duration)
        {
            transform.position = Vector3.Lerp(startPosition, _positionTarget, start / duration);
            start += Time.deltaTime;
            yield return null;
        }
    }

    // Si vous préférez async
    private async void LerpAsync(float duration)
    {
        float start = 0;
        var startPosition = transform.position;

        while (start < duration)
        {
            transform.position = Vector3.Lerp(startPosition, _positionTarget, start / duration);
            start += Time.deltaTime;
            await Task.Yield();
        }
    }
}

Cette alternative offre une transition toute trouvée vers le sujet suivant :

Quelle est la différence entre LERP et MoveTowards ?

  • Lerp interpole linéairement entre deux points (retourne un point intermédiaire selon un coefficient t allant de 0 à 1) utilisé pour obtenir un mouvement avec une décélération croissante.
  • MoveTowards déplace un point vers un autre point cible, en tenant compte d’une distance maximale, permettant des effets fluides dans les mouvements.

De plus, MoveTowards est principalement utilisé pour les déplacements, tandis que Lerp est utilisé dans tous les aspects du gameplay, permettant des transitions, des changements de direction, et plus encore.

Pour conclure, la méthode MoveTowards d’Unity offre un outil polyvalent pour obtenir des mouvements d’objets fluides avec des limites de vitesse spécifiées. On peut noter aussi que la compréhension des nuances entre Lerp et MoveTowards est une étape importante dans Unity.

Merci d’avoir lu et bon codage !

Consultez mes autres articles sur Unity :

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *