简体   繁体   中英

Mid-air movement with first person controller in Unity3D, c#

I'm currently trying to enable mid-air movement in this first person character controller I've tried to implement in my project. Currently, the player loses all movement control when in the air.

I've tried to copy the normal movement controls within the jump mechanic, but to no avail. I apologise for the simplicity of the question, I am very much a novice when it comes to coding.

Big thanks in advance to everyone who's read this :)

   [SerializeField] private string verticalInputName;
   [SerializeField] private float movementSpeed;

   private CharacterController charController;

   [SerializeField] private AnimationCurve jumpFallOff;
   [SerializeField] private float jumpMultiplier;
   [SerializeField] private KeyCode jumpKey;


   private bool isJumping;

   private void Awake()
   {
       charController = GetComponent<CharacterController>();
   }

   private void Update()
   {
       PlayerMovement();
   }

   private void PlayerMovement()
   {
       float horizInput = Input.GetAxis(horizontalInputName) * movementSpeed;
       float vertInput = Input.GetAxis(verticalInputName) * movementSpeed;

       Vector3 forwardMovement = transform.forward * vertInput;
       Vector3 rightMovement = transform.right * horizInput;

       charController.SimpleMove(forwardMovement + rightMovement);

       JumpInput();

   }

   private void JumpInput()
   {
       if (Input.GetKeyDown(jumpKey) && !isJumping)
       {
           isJumping = true;
           StartCoroutine(JumpEvent());
       }
   }

   private IEnumerator JumpEvent()
   {
       charController.slopeLimit = 90.0f;
       float timeInAir = 0.0f;


       do
       {

           float jumpForce = jumpFallOff.Evaluate(timeInAir);
           charController.Move(Vector3.up * jumpForce * jumpMultiplier * Time.deltaTime);

           timeInAir += Time.deltaTime;

           yield return null;
       } while (!charController.isGrounded && charController.collisionFlags != CollisionFlags.Above);

       float horizInput = Input.GetAxis(horizontalInputName) * movementSpeed;
       float vertInput = Input.GetAxis(verticalInputName) * movementSpeed;

       Vector3 forwardMovement = transform.forward * vertInput;
       Vector3 rightMovement = transform.right * horizInput;

       charController.SimpleMove(forwardMovement + rightMovement);
       isJumping = false;
   }
}

The documentation recommends only calling Move or SimpleMove once per frame, but you're calling both of them during every frame of the jump between the coroutine and PlayerMovement .

You should move your jump logic outside of the coroutine so you can do your jump routine logic before every call and then do a single call to Move / SimpleMove that includes calculations from the jump logic and the player's input.

Here's one way to reduce your use of Move / SimpleMove down to just one call per frame:

[SerializeField] private string horizontalInputName;
[SerializeField] private string verticalInputName;
[SerializeField] private float movementSpeed;

private CharacterController charController;

[SerializeField] private AnimationCurve jumpFallOff;
[SerializeField] private float jumpMultiplier;
[SerializeField] private KeyCode jumpKey;


private bool isJumping = false;
private float timeInAir = 0.0f;

private void Awake()
{
    charController = GetComponent<CharacterController>();
}

private void Update()
{
    PlayerMovement();
}

private void PlayerMovement()
{
    float forwardInput = Input.GetAxis(verticalInputName);
    float rightInput = Input.GetAxis(horizontalInputName);

    Vector3 forwardMovement = transform.forward * forwardInput;
    Vector3 rightMovement = transform.right * rightInput;
    Vector3 horizMovement = (forwardMovement+rightMovement) * movementSpeed;

    float jumpVelocity = JumpInput();

    if (isJumping)
    {
        Vector3 vertMovement = Vector3.up * jumpVelocity * jumpMultiplier;
        charController.Move((horizMovement + vertMovement) * Time.deltaTime) 
    } 
    else
    {
        charController.SimpleMove(horizMovement);
    }
}

private float JumpInput()
{
    float jumpVelocity = 0f;

    if (Input.GetKeyDown(jumpKey) && !isJumping)
    {
        isJumping = true;
        charController.slopeLimit = 90.0f;
        timeInAir = 0f;
    }

    if (isJumping){
        if (timeInAir == 0f || 
               (!charController.isGrounded 
                && charController.collisionFlags != CollisionFlags.Above))
        {
            jumpVelocity = jumpFallOff.Evaluate(timeInAir);
            timeInAir += Time.deltaTime;
        } 
        else
        {
            ifJumping = false;
        }
    }

    return jumpVelocity;
}

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