Digging around I see sample code using many different methods, some seemingly more concise and compact than others. What is the best way to rotate a turret around the Y axis to face a target over x period of time?
This is what I came up with plucked from my turret class. Hopefully it helps someone.
function Update () {
if (isVehicle && stateTracker.state != stateTracker.GROUNDED) {
return;
}
// If enemy is set, turn turret
if (target) {
var clampHorizontal : Vector3 = new Vector3(0, 1, 1);
var clampVertical : Vector3 = new Vector3(1, 0, 1);
// Get the Quaternion value of the turret pointing at the target
var currentTurretRotation : Quaternion = turret.transform.localRotation;
turret.transform.LookAt(target.transform.position);
var targetTurretRotation : Quaternion = turret.transform.localRotation;
turret.transform.localRotation = currentTurretRotation;
// Clamp it to only y axis
currentTurretRotation.eulerAngles = Vector3.Scale(clampHorizontal, currentTurretRotation.eulerAngles);
targetTurretRotation.eulerAngles = Vector3.Scale(clampHorizontal, targetTurretRotation.eulerAngles);
// At what angle will we be aimed at target?
horizontalFiringSolution = targetTurretRotation;
// Rotate it over time
turret.transform.localRotation = Quaternion.RotateTowards(currentTurretRotation, targetTurretRotation, horizontalSeekSpeed);
var currentBarrelRotation : Quaternion;
var targetBarrelRotation : Quaternion;
switch (projectileType) {
case ProjectileTypeEnum.Projectile:
var solutionAngle = CalculateProjectileFiringSolution();
// Not enough range
if (solutionAngle != null) {
verticalFiringSolution = new Quaternion();
verticalFiringSolution.eulerAngles = new Vector3(solutionAngle, 0, 0);
currentBarrelRotation = barrel.transform.localRotation;
targetBarrelRotation = verticalFiringSolution;
barrel.transform.localRotation = Quaternion.RotateTowards(currentBarrelRotation, targetBarrelRotation, verticalSeekSpeed);
}
break;
case ProjectileTypeEnum.Beam:
// Get the Quaternion value of the barrel pointing at the target
currentBarrelRotation = barrel.transform.localRotation;
barrel.transform.LookAt(target.transform.position);
targetBarrelRotation = barrel.transform.localRotation;
barrel.transform.localRotation = currentBarrelRotation;
verticalFiringSolution = targetBarrelRotation;
// Clamp it to only the x axis
currentBarrelRotation.eulerAngles = Vector3.Scale(clampVertical, currentBarrelRotation.eulerAngles);
targetBarrelRotation.eulerAngles = Vector3.Scale(clampVertical, targetBarrelRotation.eulerAngles);
// Rotate it over time
barrel.transform.localRotation = Quaternion.RotateTowards(currentBarrelRotation, targetBarrelRotation, verticalSeekSpeed);
break;
}
}
}
function CalculateMaximumRange() {
var barrelTransform = gunMuzzlePoint.transform.position;
var g = Physics.gravity.y;
var y = barrelTransform.y;
var v = projectileSpeed;
var a = Mathf.Deg2Rad * 45;
var vSin = v * Mathf.Cos(a);
var vCos = v * Mathf.Sin(a);
var sqrt = Mathf.Sqrt(vSin * vSin + 2 * g * y);
return Mathf.Abs((vSin / g) * (vCos + sqrt));
}
function CalculateProjectileFiringSolution() {
var targetTransform = target.transform.position;
var barrelTransform = gunMuzzlePoint.transform.position;
var y = barrelTransform.y - targetTransform.y;
targetTransform.y = barrelTransform.y = 0;
var x = (targetTransform - barrelTransform).magnitude;
var v = projectileSpeed;
var g = Physics.gravity.y;
var sqrt = (v*v*v*v) - (g * (g * (x*x) + 2 * y * (v*v)));
// Not enough range
if (sqrt < 0) {
return null;
}
sqrt = Mathf.Sqrt(sqrt);
// DirectFire chooses the low trajectory, otherwise high trajectory.
if (directFire) {
return Mathf.Atan(((v*v) - sqrt) / (g*x)) * Mathf.Rad2Deg;
} else {
return Mathf.Atan(((v*v) + sqrt) / (g*x)) * Mathf.Rad2Deg;
}
}
function isTargetInFiringArc() {
GetTarget();
if (target && verticalFiringSolution != null) {
// How far are we from our firing solution.
var horizontalOffset = Quaternion.Angle(horizontalFiringSolution, turret.transform.localRotation);
var verticalOffset = Quaternion.Angle(verticalFiringSolution, barrel.transform.localRotation);
var distanceToTarget = target ? target.transform.position - transform.position : Vector3.zero;
if (distanceToTarget.magnitude < minRange) {
return false;
}
// Doesn't work too well looking for 100% perfect accuracy, so substitute .1
if (deviation == 0 && horizontalOffset < .1 && verticalOffset < .1) {
return true;
} else if (horizontalOffset < deviation && verticalOffset < deviation) {
return true;
}
}
return false;
}