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");
}
}
}
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.
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:
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);
}
}
}