K
K
KaRaMiD2021-07-19 15:04:46
3D
KaRaMiD, 2021-07-19 15:04:46

How to make correct isGrounded in Unity 3D?

When I just stand on the surface, everything is fine
60f56994699fb357158279.png
. But when I just start to go to another surface, then for some reason isGrounded changes to false and I levitate.
60f569fb49b18843456815.png
Here is the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
    public Animator anim;
    public Rigidbody rig;
    public Transform mainCamera;

    private PlayerMotor motor;

    public float speedCharacter = 5f;
    public float runningSpeed = 6f;
    private float curVertSpeed;
    public float currentSpeed;

    public float jumpCount;
    private bool isGrounded;
    private readonly Vector3 jumpDirection = Vector3.up;
    private float animationInterpolation = 1f;

    private bool runTrue;

    void Start()
    {
        motor = GetComponent<PlayerMotor>();
        anim = GetComponent<Animator>();
        this.rig = GetComponent<Rigidbody>();

        // Прекрепляем курсор к середине экрана
        Cursor.lockState = CursorLockMode.Locked;
        // и делаем его невидимым
        Cursor.visible = false;
    }

    void OnCollisionEnter(Collision other)
    {
        var ground = other.gameObject.GetComponentInParent<Ground>();
        if (ground)
            this.isGrounded = true;
            anim.SetBool("InAir", false);
            runTrue = true;
    }

    void OnCollisionExit(Collision other)
    {
        var ground = other.gameObject.GetComponentInParent<Ground>();
        if (ground)
            this.isGrounded = false;
            anim.SetBool("InAir", true);
            runTrue = false;
    }

    void Run()
    {
        if (runTrue)
        {
            animationInterpolation = Mathf.Lerp(animationInterpolation, 1.5f, Time.deltaTime * 3);
            anim.SetFloat("x", Input.GetAxis("Horizontal") * animationInterpolation);
            anim.SetFloat("y", Input.GetAxis("Vertical") * animationInterpolation);

            currentSpeed = Mathf.Lerp(currentSpeed, runningSpeed, Time.deltaTime * 3);
        }
    }

    void Walk()
    {
        // Mathf.Lerp - отвчает за то, чтобы каждый кадр число animationInterpolation(в данном случае) приближалось к числу 1 со скоростью Time.deltaTime * 3.
        // Time.deltaTime - это время между этим кадром и предыдущим кадром. Это позволяет плавно переходить с одного числа до второго НЕЗАВИСИМО ОТ КАДРОВ В СЕКУНДУ (FPS)!!!
        animationInterpolation = Mathf.Lerp(animationInterpolation, 1f, Time.deltaTime * 3);
        anim.SetFloat("x", Input.GetAxis("Horizontal") * animationInterpolation);
        anim.SetFloat("y", Input.GetAxis("Vertical") * animationInterpolation);

        currentSpeed = Mathf.Lerp(currentSpeed, speedCharacter, Time.deltaTime * 3);
    }

    void Jump()
    {
        if (this.isGrounded)
        {
            this.rig.AddForce(this.jumpDirection * this.jumpCount, ForceMode.Impulse);
        }
    }

    void FixedUpdate()
    {
        if (isGrounded)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Jump();
            }
        }
        
        // Устанавливаем поворот персонажа когда камера поворачивается 
        transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles.x, mainCamera.rotation.eulerAngles.y, transform.rotation.eulerAngles.z);
        if (isGrounded)
            // Зажаты ли кнопки W и Shift?
            if (Input.GetKey(KeyCode.W) && Input.GetKey(KeyCode.LeftShift))
            {
                // Зажаты ли еще кнопки A S D?
                if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.D))
                {
                    Run();
                    runTrue = true;
                }
                if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.LeftShift))
                {
                    Run();
                    runTrue = true;
                }
                // Если нет, то тогда бежим!    
                else
                {
                    Run();
                    runTrue = true;
                }
            }
        // Если W & Shift не зажаты, то мы просто идем пешком
        else
        {
            Walk();
            runTrue = false;
        }
        // Здесь мы задаем движение персонажа в зависимости от направления в которое смотрит камера
        // Сохраняем направление вперед и вправо от камеры 
        Vector3 camF = mainCamera.forward;
        Vector3 camR = mainCamera.right;
        // Чтобы направления вперед и вправо не зависили от того смотрит ли камера вверх или вниз, иначе когда мы смотрим вперед, персонаж будет идти быстрее чем когда смотрит вверх или вниз
        // Можете сами проверить что будет убрав camF.y = 0 и camR.y = 0 :)
        camF.y = 0;
        camR.y = 0;
        Vector3 movingVector;
        // Тут мы умножаем наше нажатие на кнопки W & S на направление камеры вперед и прибавляем к нажатиям на кнопки A & D и умножаем на направление камеры вправо
        movingVector = Vector3.ClampMagnitude(camF.normalized * Input.GetAxis("Vertical") * currentSpeed + camR.normalized * Input.GetAxis("Horizontal") * currentSpeed, currentSpeed);
        // Magnitude - это длинна вектора. я делю длинну на currentSpeed так как мы умножаем этот вектор на currentSpeed на 86 строке. Я хочу получить число максимум 1.
        anim.SetFloat("magnitude", movingVector.magnitude / currentSpeed);
        Debug.Log(movingVector.magnitude / currentSpeed);
        // Здесь мы двигаем персонажа! Устанавливаем движение только по x & z потому что мы не хотим чтобы наш персонаж взлетал в воздух
        rig.velocity = new Vector3(movingVector.x, rig.velocity.y, movingVector.z);
        // У меня был баг, что персонаж крутился на месте и это исправил с помощью этой строки
        rig.angularVelocity = Vector3.zero;
    }
    
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
V
Vasily Bannikov, 2021-07-19
@vabka

void OnCollisionEnter(Collision other)
    {
        var ground = other.gameObject.GetComponentInParent<Ground>();
        if (ground)
            this.isGrounded = true;
        anim.SetBool("InAir", false);
        runTrue = true;
    }

    void OnCollisionExit(Collision other)
    {
        var ground = other.gameObject.GetComponentInParent<Ground>();
        if (ground)
            this.isGrounded = false;
        anim.SetBool("InAir", true);
        runTrue = false;
    }

Apparently that slope is not Ground, that's why your code does isGounded=false;
As an option - check somehow that the lower part of the legs touches at least something that you can stand on.
PS: just now I noticed, but your indents are crooked.
When you exit a collision with something, the flight animation will always turn on, and when you enter a collision, it will turn off, regardless of what the collision happened with.

S
Spartanec33, 2021-07-19
@Spartanec33

mb on this surface is missing a Ground component?

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question