Unit Moonwalking in Action Points Demo

In the video for this tutorial Unit 1 moonwalked during the wrap up, I’m not sure where the bug originated from.

By that you mean the Unit doesn’t rotate fast enough? That’s a side effect of the rotation method when rotating very close to 180º, since it’s based on Lerping a Vector direction it gets closer to 0,0 before flipping to the other side.
You can replace it with Slerp or do Quaternion.Lerp if you want to fix that

3 Likes

I would suggest waiting for rotation to finish before allowing the move to kick in. Combining rotation and movement is going to end up with units moon-walking or sliding sideways sometimes unless you write specific animations for each combination of velocity direction vs facing direction (e.g. a side-step)

1 Like

I noticed another issue when I was doing my own implementation, it looks like if you are Lerping and you need to turn exactly 180° the math works out that you turn 0°. I added a slight turn offset to break out of this issue.

1 Like

@Protesilaus can you share your code sln? I dont see where 180==0.
Thank you!

[edit] use Slerp!!

To explain this I made a quick demo, you can find it here:
https://the-guildhall.net/DevLog/LerpDemo.zip

The formula behind Lerp is very basic, it is A + (B - A) * T. For the below explanation I am going to refer to the result of the formula as L.
If we were Lerping angles we would expect the following distribution.
Lerp(0, 180, T)
T=0 L=0
T=0.25 L=45
T=0.5 L=90
T=0.75 L=135
T=1 L=180
That makes sense and the formula would work fine.

In the demo project, to rotate we were changing the “forward” vector. So we can express a change in 180° as the following:
Starting Vector 0, 0, 1
Ending Vector 0, 0, -1
This means we are starting with facing “Forward” and want to face “Backwards”.
So we will plug this into the same formula, I am going to drop the X, Y calculations since they will always be 0.
Lerp(1, -1, T)
1 + (-1 - 1) * T = 1 + (-2) * T
Don’t forget the answer is normalized, since we are dealing with directional Vectors.
T=0 L=1
T=0.25 L=0.5
T=0.5 L=0
T=0.75 L=-0.5
T=1 L=-1

So if we normalize the Vectors, here is the result at the time intervals:
T=0 V(0, 0, 1) N(0, 0, 1)
T=0.25 V(0, 0, 0.5) N(0, 0, 1)
T=0.5 V(0, 0, 0) N(0, 0, 0)
T=0.75 V(0, 0, -0.5) N(0, 0, -1)
T=1 V(0, 0, -1) N(0, 0, -1)

So if we were using Lerp by the book, we would see the character no rotate at all then all of a sudden rotate 180°, but with the way the project is designed, we are always running the Lerp in the beginning of the timespan (since we are always running it with Time.DeltaTime * RotationSpeed.

I realized this because I was having my characters movement tied to their rotation, so that they wouldn’t start walking in reverse until their bodies rotation caught up to their movement vector. I figured they would walk a little extra, but instead they walked in a straight line and never turned around. I had to do a deep dive into Lerp to figure out where the problem was. To “fix” it in my demo project, I added a small variation to their rotation on every update (something like 0.1f, 0, 0.1f) so they always rotate a little, this is enough of a “kick” to ensure they start rotating in the right direction, then we they are close to the final rotation value, I just set it and stop running the rotate code.

I hope this explanation helps.

Another thing I realized in my own projects after finishing the course was the following. Mathf.RoundToInt always rounds to the even value. Here is what happens on a few values:
R(0.5f) = 0f
R(1.5f) = 2f
R(2.5f) = 2f
R(3.5f) = 3f

This is a way to “fix” rounding to avoid positive/negative bias, but causes the GridPosition calculation to break when the GridSize is set to an odd number. To “fix” this you can instead use Floor(Position + 0.5f).
For this see the below examples for how it works.
1.7f = 2.2f = 2f
1.2f = 1.7f = 1f

Hope this all makes sense and helps.

One of the few times I will use Quaternions is for this case, I find they “look” better and aren’t as time dependent (probably using all the wrong words here), as in, I’m not giving an amount of time to complete the rotation, I am telling it to rotate at a certain speed so it looks more consistent. IMO

Vector3 direction = (moveTargetPosition - transform.position);
if ( direction != Vector3.zero ) {
    transform.rotation = Quaternion.RotateTowards(transform.rotation, Quaternion.LookRotation(direction), turnSpeed * Time.deltaTime);
}

Just realised I have necro’d this thread from oblivion, apologies!

Privacy & Terms