- Home /
Return Proper Velocity of Player object
Ok so I am basically trying to create a boolean method isMoving() for a player controller script to be used with an animator. That being said I know there are a few options for this, but I have discovered something quite disturbing, those methods rely completely on how you move the player object. For example:
If I move a player object using
// agent is our navmesh agent
agent.destination = destination;
Then I can get the agents velocity and it actually return something other than 0.
However if I move my player object using
transform.position = Vector3.MoveTowards(lastPosition, targetHit.point, Time.deltaTime * 5.0f);
Then the velocity returns 0;
Same scenario for Rigidbody velocity.
I don't wan't to use the navmesh agent to control my movement for many reasons that aren't relevant to this topic.
My problem is this! I have an idle state, when that idle state is running it changes the x,y,z of the character even though they don't actually move, so, something like this:
movementSpeed = (transform.position - lastPosition).magnitude / Time.deltaTime * 5.0f;
will spike movement speed up to 4 or 5 just during the animation, the rest of the time it is printing a floating value of something below 0.
I only want isMoving to be true, if the player is actually moving, not just standing idle. I can't figure out what to do here, I have tried taking the x and z cooridinates and absoluting them, adding them, all kinds of math many different ways, but nothing seems to work the way agent.velocity.magnitude worked (perfectly btw!) when I was using agent.destination as the way to move my agent.
I need the resulting number, be it float or int or w/e to be used in deciding if the object is moving at all, AND deter$$anonymous$$e the rate of how fast it's moving.
Answer by Harinezumi · Jan 24, 2018 at 08:49 AM
You get 0 velocity with Vector3.MoveTowards()
, because you don't use physics, you directly assign the return value of MoveTowards()
to the position, which is instantaneous movement, without velocity.
Your calculation of movementSpeed
is OK, although it can suffer from floating point imprecision. Instead I would recommend to move the animated model onto a child of your player game object, and move the player game object with physics, adding forces or velocity to its rigidbody. This way the animation will not affect your modeling of movement.
A different way to do this is to check if (transform.position - lastPosition).magnitude
is below a certain limit, e.g. 0.01f, in which case you consider it to be stopped. Note that you could also use sqrMagnitude
and square your limit value as well, which makes things more efficient, but then you can get into floating point imprecision zone again...
Yes I know the reason velocity isn't returned is because I am translating the transform directly. That still feels wrong to me, the velocity of the game object should be able to be found anyways.
What do you mean move the animated model onto a child of my player game object. The player object is the model I'm animating!!!??? I don't understand what you are saying here.
As far as the limit example of 0.01f
That is what I was trying to do, but it's useless when it still spikes to well above 1.0f while standing still.
What I'm saying is that the animated visual model and the player game object don't have to be the same object. This way you separate the visual representation from the logical and positional representation (I would upload an image example, but it doesn't work :( ).
I means something like this:
- Player (had Collider, Rigidbody, PlayerControl script)
- Visual$$anonymous$$odel (has some kind of Renderer, maybe even $$anonymous$$esh Filter, Animator)
Does this make more sense?
I'm puzzled why your velocity spikes in idle state with that calculation, it really shouldn't, unless lastPosition
is not set correctly all the time.
Ok so what you are saying is if the animator is if I move the animator to a different sub level on the same game object, it won't effect the same transform, yet the animator will still work as intended, thus eli$$anonymous$$ating the movements of the animator in the calculations of the transform for the root?
It spikes during the biggest movement, and yes I am setting the last position correctly, see other replies comments for fixed update method I am using.
Another interesting fact, rigidbody velocity doesn't actually stay 0 it randomly generates a number without me doing anything. 0,0,0,0,0, 1639, 0,0,0,0 1639, 0,0 something like that... weird...
Answer by Pangamini · Jan 24, 2018 at 08:54 AM
If you don't want to use rigidbody, you can use the (transform.position - lastPosition).magnitude
approach, but I'd strongly suggest you to do that in some fixed step (and therefore constant deltaTime) to avoid floating point inprecision fluctuations. You can use the FixedUpdate for that purpose. Just remember to store the lastPosition in the same fixed update as well.
Did you read the entire thing.... I said I did that approach. It doesn't work for me! It doesn't work because it spikes too high, and changes with IDLE animation.
Well I don't see you mentioning fixed delta time / update, but maybe I am just missing it somehow
Ok I don't specify where I used that approach. I am sorry for being snippy when you are trying to help, but man all you did was recommend I try to use an approach that I already stated doesn't work for me and why it doesn't work for me. Yes i used that approach correctly my Fixed update looks like this
void FixedUpdate()
{
if(!isLocalPlayer)
return;
movementSpeed = (transform.position - lastPosition).magnitude / Time.deltaTime * 5.0f;
lastPosition = transform.position;
if (Pressed$$anonymous$$ovementButton() || Holding$$anonymous$$ovementButton())
{
target.IsSelected = false;
if (Holding$$anonymous$$ovementButton())
{
Control$$anonymous$$ovementWithButtons();
}
}
}
use Time.fixedDeltaTime when in FixedUpdate(). That's all you need to stop the spikes.
Answer by Codinablack · Jan 24, 2018 at 10:59 PM
Anybody else out there got some clever ideas on how to make this work correctly?