Movement distance per frame providing choppy values
Hi everyone
I have some code in a 2D project which is held on an NPC who follows the player on a Lerp. This means the NPC slows down as she approaches the player (which is what I wanted).
I have set up the Animator so that when the NPC slows down as she nears the player, we go from run to walk, and when she slow down to almost stopped, play the idle.
For the most part this works too, but as the NPC slows down, I suddenly get fluctuating numbers for a frame or two, forcing the run animation to briefly play.
Here is the relevant code in Update( ). I'd be very grateful if you have any insights or alternative methodologies I could try. I am a basic-intermediate coder.
function Update()
{
//Very small numbers so *1000
distanceTravelled = Vector3.Distance(transform.position, lastPosition) * 1000;
lastPosition = transform.position;
Debug.Log("Distance = " + distanceTravelled);
//creates choppy results as it suddenly produces high numbers for one frame as the NPC slows down
anim.SetFloat("DistanceToPlayer", distanceTravelled);
}
Thanks very much in advance for any help or ideas you can contribute.
Answer by Statement · Oct 27, 2015 at 07:32 PM
You are confusing me with something.
distanceTravelled appear to be the step you took from last frame to now. That is, "distance travelled this frame". Then you feed it into "DistanceToPlayer". Conceptually, that is not the same thing. You can hug the player (being not so distant from it), but going very very fast (distance travelled is large). It doesn't make sense.
Distance travelled does not mean distance to player.
Then you say that distanceTravelled becomes larger when you slow down. That also doesn't make sense. distanceTravelled will shrink because the step between your position from the last frame becomes smaller and smaller.
Finally, you could run into floating point precision problems when you scale numbers with 1000 etc. Also the positioning of the object itself is important for precision. I don't know if your character runs around at xyz 10000, 2000, 3120 or some ridiculously large number like that. That will for sure give you precision issues. Let's have a look at what Vector3.Distance(a, a+x) * 1000 produces in a graph.
First, let's view the result from an overview. Near center of game (XYZ 000) it looks pretty normal. Just a slope as we'd expect.
Still looks ok at XYZ 1000, 1000, 1000.
Starting to look weird at 10000, 10000, 10000.
But this is just the tip of the ice berg. If we zoom in on the graph, we can see that indeed we get precision problems even at ranges 1000 units off center. Have a look at this more zoomed in detail view.
Around centre (0, 0, 0)
Far out (1000, 1000, 1000)
Very far out (10000, 10000, 10000). Woah batman, that's one big stair case.
This is the function the graph was excercising.
public static float ExampleNear(float diff)
{
Vector3 position = new Vector3(0, 0, 0);
Vector3 lastPosition = new Vector3(0, 0, 0 + diff);
return Vector3.Distance(position, lastPosition) * 1000;
}
public static float ExampleFar(float diff)
{
Vector3 position = new Vector3(1000, 1000, 1000);
Vector3 lastPosition = new Vector3(1000, 1000, 1000 + diff);
return Vector3.Distance(position, lastPosition) * 1000;
}
public static float ExampleVeryFar(float diff)
{
Vector3 position = new Vector3(10000, 10000, 10000);
Vector3 lastPosition = new Vector3(10000, 10000, 10000 + diff);
return Vector3.Distance(position, lastPosition) * 1000;
}
Diff is the distance travelled since the last frame. Yes, those who are eagle eyed see that I put it on lastPosition and I agree that's silly of me but it doesn't matter for the math. But what it means is, if we are chasing someone, and we are very far out (like 1000 or 10000 units away from world center), you'll get very discrete return values. You'll get a sudden "jump" or "flickering" effect where the distance jumps between 0 and 4 or whatever. There simply isn't any values in between that are different.
If I were you, I would check that your game isn't oddly scaled or that your characters are running very far away from 0, 0, 0. And you shouldn't have to scale distance with 1000 for your animation stuff, just make the animation accept values that are real distances, if that is what you want to have.
Just to point out, this isn't a Unity specific issue. It's a floating point issue. Here's a sine curve of the same length, but at different offsets. Sin near 0, Sin near 1000000
First, thanks enormously for your extremely generous answer. You gave me a bunch of your time and experience there - I really appreciate it.
The DistanceToPlayer in my Animator was named from a previous implementation attempt, where I tried to get this right using Raycasts. It is badly named for this implementation, but I am aware of the conceptual difference and should get round to changing it.
It absolutely doesn't make sense, and I should be getting a constantly declining number towards zero, but I will look into whether my multiplier is the guilty party and retarget (and rename) my Animator values. Thanks for the suggestion.
I'll keep you posted, but thanks again. Awesome answer, whether the multiplier is the problem or not.
Your answer
Follow this Question
Related Questions
NPC Animation 0 Answers
Animation for each movement direction 0 Answers
Check distance between Player and GameObject 0 Answers
Npc and AI 1 Answer
Detect player movement 0 Answers