0
\$\begingroup\$

So I have a bit of an issue with my Player controller script. Everything works fine except with very specific jump cases. If I jump at an object and I don't reach the top edge I will just fall normally with no issue. However, when the object is short enough for me to possible jump on top of it, if I collide with its side when jumping my player will halt in that spot, jitter for a second and then fall normally.

Here is my code:

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

public class ThirdPersonPlayerController : MonoBehaviour
{
    public CharacterController controller;
    public Transform camera;
    public Transform groundCheck;

    Vector3 direction;
    Vector3 velocity;

    public float moveSpeed = 10f;
    public float turnSmoothTime = 0.1f;
    private float turnSmoothVelocity;
    public float gravity = -39.24f;
    public float groundDistance = 0.4f;
    public float jumpHeight = 3f;

    public LayerMask groundMask;
    private bool isGrounded;

    // Update is called once per frame
    // Unity is currently working on a new input system***
    private void Update()
    {
        IsPlayerGrounded();

        float horizontal = Input.GetAxisRaw("Horizontal");
        float vertical = Input.GetAxisRaw("Vertical");
        direction = new Vector3(horizontal, 0f, vertical).normalized; // direction player is moving

        if (Input.GetButtonDown("Jump") && isGrounded)
        {
            Jump();
        }

        MoveAndRotate();
        Gravity();
    }
    

    private void MoveAndRotate()
    {
        if (direction.magnitude >= 0.1f)
        {
            float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + camera.eulerAngles.y;
            float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
            transform.rotation = Quaternion.Euler(0f, angle, 0f);

            Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
            controller.Move(moveDirection.normalized * moveSpeed * Time.deltaTime);
        }
    }

    // Implemented proper gravity from /_\ y = 1/2g * t^2
    private void Gravity()
    {
        velocity.y += gravity * Time.deltaTime;

        controller.Move(velocity * Time.deltaTime);
    }

    // Check if player is grounded and reset velocity 
    private void IsPlayerGrounded()
    {
        isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);

        if (isGrounded && velocity.y < 0)
        {
            velocity.y = -2f;
        }
    }

    private void Jump()
    {
        velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
    }

    // Current issue (Not yet fixed): When jumping against a wall the player will stick/jitter (starts to jitter at the top edge). 
}

Here is a visual representation of what I mean by colliding near its top edge enter image description here

Any help at all is greatly appreciated. Note: I thought it had something to do with objects having the Ground layer attached to them, but the bug is still present if they don't have a layer.

\$\endgroup\$
4
  • \$\begingroup\$ Doesn't CharacterController already have an "is grounded" function? Is there a reason you're making your own? \$\endgroup\$ – qwyxivi Jul 21 '20 at 18:35
  • \$\begingroup\$ Not that I can tell from the docs. The is grounded function is needed mainly for jumping right now \$\endgroup\$ – cgaudet Jul 21 '20 at 18:40
  • \$\begingroup\$ Uh, well, if you missed it, it's here: docs.unity3d.com/ScriptReference/… \$\endgroup\$ – qwyxivi Jul 21 '20 at 18:42
  • \$\begingroup\$ Ahh, well I'll read up on everything the built in CharacterController has to offer vs Rigidbody stuff, but still using controller.isGrounded does not fix my issue \$\endgroup\$ – cgaudet Jul 21 '20 at 18:47
1
\$\begingroup\$

I combined the two controller.Move in one single line (on my personal script) like this :

controller.Move(((move * speed) + velocity) * Time.deltaTime);

or this (more readable) :

controller.Move(move * speed * Time.deltaTime + velocity * Time.deltaTime)

And it fixed my issue.

Hope it works on your game

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.