Задать вопрос
KaRaMiD
@KaRaMiD
Хочу научится делать игры на Unity

Как сделать правильный isGrounded в Unity 3D?

Когда я просто стою на поверхности то все нормально
60f56994699fb357158279.png
Но когда я только начинаю заходить на другую поверхность то isGrounded почему-то меняется на false и я левитирую.
60f569fb49b18843456815.png
Вот код:
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;
    }
    
}
  • Вопрос задан
  • 1443 просмотра
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
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;
    }


Видимо тот скат не является Ground, по тому твой же код и делает isGounded=false;
Как вариант - проверяй как-нибудь, что нижняя часть ног касается хоть чего-то, на чём можно стоять.

PS: только сейчас заметил, но у тебя криво расставлены отступы.
Вы выходе из коллизии с чем-либо у тебя всегда будет включаться анимация полёта, а при входе в коллизию - она будет выключаться, не зависимо от того, с чем произошла коллизия.
Ответ написан
@Spartanec33
мб на этой поверхности отсутсвует компонент Ground?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы