Having trouble getting player's last vector and storing it into variable

I’m trying to write code for a top-down RPG player’s walking animation that moves up, down, left, and right.

And I’m having trouble trying to get the last player movement with a vector variable, but everytime I do that it only stores only one of the points, so if I’m going up-right it doesn’t store (1,1) but only (1,0)

I know this code is only messy so I’m open to suggestions to make it neater or better. Thank you.

using System.Collections;
using System.Collections.Generic;
using UnityEditor.U2D;
using UnityEngine;

public class PlayerMovement : MonoBehaviour
{
    private Animator anim;
    private Rigidbody2D rb;
    private SpriteRenderer sprite;
    private enum AnimationState { idleDown, walkingDown, idleUp, walkingUp, walkingXIdle, walkingX }
    private float dirX;
    private float dirY;
    public float lastDirX = 0.0f;
    public float lastDirY = 0.0f;
    public Vector2 moveDir;
    public Vector2 lastDir;
    [SerializeField] private float moveSpeed = 10.0f;

    private void Awake()
    {
        anim = GetComponent<Animator>();
        rb = GetComponent<Rigidbody2D>();
        sprite = GetComponent<SpriteRenderer>();
    }

    private void Update()
    {
        dirX = Input.GetAxisRaw("Horizontal");
        dirY = Input.GetAxisRaw("Vertical");

        moveDir = new Vector2(dirX, dirY);
        if (moveDir != Vector2.zero)
        { 
            lastDir = moveDir;
        }
        UpdateAnimationState();

    }

    private void FixedUpdate()
    {
        rb.velocity = new Vector2(dirX * moveSpeed, dirY * moveSpeed);
    }


    private void UpdateAnimationState()
    {
        AnimationState state;

        if (moveDir.y < 0.0f && moveDir.x == 0.0f)
        {
            state = AnimationState.walkingDown;

        }
        else if (moveDir.y > 0.0f && moveDir.x == 0.0f)
        {
            state = AnimationState.walkingUp;

        }
        else if (lastDir == new Vector2(0.0f, 1.0f) && moveDir == Vector2.zero)
        {
            state = AnimationState.idleUp;

        }
        else if ((moveDir.x > 0.0f && moveDir.y > 0.0f) || (moveDir.x > 0.0f && moveDir.y < 0.0f) || (moveDir.x > 0.0f && moveDir.y == 0.0f)) // Walking Right
        {
            state = AnimationState.walkingX;
            sprite.flipX = false;
        }
        else if ((moveDir.x < 0.0f && moveDir.y > 0.0f) || (moveDir.x < 0.0f && moveDir.y < 0.0f) || (moveDir.x < 0.0f && moveDir.y == 0.0f)) // Walking Left
        {
            state = AnimationState.walkingX;
            sprite.flipX = true;

        }
        else if (lastDir.x >= 0.0f && lastDir.y == 0.0f && moveDir == Vector2.zero)
        {
            state = AnimationState.walkingXIdle;
        }
        else if (lastDir.x <= 0.0f && lastDir.y == 0.0f && moveDir == Vector2.zero)
        {
            state = AnimationState.walkingXIdle;
            sprite.flipX = true;
        }
        else
        {
            state = AnimationState.idleDown;

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

    }

}

Use LateUpdate, and make sure it’s bottom most with the script execution order.

Are you just walking in a grid? You probably don’t want to control positions like that and you certainly do NOT want to compare floating point numbers for equality, such as this line and others:

For why google up “floating point imprecision.”

If you’re in a grid, do it all with integer positions, track your own positions in that grid, track the grid itself on a cell by cell basis and then smooth the motion between cells.

If you would like examples, check out the DemoMoveGridCell and DemoMoveGridCell2 scenes in my Proximity Buttons package.

This is the relevant code, basically a super-stripped down essential 2D grid movement setup:

proximity_buttons is presently hosted at these locations:

https://bitbucket.org/kurtdekker/proximity_buttons

I’m not having my character walk on a grid. I’m trying to make it so that for example if you’re moving up right, when you stop moving it plays the idle animation for looking right. But when I try to do that it sometimes snaps back to just up-down-left or right. The diagonal directions are a bit weird.

For example, in Final Fantasy 4 if you’re moving right, or up-right then stop it will play the same idle animation.

Firstly, it doesn’t make sense to update your last direction before you compare against it. Since you update your last direction BEFORE you update animation states, your last and current direction will always be the same, rendering it useless as a comparison. Update the last direction AFTER you have done your comparisons to the current direction.

Also, Kurt’s point about floating point precision (or lack thereof) still stands. A floating point value is almost always never going exactly equal another floating point value. In general you should never check a floating point value for equality.

In this case you should check if one direction is almost zero, and another direction is above a certain threshold.

Eg:

else if (lastDir.y < Mathf.Epsilon && lastDir.x > 0.95f && moveDir.magnitude < Mathf.Epsilon)
{
	state = AnimationState.idleUp;
}

That said, this can be greatly simplified. For example you can simply cache a bool at the beginning to check if the player is moving or not: bool isMoving = moveDir != Vector2.zero);, which helps keep your code readable.