- Home /
How to determine the direction an object is moving relative to itself?
Hi there, thanks for looking at my question.
As per the title, I'm having a bit of difficulty finding a reliable method of determining the direction an object is moving relative to itself. I'm not looking for a way to control an object or anything like that, but if an object is in motion already I need a way to determine the direction it's headed relative to itself. I need this so that no matter where it's facing or what it's doing relative to the camera or the world, if it moves sideways (relative to itself), my script will know it is doing so. Same goes for any other direction.
Right now I've cobbled together something using velocity, but it's far from ideal as the numbers it gives me to work with are all over the place and unreliable for this type of thing.
Any help would be greatly appreciated.
Answer by robertbu · Apr 19, 2014 at 06:16 PM
Assuming you have a method of getting the world velocity such as Rigidbody.velocity, or comparing positions between frames, you can get the local velocity by using Transform.InverseTransformDirection(). For example:
var localVelocity = transform.InverseTransformDirection(rigidbody.velocity);
As for moving sideways, look at localVelocity.x. Negative values are left movement, positive values are right movement.
If you are calculating velocity yourself by comparing positions, you may want to average values over a number of frames.
Sadly, this isn't a hugely reliable method, at least in my experience so far. I have something very similar and I have x, y and z exposed in the inspector so I can keep an eye on them. In the example of moving left, the x value will flicker rapidly between -2 and -5, though it goes as high as -9 and, sadly, can go far enough the other way that it reaches up to 0.5, which causes obvious issues with relying on it being negative. I spent quite a while testing it and couldn't find a solution, which is when I came here.
Do you know of a way to make this method more reliable? From what I've seen, everyone suggests this and I'm sure plenty of people must have a perfectly fine way of going about it, but I am as yet unsuccessful.
'localVelocity' should only change as rapidly as rigidbody.velocity changes. You will get rapid changes during collisions or if you are assigning directly to rigidbody velocity, but if you are driving your object through Add.Force() I would not expect to see rapid changes. You can average the velocity over time to smooth out rapid changes.
I am doing something similar and can confirm that if you are moving your character via a rigid body with addForce this works wonderfully. Thank you.
Answer by NickP_2 · Apr 19, 2014 at 06:11 AM
You can calculate the direction with the endposition and currentposition, its as easy as:
Endposition - currentposition = direction
Both end and current position are vector3
I'm not sure I understand this. Do you mean that I just subtract it's current position in Vector3 format from where it ends up? If so, I don't know how I'd use the end result to deter$$anonymous$$e the direction it's moving in relative to itself. Could you please elaborate?
This calculation will give you the world direction. You would use Transform.InverseTransformDirection() to get the direction relative to self. Something like:
var direction = transform.position - lastPosition;
var localDirection = transform.InverseTransformDirection(direction);
lastPosition = transform.position;
Note you will not get a usable direction if the object is stationary.
Was scanning around for a solution to getting a dog character to follow another one and change animation direction based on which way it was facing.
(I originally tried to tie it to the leading character but because I was lerping its position to make it more doglike it kept switching before its movement direction had actually changed).
this way works a treat as the dog character is still lerping around behind the main one, but now can deter$$anonymous$$e its own direction without reference to the direction of other objects. awesome bit of code! thanks
Apologies for it taking such a long time to get back to this. Afraid a medical incident prevented me from looking at screens for some time. Robert's answer was very helpful and my solution was based on that. If you see this and care to post it as a new answer, I will accept it as correct. Thanks!
Answer by koray1396 · Apr 19, 2014 at 06:25 AM
let's say your object is a car and you want to know the direction (going backwards, forward, sliding on the right etc...) right?
if so, you need two things;
velocity of your object
rotation of your object
with those you can do this;
theDirection = Quaternion.FromToRotation(object rotation * Vector3.up, Quaternion.identity * Vector3.up) * velocity
With these two, you would get a rotated vector of your velocity, to 0 rotation of your object.
this came later to my mind;
theDirection = Quaternion.Inverse(object rotation) * velocity
I hope this helps. good luck.
This sounds like it might be what I need, but for some reason I'm having difficulty converting the objects rotation into a Vector3 so it can be used with FromToRotation. Converting Quaternion.identity was easy enough, so I'm not sure why this is giving me difficulty. I feel rather embarrassed to have to ask for help on such a simple matter as this, but if you could see your way to doing so I would be very thankful.
Alrighty, that did the trick as far as the code goes. Sadly, it's about the same result as the code I managed to put together. If I set an object in motion, in any direction, the numbers showing up flicker wildly between 1 and 9 (or negative 1 and 9, depending on direction of movement) and, even when no longer moving, one of the axis tends to sit at about 2 or 3 (though that, of course, could be easily solved).
I imagine velocity isn't a reliable method for this and lies at the heart of the problem.
how do you find the velocity? because this just reverses direction, therefore if your velocity values are problematic, that would cause bad results.
things you may try - Normalize the velocity by Vector3.Normalize() to get a vector with length of 1, always specifying a direction - as robertbu suggested, you may get an average with a number of frames.
You may use invokerepeating to get the velocity every fixed period, such as 0.1s, put them on an array, get the average of last 0.5 seconds for example. this would give you more stable values.