# Aiming a turret of arbitrary orientation

Hey all,

I’m trying to create a turret aiming system for a third person space shooter, and am running into problems with aiming turrets on the ship.

Basically I have an aim object, moved by the mouse that the turrets should point at. So far so good, that’s simple to do. Where I run into problem is another feature I want to have - I want the turrets to a specific firing arc.

``````Ship GameObject
-Turret Object (empty gameObject)
--Turret Base
---Turret Barrel
``````

The turret base should be locked to the ship in the local X and Z axes, and only be able to rotate around the Y axis. I’ll ignore the barrel stuff for the moment, but ideally it is locked in all but local X.

The Turret Base always has a local position and rotation of (0,0,0). This is so I can just set the transform’s localRotation.x and .z parameters to 0 to lock it to the ship. Positioning is done with the empty parent Turret Object. I copy the Turret Object and position it on my ship at an arbitrary location and orientation (could be upside down , at an angle or whatever).

My current setup looks like this. In the update function I run AimBase() and AimBarrel(). If I’m correct, what this should do is get a rotation pointing at the aimTarget’s position, then interpolate from current rotation to it using Quaternion.Slerp. Then I check the angle between that interpolated rotation and the turret’s original rotation (which I initialize in Start() ), and see if that exceeds my maximum aim angle. If it does, I do nothing.

After all that, I set the euler angles of the turret in X and Z to their original values (again, initialized in Start() ) to clamp it to the ship.

``````function AimTurretBase() {
var origPos:Vector3 = turretBody.position;
var targetPos:Vector3 = aimTarget.position;
var rotGoal = Quaternion.LookRotation(targetPos - origPos);

var actualGoal = rotGoal;

var curRot = Quaternion.Slerp(turretBody.rotation,actualGoal,Time.deltaTime*turretTurnRate);

if (turretRestricted) {
if (Quaternion.Angle (baseRotation ,curRot) > turretBodyMaxAngle) {
// if angle is greater than the maximum angle...
// Do nothing
} else {
turretBody.rotation = curRot;
}
} else {
turretBody.rotation = curRot;
}
// Lock to the rotation.
turretBody.localRotation.eulerAngles.z = turretZLocked;
turretBody.localRotation.eulerAngles.x = turretXLocked;
}
``````

It seems logical to me, but it doesn’t work in all situations. If the turret is on “top” of the ship, it seems to be fine, but if the turret is at any rotation other than that, it won’t work. It traverses to some random location - sometimes it looks like it’s trying to rotate the long way around.

Does anyone see something that I’ve missed? My idea is that the last locking bit is screwing it up as by careful debugging I have found that if the turret isn’t locked to the ship it performs just fine.

I think the problem is that aimTarget.position and turretBody.position are both in world coordinates, while you are setting a local rotation. I believe you want something like this:

`var localAim = turretBody.transform.InverseTransformDirection(aimTarget.position); var rotGoal = Quaternion.LookRotation(localAim);`

If this doesn’t work, I would recommend not using LookRotation, and instead manually setting the euler angles using some trig.

`var localAim = turretBody.transform.InverseTransformDirection(aimTarget.position); var rotGoal = Quaternion.Euler(localAim.x, localAim.z);`

That might not be exactly correct, but hopefully that points you in the right direction.

Yep, That worked. Thanks tons! For anyone interested:

``````// transform the aim position into local coords
var localAim = turretBody.parent.InverseTransformPoint(aimTarget.position);
var rotGoal = Quaternion.LookRotation(localAim);

var curRot = Quaternion.RotateTowards(turretBody.localRotation,rotGoal,Time.deltaTime*turretTurnRate);

var toCompare:Quaternion = turretBody.parent.localRotation;
toCompare.eulerAngles.z = 0;

//print(Quaternion.Angle (toCompare ,curRot));

if (turretRestricted) {
if (Quaternion.Angle (toCompare ,curRot) > turretBodyMaxAngle) {
// if angle is greater than the maximum angle...
// Do nothing

} else {
turretBody.localRotation = curRot;
}
} else {
turretBody.localRotation = curRot;
}

// always clamp the turret to the ship
turretBody.localRotation.eulerAngles.z = turretZLocked;
turretBody.localRotation.eulerAngles.x = turretXLocked;
``````