Custom Character Controller Jump & Movement

I have been writing a character controller on and off for a few weeks now, and it seems no matter what I do I can’t get it all working at the same time, when the movement works the jumping is screwed up, and when the jumping works the rest doesn’t.

I have now got the movement working with the physics instead of using rb.MovePosition, but now the jumping doesn’t to hardly anything.

The jumping, which used to add force at 0,5,0 worked fine, now I have to multiply that by 1000 to get it to make anything even remotely resembling a jump, then the player takes AGES to come back down again.

I’m not the greatest lover of PhysX or physics simulation in general for that matter, I think it is clumsy, but surely this can’t be a limitation, gravity on boxes don’t fall that slowly, so, why does the player, and why do I have to add 5k force to get it to do a .5 jump?

public float speed = 3.0f;
    private float distToGround;

    void Start()
    {
        Cursor.lockState = CursorLockMode.Locked;
        distToGround = GetComponent<Collider>().bounds.extents.y;
    }

    bool isGrounded()
    {
        return Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1f);
    }

    void Update()
    {
        if (!PlayerControl.playerControl.isPaused)
        {
            if (Input.anyKeyDown)
            {
                Cursor.lockState = CursorLockMode.Locked;
            }

            float translation = Input.GetAxis("Vertical") * speed;
            float straffe = Input.GetAxis("Horizontal") * speed;
            translation *= Time.deltaTime;
            straffe *= Time.deltaTime;

            Vector3 moveDir = new Vector3(straffe, 0, translation);
            moveDir = transform.TransformDirection(moveDir);
            //GetComponent<Rigidbody>().MovePosition(transform.position + moveDir);
            GetComponent<Rigidbody>().velocity = moveDir * 70;

            if (Input.GetKeyDown(PlayerControl.playerControl.pauseKey))
            {
                Cursor.lockState = CursorLockMode.None;
            }

            if (Input.GetKeyDown(PlayerControl.playerControl.sprintKey))
            {
                speed = speed * 2;
            }
            if (Input.GetKeyUp(PlayerControl.playerControl.sprintKey))
            {
                speed = 3.0f;
            }
            if (Input.GetKeyDown(PlayerControl.playerControl.jumpKey) && isGrounded())
            {
                GetComponent<Rigidbody>().AddForce(Vector3.up * 5, ForceMode.Force);
            }
            GetComponent<Rigidbody>().velocity = Vector3.ClampMagnitude(GetComponent<Rigidbody>().velocity, 30f);
        }
    }

Few problems. When you’re setting rigidbody.velocity directly, that is overriding gravity (as well as forces that you yourself add!) for the most part. You also need to be interacting with your rigidbody in FixedUpdate rather than Update – poll your input in Update then apply it in FixedUpdate.

Cache your rigidbody - you’re calling GetComponent() 4 times in your Update loop - it’s ugly and inefficient.

Don’t add an absurdly high force for the jump – use GetComponent().AddForce(Vector3.up * 5, ForceMode.VelocityChange);

I think rigidbody.MovePosition should work fine after that - I don’t believe it overrides velocity.

1 Like

Agreed on @flaminghairball 's points. And finally, are you sure you need physics at all? You say you’re not a fan of it, and I’m right there with you… so I don’t use it for games like this. Check out this article for my approach (and code you’re welcome to use if you like).