Rotate so the left/right direction faces the target

Hi
I am trying to make my spaceship to rotate so the sides (not the front) faces the target - cus that’s where the main guns is. I’ve been trying a lot of things, but nothing seem to work right. Any suggestions on how to get this to work properly? Thanks in advance for any good answers :slight_smile:

I’ve used this code:
function Update () {
var dir = GameObject.FindGameObjectWithTag(“point”).gameObject.transform.position - transform.position;
dir.y = 0; // use this to keep the direction strictly horizontal
// gradually rotate left side (-right) in direction to the target:
transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.FromToRotation(-transform.right, dir), 2.5 * Time.deltaTime);
}

Example pictures
Blue line = Front
Red line = left side of ship
Green line = where the target is

Start position (before rotation):
The ship should rotate 45deg.
2208461--146770--upload_2015-7-17_9-47-27.png

End position (after rotation is done):
You can clearly see that the object won’t rotate all the way (45deg)…
2208461--146771--upload_2015-7-17_9-48-10.png

please use [code ][/code ] tags when pasting in code to the forums, really helps with the readability, there is a sticky on them at the top of the scripting forum.

that slerp function doesn’t look right. Slerp and lerp are simply functions to work out midpoints, you’re passing the current and final rotations as parameters and asking for a rotation some small % between the two, that’s going to return an ever decreasing amount.

the Quaternion.Slerp(…) api page doesn’t have a very good example, have a look at the Vector3.Lerp(…) page instead (it’s all the same idea :slight_smile: )

Firstly, GameObject.FindGameObjectWithTag is super expensive (as are all the GameObject.Find* static methods), you really shouldn’t be doing that in an update loop, ever. Cache a reference and use that instead.

Secondly, you’re attempting to rotate an absolute rotation towards a relative rotation. You’re effectively saying "Hey ship, point yourself in the direction of (the angle between my right and the my target) as measured from the identity rotation.

However, for this I’d avoid rotations, they shouldn’t be necessary as you can actually assign a Vector3 to transform.right.

Totally untested pseudo code…

var shipA = player.transform;
var shipB = target.transform;

var direction = (shipB.position - shipA.position).normalized
shipA.right = Vector3.Slerp(shipA.right, direction, Time.deltaTime * rotationSpeed);

I’m using Slerp here because we’re dealing with unit length direction vectors that are multiplied into the rotation Quaternion. Lerp would also work but the motion wouldn’t be linear. You should also probably measure the angle between and factor that into the rotation speed as well.

(editet)
Hi. Thanks for answering (both of you), but I didn’t get much out of it (call me a noob) :wink:
I’ve looked at the vector3.lerp example - and tried to tweak it into rotation - but with no luck.

So what you say is that i should not send in the current position into the slerp/lerp as a from variable? I’ve tried with a static “from”-variable, but the I got some wierd behaviour. And what if the target is moving - the ship should constantly try to rotate after it.

I’ve been trying for hours now…can you please come up with an example that works? It was easy to get the ship to allways fly toward the point - even when I move the point around. But this rotation was pain…

Cameron: I’m just looking up the target on the fly now…I will replace that code with a better refrence later (player selects target etc)
Testing your approach now Cameron…

Thanks, Cameron. I’ve tried something similar, but that example worked - but I’m only half there.
You see, there is nothing that says “.left” for the transform direction. If the target is closer to the left side of the ship, it should not rotate all the way round. I think I can calculate which way to rotate, but how do I get the left side aligned up?

I’ve previously used “-transform.right” as left, but I can’t see how to adapt your example to do the same. Any tips?

You’ll probably want to have a look at the dot product. Vector3.Dot(vectorA, VectorB); If given two unit length direction vectors, the result of the dot product will be between -1 and 1.

< dot < = 1;
< dot ^ = 0;
< dot > = -1

You can use this with transform.right and the direction to target vector. If the value is greater than zero then you’re turning in the other direction.

You should be able to use transform.right still, just flip the sign before you apply it. transform.right = -targetVector is the same as transform.left = targetVector;

Likewise, transform.right = -transform.right will instantly turn an object 180 degrees.

Thanks again! That helped alot. Learned a few new things today :slight_smile:
Now the ship turns the right way!
This is the code that will turn the ship right/left side towards the target:

var shipA = gameObject.transform;
var shipB = GameObject.FindGameObjectWithTag("point").gameObject.transform;
     
var direction = (shipB.position - shipA.position).normalized;
if(Vector3.Dot(shipA.right, shipB.position) > 0) {         
            shipA.right = Vector3.Slerp(shipA.right, direction, Time.deltaTime * 5);
} else {
            shipA.right = Vector3.Slerp(shipA.right, -direction, Time.deltaTime * 5);
}

Using Time.deltaTime for the t value to a lerp function is probably not what you want. Please see this fine article.

I’ll read that article, blizzy :slight_smile:

Nice article blizzy, I’d suggest you also mention PID controllers as an alternative to interpolation in general. For most movement in games interpolating between A and B and trying to fit curves that feel right works fine when A and B are fixed in space and time, but when they’re not most people seem to just keep adding on additional layers of fudge to try and get it right not realizing there’s a much simpler way to approach those kind of problems.

In fact, passing delta time into Lerp is a form of PID controller with Ki and Kd gains of zero, aka a Proportional controller so it’s not necessarily always a bad thing but you don’t get acceleration from it and as as a dev you should be aware of what is happening when pass dt’s into lerp.