CharacterController problem when jumping upwards on slopes

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.

Just looking at this I am not going to be able to figure out what is perhaps the logic bug. I think you are going to have to add some Debug.Log() statements into this script in order to figure out how the logic is actually running.

I recommend at each “important” place, such as when you test or set or clear a boolean value, use Debug.Log() to display something meaningful, and perhaps that will give you insight into how it is behaving.