Hi! I’m still learning how to use Unity so, if this is a really stupid question, I’m sorry. I’m trying to get a combat system working and I’m testing it on two AI characters. Right now, what I’m trying to get working is them turning to face each other so that they’re actually shooting at each other. Here’s my code minus comments and print statements.
enemy and myRotation are defined elsewhere. enemy is the enemy’s collider. myRotation is the AI character’s current rotation.
When I hit play, one of the AI characters turns. But he would have to turn about 180 degrees to be facing the other character. Instead, he only turns about 105 degrees. The other character stays perfectly still. I used print statements and found out that, no matter how I change the relative positions of the two characters, Quaternion.LookRotation always returns {0.0, 0.0, 0.0, 1.0} and the reason one character didn’t turn at all is that he happens to already be facing in that direction. But I can’t figure out why Quaternion.LookRotation is always returning the same thing. Does anyone have any ideas? Am I doing something stupid?
Thanks!
Output each involved variable to look for something unusual. Start with relativePos - If LookRotation is the same, that strongly suggests that relativePos is the same each time (and, presumably, wrong). And output the components that go into it, too. I find this sort of log to be helpful in getting a real-time, bird’s eye view of your variables.
If not that, output your “str” variable. Your Mathf.Min call might have some int/float issues (you’re feeding it at least one int, it may be confused whether to return a float or int).
This looks like a common misunderstanding of the Lerp() family of functions. While Lerp() is often described as providing smooth movement from one position or orientation to another, it doesn’t actually do that on its own, though it can be a tool to do that with some additional supporting code.
What it does do is simply find an intermediate position/orientation between the initial and final, based on the value of the third parameter. Values closer to 0 result in an intermediate position/orientation closer to the initial, and values closer to 1 produce outputs closer to the final. You’re passing in what it probably a really small value (Time.deltaTime is simply the duration, in seconds, of the last frame, which tends to be around 0.017), so the orientation returned by Lerp() is really close to the current orientation of the character.
First try removing the Lerp() altogether, and assigning rotation directly, just to confirm that it is the correct orientation.
If so, the easy way to use Lerp() to smoothly rotate is to change TurnToFaceEnemy() into a coroutine. This way, you call Lerp() and assign rotation multiple times, once per frame, updating that third variable smoothly from 0 to 1.
public IEnumerator TurnToFaceEnemy() {
Vector3 relativePos = enemy.transform.position - pos;
Quaternion initialRotation = myRotation;
Quaternion finalRotation = Quaternion.LookRotation (relativePos);
float angle = Quaternion.Angle(initialRotation, finalRotation);
float startTime = Time.time;
float duration = angle / turnRate; // Turn rate is in degrees per second.
while (Time.time - startTime < duration)
{
float t = (Time.time - startTime) / duration; // This is the current progress over time, from 0 to 1.
transform.rotation = Quaternion.Lerp (initialRotation, finalRotation, t);
yield return null; // This waits for the next frame before continuing to execute code.
}
transform.rotation = finalRotation;
}
//Wherever you call TurnToFaceEnemy(), change it to:
StartCoroutine(TurnToFaceEnemy());
If you need to be able to cancel the turning animation (perhaps a new enemy shows up and the turning characters need to stop what they’re doing and turn to face the new enemy), then you can save the return value from StartCoroutine() in a class field, and use that later to stop the coroutine.
Thanks for responding, everyone!
Sorry, takatok! I didn’t notice that I had another variable that wasn’t set there. Thanks for asking where pos was set! I thought I was updating it every frame. It turned out I wasn’t. Once I fixed that, they started turning the way they’re supposed to.
Thanks, AndyGainey, for the explanation of Lerp! Searching for information online about turning things, I’d seen someone using it. I didn’t realize it wasn’t a smooth turn.
Sorry for bothering you guys over a silly mistake! Thanks again!
Also try to get at what @AndyGainey was saying. A lerp says give me a value between a and b, based on a float t between 0 and 1. so if you give it .5 it will give a a point halfway betweeen a,b. So ideal you want to have a static startRotation (a) and static endRotation(b) and slowly increase t over time.
With the way your doing it your updating the start rotation each with the value it lerped to. So say you going from 10 to 20 and the time between each lerp is .1. Ideally you want to go 10,11,12,13,14…20. But your code will go
10,20, .1 == 11
11,20, .1 = 11.9
11.9,20,.1 = 12.71.
Each time your going to move slower and slower to the goal because the distance from the start to the goal is getting smaller. Now depending on the frameRate it might not be too noticeable and you will eventually “Get there”… but if you watch closely i bet your guy turns fairly fast to start and starts turning slower near the end.