Reputation: 211
I have a 2d RPG click to move game. I want to improve my code so that my players animation doesn't look bad, for example this is a video of what my player's animation looks like. As you can see my player's idle state animation isn't the best. The video also allows you to see my animator, just in case if I have made a mistake within my blend tree or transitions. How can I improve my code so that my player's animation isn't bad and my player's idle state animation face the correct direction it is suppose to be facing. Thank you!
private Animator anim;
public float speed = 15f;
private Vector3 target;
private bool touched;
private bool playerMovementRef;
void Start()
{
target = transform.position;
anim = GetComponent<Animator>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint(mousePosition);
target.z = transform.position.z;
var movementDirection = (target - transform.position).normalized;
if (movementDirection.x != 0 || movementDirection.y != 0)
{
anim.SetBool("walking", true);
anim.SetFloat("SpeedX", movementDirection.x);
anim.SetFloat("SpeedY", movementDirection.y);
if (movementDirection.x < 0)
{
anim.SetFloat("LastMoveX", -1f);
}
else if (movementDirection.x > 0)
{
anim.SetFloat("LastMoveX", 1f);
}
else
{
anim.SetFloat("LastMoveX", 0f);
}
if (movementDirection.y > 0)
{
anim.SetFloat("LastMoveY", 1f);
}
else if (movementDirection.y < 0)
{
anim.SetFloat("LastMoveY", -1f);
}
else
{
anim.SetFloat("LastMoveY", 0f);
}
}
}
else
{
if (Mathf.Approximately(transform.position.x, target.x) && Mathf.Approximately(transform.position.y, target.y))
{
touched = false;
anim.SetBool("walking", false);
}
else
{
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
}
}
To be more clear, I want to do something like this: https://i.sstatic.net/WsrIY.jpg But I'm having problems with my code, I'm close it's just isn't facing correctly when it goes to it's idle state. I've check if "has exit time" was on, which it was not, so I'm not sure what I am doing wrong. I also made sure that I debug.log it and it didn't exactly give me an answer to what I was looking for.
Upvotes: 0
Views: 104
Reputation: 183
At present you are using a crude bunch of if-then
blocks to set various floats in the mechanim controller, which in the end controls the direction the character is facing. It is possible (in fact extremely likely) for both movementDirection.x
and movementDirection.y
to be non-negative. However, your animation panels are only four-directional, so you need to convert the 2D vector to one which has only one non-zero value between its x
and y
.
Vector3 animDirection = Vector3.zero;
if (movementDirection.sqrMagnitude > 0)
{
// Use >= to default to horizontal on both being equal
if (movementDirection.x > movementDirection.y)
animDirection.x = 1;
else
animDirection.y = 1;
}
Upvotes: 1
Reputation: 292
In your idle animation you have a blend tree with four different states in Freeform Cartesian. The problem is you only have four discrete animations to choose from, not an infinite range of motion as would be the case in 3d. It looks like what's happening is that you're getting non-zero values for each of LastMoveX and LastMoveY. Because of that the result puts your animation in one corner of the blend tree - right between two states. I think the only thing determining which way the end result faces is floating point imprecision. To solve the issue you can boil down the logic of the idle state to it's four components, a single variable would probably work, and just have each animation assigned to a value.
Upvotes: 0