- Home /
Calculate angle between two locations, and then rotate object to face target based on this.
I have a projectile that i want to seek a target. I don't want to use the look at function because i don't think i can change how quickly it looks at the target. I have my projectile constantly moving forward:
transform.Translate(new Vector3(0,0,-(ProjThrust * Time.deltaTime)));
so no matter what orientation it is, it will move forward. Then i plan to just rotate the projectile up/down or left/right (by a certain variable amount) to seek my target.
At first i tried splitting up my rotations into up/down and left/right, by defining a triangle encompassing these two "planes" i made. If i can determine the angle to the target i can figure out of my target is to the left or right of my target by using its location.
Now i tried using this: http://answers.unity3d.com/questions/15822/how-to-get-the-positive-or-negative-angle-between.html
to find out how to figure out the angles on both of my axis and then rotate the direction needed based on the angle. This method doesn't seem to work.
Next i tried making a triangle out of each position's x and z locations to make a plane and a triangle to figure out the angle. i used:
float SideO = Mathf.Abs(transform.position.z - targetLocation.z);
float SideA = Mathf.Abs(transform.position.x - targetLocation.x);
float targetAngle = Mathf.Atan(SideO / SideA) * Mathf.Rad2Deg;
This picture shows what i mean by by my horizontal plane, the z is used for my depth but if i look at it form the side i can form a triangle with this data, and then calculate the angle and then if my x value is larger than my target (more right) i turn left, and i turn right if my x value is smaller.
This one describes the vertical movement, using z again for depth. And using the same kind of idea, if my y is less i move up, and i move down if my y is bigger.
Obviously i would check angles and see if i am within a threshold to be looking at my target, but tan doesn't work well with negative values, and neither does the unity angle functions (they wrap around 180 degrees or pi rads).
How would i use my current methods to determine how to rotate my projectile? Am i using the correct axis, or are the axis inconsistent if it rotates, and if so how do i determine axis of the object in world space and also in local space (to determine angle). I am confused on this.
I hope i explained this well and the pictures aren't too ugly. I don't know if this system has a "spoiler" or "image" hider tags.
I can answer you're question but a quick question to you.. do you absolutly want to rule out a LookAt ? as I think I can give you a very simple solution using lookat if you're interested - which allows a 'turnSpeed' so the rocket will gradually turn not instantly like you mentioned.
Answer by Rod-Green · Jan 01, 2012 at 01:21 AM
Try this..
One issue though is as the missile gets closer it can fall into a 'deadzone' which can cause you issues. This isn't because of the lookat or anything it's just because if you want to fix the rotation speed the missile can't turn quick enough.
One method, *cough* hack *cough* is to ignore rotation speed once the missile gets close enough.
There is also this more correct solution: http://gamedev.stackexchange.com/questions/17313/how-to-prevent-homing-entities-from-orbiting-their-targets
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Missile : MonoBehaviour
{
public Transform m_target;
public float m_moveSpeed = 1.0f;
public float m_turnSpeed = 1.0f;
public int m_maxTail = 10;
List<Vector3> m_prevPoints = new List<Vector3>();
void Update()
{
Quaternion lookAt = Quaternion.LookRotation(m_target.position - transform.position);
transform.rotation = Quaternion.Lerp(transform.rotation, lookAt, Time.smoothDeltaTime * m_turnSpeed);
transform.Translate(Vector3.forward * m_moveSpeed);
if(m_prevPoints.Count == m_maxTail)
m_prevPoints.RemoveAt(0);
m_prevPoints.Add(transform.position);
for (int i = 0; i < m_prevPoints.Count - 1; i++)
{
Debug.DrawLine(m_prevPoints[i], m_prevPoints[i + 1], Color.green);
}
}
}
I dont recognize the " List m_prevPoints = new List();" so ill read up on that. this seems to be what i am looking for. thanks! ill post here if there are any problems. I knew there could be a gimble lock problem, and a target rotation problem (i can try to detect if it is orbiting, and then just slow its speed so it can turn more and face its target).
What is max tail supposed to keep track of? the distance since the last tail marker? Or the beginning of a tail marker? And why use smoothdeltatime over regular delta time? If smooth is better, then why have regular?
The list and the trail are just to indicate the path traveled and are not important so don't worry about them
Hmm this doesnt seem to work. I tried it (couldnt test lately due to new rom and bugs on tablet) and the code just makes my projectile move upwards (while target is in front of projectile)
here is my code:
Quaternion lookAt = Quaternion.LookRotation(targetLocation - transform.gameObject.transform.position);
transform.gameObject.transform.rotation = Quaternion.Lerp(transform.gameObject.transform.rotation, lookAt, ProjTurnRadiusDegreesPerSec);
transform.Translate(new Vector3(0,0,-(ProjThrust * Time.deltaTime)));
This is in the update method of my script. Target is my ship gameObject's position.
What is wrong?
Here are pictures to demonstrate my problem:
Please don't post followup questions as answers. You should read the FAQ http://answers.unity3d.com/page/faq.html
Hmm this doesnt seem to work. I tried it (couldnt test lately due to new rom and bugs on tablet) and the code just makes my projectile move upwards (while target is in front of projectile)
here is my code:
Quaternion lookAt = Quaternion.LookRotation(targetLocation - transform.gameObject.transform.position);
transform.gameObject.transform.rotation = Quaternion.Lerp(transform.gameObject.transform.rotation, lookAt, ProjTurnRadiusDegreesPerSec);
transform.Translate(new Vector3(0,0,-(ProjThrust * Time.deltaTime)));
This is in the update method of my script. Target is my ship gameObject's position.
What is wrong?
firstly.. no need to do : 'transform.gameObject.transform.xxxx' where 'transform.xxx' will work fine.
Secondly I'm not sure waht ProjTurnRadiusDegreesPerSec actually equals but you need to multiply it by Time.deltaTime to get this to work.
You might want to add a 'up vector' to the look rotation see if that helps..
this works fine on my machine
Quaternion lookAt = Quaternion.LookRotation(m_target.position - transform.position, Vector3.up);
transform.rotation = Quaternion.Lerp(transform.rotation, lookAt, ProjTurnRadiusDegreesPerSec * Time.deltaTime);
transform.Translate(new Vector3(0.0f ,0.0f , (ProjThrust * Time.deltaTime)));