user16777176
user16777176

Reputation:

jumping/falling animation script

I'm trying to learn unity 2D and now iI need to do animations. I did walking animation, falling animation, jumping animation and the idle animation. However, when I jump, the falling animation doesn't play as intended. The falling animation isn't working properly, so it looks like this:

https://www.awesomescreenshot.com/video/8054610?key=208b095723f0bd4d8dfb936c88485e76

So when I'm falling, it doesn't play the animation right.

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private Rigidbody2D rb;
    private Animator anim;
    private SpriteRenderer sprite;

    private enum MovementState { idle, running, jumping, falling }

    private float dirX = 0f;
    [SerializeField] private float moveSpeed = 7f;
    [SerializeField] private float jumpForce = 5f;

    private void Start()
    {
        Debug.Log("program started...");

        rb = GetComponent<Rigidbody2D>();
        sprite = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();
    }

    private void Update()
    {
        dirX = Input.GetAxisRaw("Horizontal");
        rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);

        if (Input.GetButtonDown("Jump"))
        {
            rb.velocity  = new Vector2(rb.velocity.x, jumpForce);
        }

        Animation();
    }

    private void Animation()
    {
        MovementState state;

        if (dirX > 0f)
        {
            state = MovementState.running;
            sprite.flipX = false;
        }

        else if (dirX < 0f)
        {
            state = MovementState.running;
            sprite.flipX = true;
        }

        else
        {
            state = MovementState.idle;
        }

        if (rb.velocity.y > .1f)
        {
            state = MovementState.jumping;
        }
        else if (rb.velocity.y < -.1f)
        {
            state = MovementState.falling;
        }

        anim.SetInteger("state", (int)state);
    }
}

i don't know how to fix it, i've searched for about a hour how to fix it.

animations setting (my settings) this the settings that i want this

Upvotes: 0

Views: 1966

Answers (3)

TEEBQNE
TEEBQNE

Reputation: 6266

As it has been suggested, I would add what is called a ground check to your player, which is exactly what it sounds like. An easy way to do this would be to Raycast downward from your player's position offset by the sprite's extents and only detect casts against a specific ground LayerMask.

Once you have a ground check done, you can set the state of your animation based on 4 criteria.

  1. Is the player grounded?
  2. What is your relative velocity? (Positive / Negative)

With your four states, the logic would look as follows

•Idle - Grounded and X Velocity equals 0 (Or default)
•Running - Grounded and X Velocity not equal to 0
•Jumping - Not Grounded and Y Velocity greater than or equal to 0
•Falling - Not Grounded and Y Velocity less than 0

With this in mind, here is how I would edit your existing code to work as intended

using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private Rigidbody2D rb;
    private Animator anim;
    private SpriteRenderer sprite;

    private enum MovementState { idle, running, jumping, falling }

    private float dirX = 0f;
    [SerializeField] private float moveSpeed = 7f;
    [SerializeField] private float jumpForce = 5f;
    [SerializeField] private LayerMask groundMask;
    [SerializeField] private float groundLengthCheck = 0.03f;

    private Vector3 spriteGroundOffset = Vector3.zero;
    private bool isGrounded = false;

    private void Start()
    {
        Debug.Log("program started...");

        rb = GetComponent<Rigidbody2D>();
        sprite = GetComponent<SpriteRenderer>();
        anim = GetComponent<Animator>();

        // offset the raycast check to be half our sprite bounds in the Y (the bottom of your sprite)
        spriteGroundOffset = new Vector3(0f, sprite.bounds.extents.y, 0f);
    }

    private void Update()
    {
        dirX = Input.GetAxisRaw("Horizontal");
        rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);

        // determine if our player is grounded by casting down from their feet with our slight offset
        isGrounded = Physics2D.Raycast(transform.position - spriteGroundOffset, Vector2.down, groundLengthCheck, groundMask);

        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.velocity = new Vector2(rb.velocity.x, jumpForce);
        }

        Animation();
    }

    private void Animation()
    {
        // default our state to idle - as if we are just standing
        MovementState state = MovementState.idle;

        // change 
        if (isGrounded)
        {
            if (dirX > 0f)
            {
                state = MovementState.running;
                sprite.flipX = false;
            }
            else if (dirX < 0f)
            {
                state = MovementState.running;
                sprite.flipX = true;
            }
        }
        else
        {
            if (rb.velocity.y > 0)
            {
                state = MovementState.jumping;
            }
            else if (rb.velocity.y < 0f)
            {
                state = MovementState.falling;
            }
        }
        anim.SetInteger("state", (int)state);
    }
}

Keep in mind

  • Add a new layer, assign it to your ground objects, and set the serialized field groundMask to check for this new layer.
  • There are a few other issues that might come about with the current code. The current snippet I have provided only fixes the issue related to jumping/falling.

Here is a gif of the current code in action - I am using a public domain sprite as I do not currently have any art for a 2D player.

Example gif

Upvotes: 1

Digvijaysinh Gohil
Digvijaysinh Gohil

Reputation: 1455

I suggest you to use two different floats for your animations, one for Movement and one for Jumping.

Then something like following to handle them.

private void Animation() {
    sprite.flipX = dirX > 0f;
    
    //Do some sort of ground check
    if (isGrounded) {
        anim.SetFloat("Move", dirX);
    }
    else {
        anim.SetFloat("Jump", rb.velocity.y);
    }
}

And of course you need to change your condition that you have setup in your Animator as well from your Animator window to make it work.

Upvotes: 1

mandy1339
mandy1339

Reputation: 516

There's a couple of things you can try to do to narrow down the issue. See if commenting out this else statement has an effect on the issue you are experiencing between jump and fall.

     else
     {
        state = MovementState.idle;
     }

I think this else could possibly to interrupt your Y velocity animation transition when the object reaches the max height of the jump. Try to comment out different part of your if else statements until you find the culprit. Also try to get rid of the overlap on the transition between jump and fall. I think you want to instantly move from jump animation to fall animation.

Upvotes: 1

Related Questions