3

I've been struggling with what I think should be a very simple problem:

Diagram of the problem.

I know the current heading angle (say 15 deg), and given a target gameObject's transform, I want to calculate the angle that I should rotate towards to face the target. In the above example I want to calculate say 335ish deg.

Note that I need to calculate the target angle, I have another class that, given an angle, takes care of rotating the heading to the desired angle. I'm aware of the Transform.LookAt() and other similar functions, they don't apply in this situation because reasons (in the other class I basically calculate a Euler Quaternion and Lerp until I reach the target angle, due to project constraints, Transform.LookAt() doesn't work).

In the first approach, I tried calculating angle theta with the Dot product of Vector3.forward and the direction vector, didn't quite work right (either rotated forever or in the wrong direction)

Diagram of the problem

targetAngle = Vector3.Angle(Vector3.forward, (target pos - current pos).normalized);

I thought maybe if I could calculate the current heading direction vector, I could take the Dot product of that and the target direction vector to get angle theta, then use theta and the current angle to figure out the target angle (360 - theta or something?) to get the angle I want to rotate to. Thing is, I only have the current angle and current pos, I don't understand how to calculate the current heading direction vector from that info. Do I just add some arbitrary constant to the current position's Z value and subtract from that the current position, to get a dir vector? Seems hacky and like it shouldn't work.

Diagram of the problem

Any ideas are welcome.

Edit: Additional Info

The orientation code /u/Asad asked about:

    // Calculate the target Quat to rotate all children by
    Quaternion targ = Quaternion.Euler(0, 0, targetAngleHeading);
    // Calculate the Linear interpolation to apply to all children
    Quaternion lerp = Quaternion.Lerp(children[0].transform.localRotation, targ, Time.deltaTime * speedHeading_dps);

    foreach (GameObject c in children)
    {
        // Apply lerp calcualted above to all children
        c.transform.localRotation = lerp;
    }
    // Update the current heading angle 1st child's local z angle
    currentAngleHeading = turrets[0].transform.localEulerAngles.z;

Then in FixedUpdate() I have:

    if (currentAngleHeading != targetAngleHeading)
    {
        DesiredHeading();
    }
Murkantilism
  • 1,060
  • 1
  • 16
  • 31
  • Is this in 2D? If not, you need a unit vector to indicate your current bearing, not a scalar angle like 15 deg. – Asad Saeeduddin Jul 24 '15 at 00:45
  • Also, it would help if you showed what your code does with the angle you're computing. You're correctly computing the angle between `(0, 0, 1)` and the desired heading. Are you sure your rotation code is also interpreting the angle provided relative to `(0, 0, 1)`? – Asad Saeeduddin Jul 24 '15 at 01:00
  • The comment "*didn't quite work right (either rotated forever or in the wrong direction)*", along with the evidence of your diagrams, strongly suggests that you have not been careful with your signs. The math you describe should be both correct and almost trivial to implement; about the only thin you **can** do wrong is to mix up your signs, – Pieter Geerkens Jul 24 '15 at 01:01
  • It's 3D, right I can [convert from angle to unit vector](http://math.stackexchange.com/questions/180874/convert-angle-radians-to-a-heading-vector), but where do I go from there? – Murkantilism Jul 24 '15 at 01:01
  • Yea I'm sure the rotation code in the other class works, I wrote another script that used it to ping-pong between two given angles, it works given a desired angle. – Murkantilism Jul 24 '15 at 01:02
  • @Murkantilism A single scalar angle doesn't have enough information for you to work out a unit vector indicating a direction in 3D space from it. Like I said, it would be really helpful if you could provide a brief overview of what your orientation code does with its inputs (and what inputs exactly it takes). It *should* only need a unit vector, and this unit vector is just `(target pos - current pos)/|(target pos - current pos)|`. – Asad Saeeduddin Jul 24 '15 at 01:10
  • @Asad - added the additional info you asked about to the OP. The code shown is for just the heading, a separate function does elevation. So in some sense it is sort of 2D in that the heading and elevation are handled separately. – Murkantilism Jul 24 '15 at 15:31
  • @PieterGeerkens - I don't think my signs are off, I've checked. So you're saying the first approach is correct and what should be working? – Murkantilism Jul 24 '15 at 15:31

2 Answers2

2

You can take your transform's forward, and the vector to your target, and get an angle or rotation from those:

Vector3 vectorToTarget = target.transform.position - transform.position;
Vector3 facingDirection = transform.forward; // just for clarity!

float angleInDegrees = Vector3.Angle(facingDirection, vectorToTarget);
Quaternion rotation = Quaternion.FromToRotation(facingDirection, vectorToTarget);

Note that the rotation is relative; i.e., it's the rotation you need to apply from the current position to be facing the target.

Dan Puzey
  • 33,626
  • 4
  • 73
  • 96
  • Right, I tried that sans the last step in my first approach. I just pass the angle in degrees to my other class that handles what you said in the last sentence, ie applying rotation from the current position to the given angle in degrees. I'm revisiting that approach, maybe I made a silly mistake somewhere – Murkantilism Jul 24 '15 at 16:29
  • Mmk so after re-implementing the first approach I noticed a small error. I was using Vector3.forward instead of children[0].transform.forward. After correcting that, the angle calculated was exactly the opposite of what I wanted, so I added 180 and modulo'd by 360 to get the correct angle to rotate to. Another thing, if I want to constantly or at least very regularly re-calculate these (say to rotate towards a moving target, or rotate while moving, or both) any suggestions on what I need to change or do? – Murkantilism Jul 24 '15 at 17:38
  • If you want to rotate smoothly (i.e. over a number of frames) you'll want to look at `Quaternion.Lerp` or `Quaternion.Slerp`. All of these are fast enough that you can recalulate every frame (assuming you don't have a million running at once!). If your angle was opposite then perhaps you were calculating the `vectorToTarget` value backwards. – Dan Puzey Jul 24 '15 at 19:44
  • I'm doing just that, if you look at my edit in the OP you'll see I use Lerp for the actual rotation. I'm correctly doing targetPos - currentPos for the direction vector calculation, any other idea why it might be opposite? – Murkantilism Jul 24 '15 at 21:10
  • To expand on "I'm doing just that" - although I'm using lerp, when I calculate the target angle each frame, it doesn't track movement properly. It ends up being off by a few degrees. If I trigger the target angle calculations just once, it's more exact but then cannot account for movement. – Murkantilism Jul 24 '15 at 21:12
0

try this instead

you can directly take the vector distance vector from transform.position and then vector3.normalize (target.position - object.position)

this is the angle object'll want to move