Hello, I’m building a Character Controller for a 3D Platformer, and I’m having a problem with my Jump mechanic.
Whenever I’m going upwards on a Slope, if I jump it looks like I didn’t really jump and I’m still walking, but if I stop walking or go downwards it will go higher for the remaining jump height.
This is what happens:
It does not look right, I’m pretty sure this doesn’t happen on other 3D Platformers, I don’t understand how to fix it though, do you guys have any idea?
This is the code snippet responsible for jumping:
if (isGrounded && velocity.y < 0)
{
isJumping = false;
controller.slopeLimit = ogSlopeLimit;
velocity.y = -2f;
}
if (Input.GetButtonDown("Jump") && isGrounded)
{
isJumping = true;
controller.slopeLimit = 100.0f;
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
This is the full Character Controller script (it’s a bit messy, I know):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private Transform camT;
private CharacterController controller;
private Vector3 velocity, moveDir, floorNormal, slopeVect;
private bool isJumping = false, isGrounded;
private float accel, ogSlopeLimit, ogAccel;
[Header("Movement Settings")]
public float moveSpeed;
public float rotSpeed;
public float jumpHeight;
public float airControl;
public float gravity = -9.81f;
[Header("Slope Settings")]
public float slopeForce;
public float slopeForceRayLenght;
[Header("Ground Settings")]
public Transform groundCheck;
public float groundDistance;
public LayerMask groundMask;
void Start()
{
//Prendi il transform della telecamera
camT = FindObjectOfType<Camera>().transform;
//Prendi il char controller
controller = this.GetComponent<CharacterController>();
//Salva lo slope limit originale nella variabile ogSlopeLimit, per non perdere cambiamenti fatti nell'inspector quando lo andiamo a cambiare durante il salto
ogSlopeLimit = controller.slopeLimit;
}
void Update()
{
//Controllo del grounded
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
ogAccel = airControl / 100;
RaycastHit fHit;
if (Physics.Raycast(transform.position, Vector3.down, out fHit, controller.height / 2 * slopeForceRayLenght))
{
floorNormal = fHit.normal;
Debug.DrawRay(fHit.point, floorNormal, Color.yellow);
}
if (isGrounded)
{
accel = 1;
}
else
{
accel = ogAccel;
}
//Se è grounded e la velocità y è negativa(così da evitare di attivarlo quando abbiamo appena iniziato il salto),
//reset a -2 per evitare di accumulare velocità verticale e ripristina l'angolo originale per gli slope
if (isGrounded && velocity.y < 0)
{
isJumping = false;
controller.slopeLimit = ogSlopeLimit;
velocity.y = -2f;
}
//Cattura gli input (da integrare con l'input system proprietario)
float x = Input.GetAxisRaw("Horizontal");
float z = Input.GetAxisRaw("Vertical");
Vector2 pInput = new Vector2(x, z);
//Prendi e normalizza il vettore forward e il vettore right della telecamera per raddrizzare poi la direzione del movimento in base alla telecamera
Vector3 camF = camT.forward;
Vector3 camR = camT.right;
camF.y = 0;
camR.y = 0;
camF = camF.normalized;
camR = camR.normalized;
//Se c'è del movimento e siamo su uno slope, assicurati che il personaggio vi rimanga sopra in maniera corretta
if ((pInput.magnitude != 0) && OnSlope())
{
slopeVect = Vector3.Normalize(Vector3.down * controller.height / 2 * slopeForce * Time.deltaTime);
moveDir = moveDir * moveSpeed * Time.deltaTime;
Vector3 slopeMove = new Vector3(moveDir.x, slopeVect.y, moveDir.z);
controller.Move(Vector3.Normalize(slopeMove));
}
//Applica l'input del giocatore e la direzione della camera al vettore della direzione di movimento, e successivamente applica il movimento
moveDir = Vector3.Lerp(moveDir, Vector3.Normalize(camR * pInput.x + camF * pInput.y), accel);
if (!OnSlope())
controller.Move(moveDir * moveSpeed * Time.deltaTime);
Debug.Log(controller.velocity);
Debug.DrawRay(transform.position, controller.velocity, Color.green);
//Rotea il personaggio nella direzione in cui è diretto
if ((pInput.magnitude != 0))
transform.forward = Vector3.Slerp(transform.forward, moveDir, rotSpeed);
//Salta e imposta lo slope limit a 100 per evitare problemi d'incastro con gli slope
if (Input.GetButtonDown("Jump") && isGrounded)
{
isJumping = true;
controller.slopeLimit = 100.0f;
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
//Applica la gravità a velocity, con la quale poi ci muoveremo
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
//Se c'è una collisione sopra, ferma il salto per evitare di rimanere fluttuante per tutta la durata del salto
if ((controller.collisionFlags & CollisionFlags.Above) != 0)
{
velocity.y = -2f;
}
}
private bool OnSlope()
{
//Se salti, restituisci falso perchè non sei più su uno slope
if (isJumping)
return false;
//Se c'è uno slope sotto al personaggio, restituisci vero
RaycastHit hit;
if (Physics.Raycast(transform.position, Vector3.down, out hit, controller.height / 2 * slopeForceRayLenght))
if (hit.normal != Vector3.up)
return true;
//Se nessuno dei due casi avviene, restituisci automaticamente falso
return false;
}
}
Thanks.
