Jump pad With Character Controller

Hello, I’m creating a jump pad that would launch the player up in the air. I’m using a character controller, in 3D. The issue seems to be that the character snaps up in Y, and without any “hang time” before it drops down. How do i polish the movement in my code? Thank you for taking a look.

using DG.Tweening;
using DG.Tweening.Plugins;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public static PlayerController instance;


    public CharacterController controller;
    public float moveSpeed;
    public float jumpForce;
    public float rotationSpeed;
    public float gravityScaler;
    public bool isGrounded;
    public Animator myAnimator;
    public GameObject playerModel;
    private Vector3 moveDirection;


   
   
    private Camera theCam;

    public GameObject jumpFx;

    public float jumpGracePeriod;
    private float? lastGroundTime;
    private float? jumpButtonPressedTime;

    private Vector3 jumpPadDirection;
    public float jumpPadForce;

    public bool stopMove;




    private void Awake()
    {
        instance= this;
    }


    // Start is called before the first frame update
    void Start()
    {
     
        theCam = Camera.main;
    }

    // Update is called once per frame
    void Update()
    {

        if(!stopMove)
        {
            float yStore = moveDirection.y;

            moveDirection = (transform.forward * Input.GetAxisRaw("Vertical")) + (transform.right * Input.GetAxisRaw("Horizontal"));
            moveDirection.Normalize();
            moveDirection = moveDirection * moveSpeed;
            moveDirection.y = yStore;



            //Jump
            if (controller.isGrounded)
            {

                lastGroundTime = Time.time;
            }
            if (Input.GetButtonDown("Jump"))
            {
                jumpButtonPressedTime = Time.time;
            }

            if (Time.time - lastGroundTime <= jumpGracePeriod)
            {
                moveDirection.y = 0f;

                if (Time.time - jumpButtonPressedTime <= jumpGracePeriod)
                {
                    moveDirection.y = jumpForce;
                    jumpButtonPressedTime = null;
                    lastGroundTime = null;
                    myAnimator.SetTrigger("Jump");
                    myAnimator.SetInteger("JumpIndex", Random.Range(0, 3));
                    Instantiate(jumpFx, gameObject.transform.position, Quaternion.Euler(90, 0, 0));
                    AudioManager.instance.PlaySFX(0);
                    AudioManager.instance.PlaySFX(1);

                }
            }


            //Gravity
            moveDirection.y += Physics.gravity.y * Time.deltaTime * gravityScaler;
            controller.Move(moveDirection * Time.deltaTime);

            //Camera
            if (Input.GetAxisRaw("Horizontal") != 0f || Input.GetAxisRaw("Vertical") != 0f)
            {
                transform.rotation = Quaternion.Euler(0f, theCam.transform.rotation.eulerAngles.y, 0f);
                Quaternion newRotation = Quaternion.LookRotation(new Vector3(moveDirection.x, 0f, moveDirection.z));
                playerModel.transform.rotation = Quaternion.Slerp(playerModel.transform.rotation, newRotation, rotationSpeed * Time.deltaTime);
            }

            myAnimator.SetFloat("Speed", Mathf.Abs(moveDirection.x) + Mathf.Abs(moveDirection.z));


        }
        if (stopMove)
        {
            moveDirection = Vector3.zero;
            moveDirection.y += Physics.gravity.y * Time.deltaTime * gravityScaler;
            controller.Move(moveDirection);
            myAnimator.SetFloat("Speed", 0);
          

        }


    }



    public void JumpingPad()
    {
        float yStore = jumpPadDirection.y;
        jumpPadDirection.y = jumpPadForce;

        Vector3 moveUp = new Vector3(transform.position.x, jumpPadForce, transform.position.z);

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


}

This is my Jump Pad Script.

using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;

public class JumpPad : MonoBehaviour
{
    private Animator myPadAnimator;

    private void Start()
    {
        myPadAnimator= GetComponent<Animator>();   
    }
    public void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Player")
        {
            PlayerController.instance.JumpingPad();
            myPadAnimator.SetTrigger("PushUp");
        }
    }


}

Here is the visual result :

https://im5.ezgif.com/tmp/ezgif-5-534a75b815.gif

You should only make one call to CharacterController.Move() per frame.

Said method takes a direction, and you can easily ‘build’ a direction by adding directional vectors together. So a jump pad would just add a large vertical directional vector to the vector you build each frame, which gets tapered off naturally via gravity.

1 Like

Thank you for your reply, could you explain a bit further? I didn’t fully understand the logic here.

No problem.

As mentioned it’s pretty easy to add vectors together. A super basic character controller could be boiled down to:

private void Update()
{
   float xInput = Input.GetAxis("Horizontal");
   float zInput = Input.GetAxis("Vertical");

   Vector3 movementInput = new Vector3(xInput, 0, zInput);
   Vector3 gravity = new Vector3(0, -9.8f, 0);

   Vector3 finalVector = (movementInput + gravity) * Time.deltaTime;

   characteController.Move(finalVector);
}

You make a vector for input, and for gravity, and just slap them together.

Obviously this doesn’t include jumping. But that should be easy to add. You simply maintain another Vector3 (one scoped to the class, rather than the method), modify it’s y component over time, then add that plus your movement vector together for the right result.

A jump pad follows pretty much the same logic as jumping.

In a character controller I’ve done, it all boiled down to:

Vector3 finalDirection = (movementInput + verticalVelocity + externalForces) * Time.deltaTime;
characteController.Move(finalDirection);

Thanks again, bare with me please, so i can get it right…
So In the Playercontroller, i wouldn’t need to have an extra method to be called from Jumping Pad script? Then how would i call it when player triggers the “jump Zone” ?

You’d still have a method, just not a ‘jump pad’ specific one. Instead a more general one that allows outside objects to mutate one or more of the directional vectors you build.

Super basic example:

//somewhere in your CC script:
private Vector3 verticalVelocity;

public void ModifyVerticalVelocity(Vector3 velocity)
{
    verticalVelocity += velocity;
}

//jump pad
public class JumpPad : MonoBehaviour
{
    public void OnTriggerEnter(Collider other)
    {
        if (other.TryGetComponent(out PlayerController controller))
        {
            Vector3 velocity = Vector3.up * 10f;
            controller.ModifyVerticalVelocity(velocity);
        }
    }
}

Thank you, i ll have a go and try to understand it all and will reply here. A lot of new content.

1 Like

Why I am getting private modifier not valid?