I just did this a few weeks ago for a gun turret system in my Jetpack Kurt Space Flight game, which is getting more combat mode targets.

This is the aiming portion (it’s a partial class):

**You should call StartAimer() from Start()**

**You should call UpdateAiming() from Update()**

```
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public partial class TurretBrainAndTargeter
{
// Feel free to make these public, drag them in using the Editor,
// then remember to REMOVE the StartAimer() method "FindChild" calls.
Transform traverse;
Transform elevate;
Transform muzzle;
float age;
void StartAimer()
{
// Transform STATE.FindChild(string) is just a typical "find by name" helper
traverse = STATE.FindChild( transform, "Traverse");
elevate = STATE.FindChild( transform, "Elevate");
muzzle = STATE.FindChild( transform, "Muzzle");
}
// set negative for no update
// set zero for every frame update
// otherwise it's an interval
public void SetUpdateInterval( float interval)
{
UpdateInterval = interval;
}
float TraverseSnappiness = 2.0f;
float ElevationSnappiness = 2.0f;
float DesiredTraverse;
float DesiredElevation;
Vector3 DeltaToTarget;
public void UpdateTargetTracking()
{
if (ValidTarget)
{
DeltaToTarget = ValidTarget.position - traverse.position;
DesiredTraverse = Mathf.Atan2( DeltaToTarget.x, DeltaToTarget.z) * Mathf.Rad2Deg;
float range = Mathf.Sqrt( DeltaToTarget.x * DeltaToTarget.x + DeltaToTarget.z * DeltaToTarget.z);
// this also elevates the barrel more so the bullet drop is (mostly) accounted for
// bullet drop is not precisely accounted for except in the case where you are at
// precisely the same Y. It's an approximation that does not take into account Y delta.
{
float timeInTransit = DeltaToTarget.magnitude / MuzzleVelocity;
float bulletDrop = (timeInTransit * timeInTransit) / 2;
DeltaToTarget.y += bulletDrop * Physics.gravity.magnitude;
}
DesiredElevation = Mathf.Atan2( -DeltaToTarget.y, range) * Mathf.Rad2Deg;
}
}
void Slew()
{
string s = System.String.Format( "T:{0}\nE:{1}", (int)DesiredTraverse, (int)DesiredElevation);
Quaternion trav = Quaternion.Euler( 0, DesiredTraverse, 0);
Quaternion elev = Quaternion.Euler( DesiredElevation, 0, 0);
traverse.localRotation = Quaternion.Lerp( traverse.localRotation, trav, TraverseSnappiness * Time.deltaTime);
elevate.localRotation = Quaternion.Lerp( elevate.localRotation, elev, ElevationSnappiness * Time.deltaTime);
OnTarget = false;
if (ValidTarget)
{
float angle = Vector3.Angle( DeltaToTarget, elevate.forward);
if (angle < 5) OnTarget = true;
s += "->" + angle.ToString( "0.0") + " (" + OnTarget.ToString() + ")";
}
// my debug output using my Datasacks module:
// DSM.SpaceFlightDebug1.ValueIfDifferent = s;
}
void UpdateAiming()
{
if (UpdateInterval >= 0)
{
age += Time.deltaTime;
if (age >= UpdateInterval)
{
age -= UpdateInterval;
UpdateTargetTracking();
}
}
Slew();
}
}
```

The GameObject hierarchy for my turret is:

```
GunTurret1_Prefab
Traverse
TurretGraphics
Elevate
BarrelGraphics
Muzzle
```

“Traverse” is the transform to spin around the Y (heading)

“Turret Graphics” is the housing of the gun, and the barrel sticks out of a slot in the front.

“Elevate” is the transform to rotate (local) around the X (elevation).

“Barrel Graphics” is the barrel sticking out

“Muzzle” is where to spawn the blast and bullet.

The string debugging code lets you display that string anywhere you want and it will tell you the attempted Traverse and Elevate values it is trying to get to.