Jumping and other actions

This was a question that was asked before, but since I had a few more questions regarding the answer within the topic, I wanted to open a new topic as I couldnt reply to that thread.

Upon the suggestion of using triggers instead of bools to switch states, I found it didnt work as I expected it to and I was a bit confused on how to create the transition lines when using triggers instead of bools. In my case what happens is that when I jump, the jump animation continues looping even after I’ve landed on the ground. I tried many ways, but I simply couldnt get the jumping animation to go back to idle once I was on the ground. Below is a snapshot of my settings in Unity as well as a snippet of my code

void OnJump(InputValue value)
    {
        if (!myCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
        { 
            return;
        }

        if(value.isPressed)
        {
            myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
            myAnimator.SetTrigger("isJump");  //Basically here I set the jump trigger to high and 
            myAnimator.ResetTrigger("isIdle");  //the idle trigger to low so that after the jump, the triggers go 
                                                                     //go back to their initial states of isJump = low and IsIdle = High
        }
    }

Is there perhaps something that I got wrong?

Hi,

Maybe you could try to call myAnimator.ResetTrigger("isJump"); in the first if-block in the OnJump method. Do that before the return; instruction. Or have you already tried that?

Also try to swap the lines with SetTrigger and the ResetTrigger in the second if-block.

I just tried it, so my code now basically looks like this

void OnJump(InputValue value)
    {
        if (!myCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
        { 
            myAnimator.ResetTrigger("isJump");
            return;
        }

        if(value.isPressed)
        {
            myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
            myAnimator.ResetTrigger("isIdle"); 
            myAnimator.SetTrigger("isJump");
        }
    }

I still get the error. Basically what happens is that after the first jump, the character is constantly in the Jumping state. For some reason, it doesnt get set back to not jumping even after the character is grounded. Is the solution then to implement some sort of ‘isGrounded’ state? I also tried this piece of code and the same behavior wherein the character is stuck in a jumping state after the first loop happens. Of course I made sure to switch the conditions of the transitions back to using the isJumping bool.

void OnJump(InputValue value)
    {
        if (!myCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
        { 
            myAnimator.SetBool("isJumping",false);
            //myAnimator.ResetTrigger("isJump");
            return;
        }

        if(value.isPressed)
        {
            myAnimator.SetBool("isJumping",true);
            myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
            //myAnimator.ResetTrigger("isIdle"); 
        }
    
    }

Have you already tried to add Debug.Logs to your code to see what is going on during runtime? I’m wondering how OnJump is getting called.

Theoretically, the trigger should get set back to false automatically. See the decription in the API:

Unlike bools which have the same true/false option, Triggers have a true option which automatically returns back to false.

Maybe something is constantly calling myAnimator.SetTrigger("isJump");. That’s impossible to tell, though, just by looking at the code.

By the way, which version of Unity do you use?

After using debug.log, I saw that though the player has no Y velocity, the isJumping state is never turned ‘off’. But it makes sense since there is never really a time when the code goes into the ‘OnJump’ function when the key is not pressed. I assume that the OnJump function is an interrupt that happens when the jump button is pressed. So the code is not really checking for the time when the jump is finished and then set isJumping to false. After looking at many other examples, people from what I can see have the Jump function inside the update() function, and they give the player y velocity when the button is pressed. For example, like this code I found at another thread in this website

void Update () {

    Run();

    LookLeftOrRight();

    Jump();

    ClimbLadder();

}


private void LookLeftOrRight()

{ // if the player is moving horizontally...

    bool playerHasHorizontalSpeed = Mathf.Abs(myRigidBody2D.velocity.x) > Mathf.Epsilon;

    // mathf.epsilon gives an almost zero value.


    if (playerHasHorizontalSpeed)

    {

        transform.localScale = new Vector2(Mathf.Sign(myRigidBody2D.velocity.x), 1f);

        //localScale is simply the scale parameter in inspector under transform.

        // reverse the current scaling for x axis

        // use mathf.abs to get a positive number.

        // use mathf.sign to give a negative sign or positive.

    }

}


private void Jump()

{

    if (!myCollider2D.IsTouchingLayers(LayerMask.GetMask("Ground")))

    { return; }


        if (CrossPlatformInputManager.GetButtonDown("Jump"))

        { // give ourselves a new y velocity:

            Vector2 jumpVelocityToAdd = new Vector2(0f, jumpHeight);

            myRigidBody2D.velocity += jumpVelocityToAdd;

        }


        // My code that gets jump animation working and stopping when it should:

        bool playerIsJumping = Mathf.Abs(myRigidBody2D.velocity.y) > Mathf.Epsilon;


        if (playerIsJumping)

        {

            myAnimator.SetBool("Jumping", true);

        }

        else if (!playerIsJumping)

        {

            myAnimator.SetBool("Jumping", false);

        }

   

}

I believe the problem here is that Rick is using the new unity input system, wherein you already have predefined functions such as OnJump that are not inside the update function. One solution of course would be to call the Jump function every frame and use the GetButtonDown function. With the new input manager, I’m not sure how to handle this issue.

I forgot to mention this but I am using Unity version 2021.2.3f1

As before, thanks a lot for taking your time with looking at this!

Finally got it to sort of work! What I mean is that the animation and states themselves do get triggered as they should, but the jump animation is very ‘basic’ in that you have no animation states for when you fall from very steep heights, in which case the character simply loops the default jumping animation over and over. But of course this is a whole different topic and not quite related to this particular problem from before. This is how I got it to work:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerMovement : MonoBehaviour
{

    Vector2 moveInput;
    Rigidbody2D myRigidbody;
    Animator myAnimator;
    CapsuleCollider2D myCapsuleCollider;
    [SerializeField] float runSpeed = 10f;
    [SerializeField] float jumpSpeed = 5f;
 
    void Start()
    {
        myRigidbody = GetComponent<Rigidbody2D>();
        myAnimator = GetComponent<Animator>();
        myCapsuleCollider = GetComponent<CapsuleCollider2D>();
        myAnimator.SetBool("isRunning",false);
        
    }

    void Update()
    {
        Run();
        FlipSprite();
        bool playerHasVSpeed = Mathf.Abs(myRigidbody.velocity.y) > Mathf.Epsilon;
        myAnimator.SetBool("isJumping",playerHasVSpeed);
        
    }

    void OnMove(InputValue value)
    {
        moveInput = value.Get<Vector2>();
    }


    void OnJump(InputValue value)
    {
        if (!myCapsuleCollider.IsTouchingLayers(LayerMask.GetMask("Ground")))
        { 
            return;
        }

        if(value.isPressed)
        {
            myAnimator.SetBool("isJumping",true);
            myRigidbody.velocity += new Vector2 (0f, jumpSpeed);
        }
    
    }

    void Run()
    {
        Vector2 playerVelocity = new Vector2 (moveInput.x * runSpeed, myRigidbody.velocity.y);
        myRigidbody.velocity = playerVelocity;
        bool playerHasVSpeed = Mathf.Abs(myRigidbody.velocity.y) > Mathf.Epsilon;
        bool playerHasHorizontalSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
        if(playerHasVSpeed && playerHasHorizontalSpeed)
        {
            myAnimator.SetBool("isRunning",false);
        }
        else
        {
            myAnimator.SetBool("isRunning",playerHasHorizontalSpeed);        
        }
        
    }

    void FlipSprite()
    {
        bool playerHasHorizontalSpeed = Mathf.Abs(myRigidbody.velocity.x) > Mathf.Epsilon;
        if (playerHasHorizontalSpeed)
        {
            transform.localScale = new Vector2 (Mathf.Sign(myRigidbody.velocity.x),1f);
        }
        
    }
}

So basically in my update function I check if my character has vertical speed, and if so I simply use that bool variable to toggle the jumping state. Because the update function checks this every frame, the Jumping state is automatically turned off when there is no vertical speed. Of course there was also another issue where you have both X and Y velocities, in which case there would be a conflict of animation states between running and jumping. For that I went to the running script and added an exception wherein I turn off the isRunning state if the player also has vertical speed.

I realize this is not the best of fixes, but for now, I think I worked on this much more than I should have considering that in this part of the course the jump animation was not an aspect that was discussed.

Thank you so much for all your help!

Good job! I think it’s fine if you keep this solution for now and finish your game first. If you have time at a later juncture, you could revise your solution and improve it if necessary. :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms