Menu
CoddyTech

Gravité manuelle

Fait partie de la section Créer de vrais jeux du Journey Unity de Coddy. Leçon 39 sur 60.

Un CharacterController ne tombe que si ton script le fait tomber, et une vraie chute s'accélère : la gravité ajoute environ 9.81 unités par seconde à la vitesse de chute chaque seconde. Le script conserve donc la vitesse verticale dans un champ, lui ajoute gravity * Time.deltaTime à chaque frame, et se déplace en fonction de cette vitesse dans le même Move que la marche :

public float gravity = -9.81f;
float verticalSpeed;

void Update()
{
    if (controller.isGrounded && verticalSpeed < 0f)
    {
        verticalSpeed = -2f;   // au sol : arrêter la chute, maintenir une légère poussée vers le bas
    }
    verticalSpeed += gravity * Time.deltaTime;

    Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
    move.y = verticalSpeed;
    controller.Move(move * Time.deltaTime);
}

Time.deltaTime apparaît deux fois pour deux rôles : gravity * Time.deltaTime correspond à la vitesse gagnée pendant cette frame, et la vitesse multipliée par Time.deltaTime correspond à la distance parcourue pendant cette frame. La vitesse est un champ, car elle doit persister d'une frame à l'autre ; une variable locale repartirait de 0 à chaque frame. En tombant depuis l'arrêt, le contrôleur atteint -4.9 unités par seconde au bout d'une demi-seconde et -9.81 au bout d'une seconde.

La réinitialisation est aussi importante que la chute. Au sol, Move arrête le contrôleur, mais rien n'arrête le champ : sans la réinitialisation, sa valeur continue d'augmenter pendant que le joueur reste immobile, et le prochain pas dans le vide entraîne une chute à pleine vitesse. La vitesse est réinitialisée à un petit nombre négatif plutôt qu'à 0 afin que chaque Move continue d'exercer une pression vers le sol : à une fréquence d'images élevée, la poussée due à la gravité pendant une seule frame peut être inférieure à Min Move Distance ; Move ne fait alors rien et isGrounded devient false. isGrounded est lu avant Move, il décrit donc le Move de la frame précédente.

challenge icon

Défi

Moyen

Donne au plongeur une gravité pour que sa chute s’accélère.

  1. Au début de Update(), lorsque controller.isGrounded et que verticalSpeed < 0f, définis verticalSpeed = -1f;.
  2. Ajoute gravity * Time.deltaTime à cette valeur, et maintiens-la à -maxFall ou au-dessus avec Mathf.Max.
  3. Avant la ligne controller.Move, définis move.y = verticalSpeed;.

Appuie sur « Jouer » et marche jusqu’au bord de la tour : la chute s’accélère jusqu’à 10 unités par seconde. Puis clique sur « Vérifier ».

Essayez vous-même

using UnityEngine;

public class Diver : MonoBehaviour
{
    public float speed = 4f;
    public float gravity = -12f;
    public float maxFall = 10f;

    CharacterController controller;
    float verticalSpeed;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    void Update()
    {
        // Gravité : réinitialiser verticalSpeed au sol, ajouter la gravité, limiter la chute, puis placer le résultat dans move.y

        Vector3 move = new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")) * speed;
        controller.Move(move * Time.deltaTime);
    }
}

Toutes les leçons de Créer de vrais jeux

Entraînez-vous par vous-même : Playground Unity