简体   繁体   中英

Character doesn't jump sometimes - Unity

I am new to Unity and I am using the following CharacterController for my character. Everything is working well, except that sometimes the character jumps and sometimes it doesn't when I hit the spacebar. I used Debog.Log using Raycast to check if my character is grounded, and the result was True. So what is preventing my character from jumping whenever I hit the key?

using UnityEngine;
using System.Collections;
 
[RequireComponent(typeof(CharacterController))]
public class RPGMovement : MonoBehaviour
{
    public float ForwardSpeed = 8f;
    public float BackwardSpeed = 4f;
    public float StrafeSpeed = 5f;
    public float RotateSpeed = 110f;
 
    CharacterController m_CharacterController;
    Vector3 m_LastPosition;
    Animator m_Animator;
    PhotonView m_PhotonView;
    PhotonTransformView m_TransformView;
 
    float m_AnimatorSpeed;
    Vector3 m_CurrentMovement;
    float m_CurrentTurnSpeed;
 
    Vector3 playerVelocity;
    private bool groundedPlayer;
    private float jumpHeight = 0.9f;
    private float gravityValue = -20.81f;
 
    void Start()
    {
        m_CharacterController = GetComponent<CharacterController>();
        m_Animator = GetComponent<Animator>();
        m_PhotonView = GetComponent<PhotonView>();
        m_TransformView = GetComponent<PhotonTransformView>();
    }
 
    void Update()
    {
        if (m_PhotonView.isMine == true)
        {
            ResetSpeedValues();
            UpdateRotateMovement();
            UpdateForwardMovement();
            UpdateBackwardMovement();
            UpdateStrafeMovement();          
            MoveCharacterController();
            UpdateJump();
            ApplySynchronizedValues();
        }
        UpdateAnimation();
    }
 
    void UpdateAnimation()
    {
        Vector3 movementVector = transform.position - m_LastPosition;
 
        float speed = Vector3.Dot(movementVector.normalized, transform.forward);
        float direction = Vector3.Dot(movementVector.normalized, transform.right);
 
        if (Mathf.Abs(speed) < 0.2f)
        {
            speed = 0f;
        }
 
        if (speed > 0.6f)
        {
            speed = 1f;
            direction = 0f;
        }
 
        if (speed >= 0f)
        {
            if (Mathf.Abs(direction) > 0.7f)
            {
                speed = 1f;
            }
        }
 
        m_AnimatorSpeed = Mathf.MoveTowards(m_AnimatorSpeed, speed, Time.deltaTime * 5f);
 
        m_Animator.SetFloat("Speed", m_AnimatorSpeed);
        m_Animator.SetFloat("Direction", direction);
 
        m_LastPosition = transform.position;
    }
 
    void ResetSpeedValues()
    {
        m_CurrentMovement = Vector3.zero;
        m_CurrentTurnSpeed = 0;
    }
 
    void ApplySynchronizedValues()
    {
        m_TransformView.SetSynchronizedValues(m_CurrentMovement, m_CurrentTurnSpeed);
    }
 
    void MoveCharacterController()
    {
        m_CharacterController.Move(m_CurrentMovement * Time.deltaTime);
    }
 
    void UpdateForwardMovement()
    {
        if (Input.GetKey(KeyCode.W) || Input.GetAxisRaw("Vertical") > 0.1f)
        {
            m_CurrentMovement = transform.forward * ForwardSpeed;
        }
    }
 
    void UpdateBackwardMovement()
    {
        if (Input.GetKey(KeyCode.S) || Input.GetAxisRaw("Vertical") < -0.1f)
        {
            m_CurrentMovement = -transform.forward * BackwardSpeed;
        }
    }
 
    void UpdateStrafeMovement()
    {
        if (Input.GetKey(KeyCode.Q) == true)
        {
            m_CurrentMovement = -transform.right * StrafeSpeed;
        }
 
        if (Input.GetKey(KeyCode.E) == true)
        {
            m_CurrentMovement = transform.right * StrafeSpeed;
        }
    }
 
    void UpdateRotateMovement()
    {
        if (Input.GetKey(KeyCode.A) || Input.GetAxisRaw("Horizontal") < -0.1f)
        {
            m_CurrentTurnSpeed = -RotateSpeed;
            transform.Rotate(0.0f, -RotateSpeed * Time.deltaTime, 0.0f);
        }
 
        if (Input.GetKey(KeyCode.D) || Input.GetAxisRaw("Horizontal") > 0.1f)
        {
            m_CurrentTurnSpeed = RotateSpeed;
            transform.Rotate(0.0f, RotateSpeed * Time.deltaTime, 0.0f);
        }
    }
 
    void UpdateJump()
    {
      groundedPlayer = m_CharacterController.isGrounded;
        if (groundedPlayer && playerVelocity.y < 0)
        {
            playerVelocity.y = 0f;
        }
 
        if (Input.GetButtonDown("Jump") && groundedPlayer)
        {
            playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
            m_Animator.SetTrigger("Jump");
            print("Jumping Now");
        }
 
        playerVelocity.y += gravityValue * Time.deltaTime;
        m_CharacterController.Move(playerVelocity * Time.deltaTime);
    }
}

Best guess is that "m_PhotonView.isMine" is not returning true on the frames where you're missing input. It only checks jump input for that frame, so if the last frame you pressed it but jumping wasn't checked then that input is lost forever. First test this. Change the update code to this:

void Update()
{
    if (Input.GetButtonDown("Jump")) { Debug.Log("Jump was pressed at {Time.time}"); }
    if (m_PhotonView.isMine == true)
    {
        if (Input.GetButtonDown("Jump")) { Debug.Log("Attempting Jump at {Time.time}"); }
        ResetSpeedValues();
        UpdateRotateMovement();
        UpdateForwardMovement();
        UpdateBackwardMovement();
        UpdateStrafeMovement();          
        MoveCharacterController();
        UpdateJump();
        ApplySynchronizedValues();
    }
    UpdateAnimation();
}

Then play the game and jump a bunch. The first debug log line should happen every time you click the spacebar no matter what. The second debug line would only happen if physics are calculated that frame. Both have times attached. Keep jumping until the jump doesn't work. If that jump only produces the first debug log and not the second, then I am correct and that is your issue.

If so, then it's an easy fix. Add a new bool variable called "jumpInput". Whenever you check if jump was pressed, instead check if "jumpInput" is true. Then, change update to this:

void Update()
{
    if (Input.GetButtonDown("Jump")) { jumpInput = true; }
    if (m_PhotonView.isMine == true)
    {
        ResetSpeedValues();
        UpdateRotateMovement();
        UpdateForwardMovement();
        UpdateBackwardMovement();
        UpdateStrafeMovement();          
        MoveCharacterController();
        UpdateJump();
        ApplySynchronizedValues();
        jumpInput = false;
    }
    UpdateAnimation();
}

This way if you pressed jump, it's set to true... but it's only set to false after physics are done. So if you press jump on frame 20 and physics are somehow not calculated until frame 25, it'll still know that you pressed jump at some point and thus execute it. If you're using networking, you might want to also have another variable that's what frame jump was pressed. That way you can figure out how many frames it's been since input and compensate for missed time in the jump if necessary.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM