- Home /
Doesn't Add Rotation Over 180
I'm using this script to make an AI walk around smoothly instead of making jerky turns. Here's ta script I whipped up in a couple minutes:
public float speed;
public float rotateSpeed;
public float minWalkTime;
public float maxWalkTime;
public float minRotateAmount;
public float maxRotateAmount;
public bool rotate;
public float timeToNewDir;
private Transform student;
private CharacterController controller;
void Awake () {
student = transform;
controller = student.GetComponent<CharacterController>();
}
void Update () {
Wander();
if(rotate){
Rotate(minRotateAmount, maxRotateAmount);
}
}
void Wander () {
float idleTime = Random.Range(minWalkTime, maxWalkTime);
if(Time.time > timeToNewDir){
timeToNewDir = Time.time + idleTime;
rotate = true;
}
var fwd = student.TransformDirection(Vector3.forward);
controller.SimpleMove(fwd * speed);
}
void Rotate (float minAmount, float maxAmount) {
float rotateAmount = Random.Range(minAmount, maxAmount);
Quaternion newRot = student.rotation;
newRot.y += rotateAmount;
student.rotation = Quaternion.Slerp(student.rotation, newRot, rotateSpeed * Time.deltaTime);
if(student.rotation == newRot){
rotate = false;
}
}
The problem is, once "y" has become 180, the AI no longer turns, even though he should. The script doesn't stop executing, the rotation just isn't going though. Does it have to do with it being a Quaternion?
Answer by aldonaletto · Aug 04, 2012 at 11:42 AM
@Akill is right: the quaternion components XYZ have nothing to do with those nice angles you see in the Inspector (they are the localEulerAngles).
But your code had other problems too: Rotate will be called every frame, defining new orientations each time, and you probably would never get an equality to set rotate to false due to the limited floating point precision.
A better approach is to define the desired angle (yAngle) in Rotate and make the character always follow this angle smoothly at Update:
... private CharacterController controller; // declare these new variables: private Vector3 curEuler; // holds current rotation angles private float yAngle; // holds desired angle around Y
void Awake () {
student = transform;
controller = student.GetComponent<CharacterController>();
curEuler = student.eulerAngles; // initialize the new variables
yAngle = curEuler.y;
}
void Update () {
Wander();
// smoothly follows the desired yAngle:
curEuler.y = Mathf.Lerp(curEuler.y, yAngle, rotateSpeed * Time.deltaTime);
student.eulerAngles = curEuler;
}
void Wander () {
float idleTime = Random.Range(minWalkTime, maxWalkTime);
if(Time.time > timeToNewDir){
timeToNewDir = Time.time + idleTime;
Rotate(); // just set the new direction
}
var fwd = student.TransformDirection(Vector3.forward);
controller.SimpleMove(fwd * speed);
}
void Rotate (float minAmount, float maxAmount) {
float rotateAmount = Random.Range(minAmount, maxAmount);
// just add rotateAmount to yAngle modulo 360:
yAngle = (yAngle + rotateAmount) % 360;
}
That worked better than I thought it would! Thanks, that makes sense.
Answer by Akill · Aug 04, 2012 at 11:14 AM
Yes, Quaternions can not be used like this. You will need to create a new Quaternion which will hold the new rotation you want. To apply this rotation to the previous rotation, you multiply the 2 quaternions together.
void Rotate (float minAmount, float maxAmount) {
float rotateAmount = Random.Range(minAmount, maxAmount);
Quaternion newRot = student.rotation;
newRot*= Quaternion.Euler(0,rotateAmount,0);
student.rotation = Quaternion.Slerp(student.rotation, newRot, rotateSpeed * Time.deltaTime);
if(student.rotation == newRot){
rotate = false;
}
}