Turrets: Take 3

Good evening, everyone.

I’m working on setting up turrets on a spaceship. The code I have currently does work the way that I want it - for the most part. The gun rotates within the limits that I’ve set for it, and it even has a field of fire. However, the rotations are currently controlled with the mouse. I would like to have it be controlled by the computer instead. I’ve tried using the Quaternion.LookRotation method, but it ends up rotating the turret along two axis, rather than just one. Additionally, it also appears that the rotation limits that I’ve set up will not restict the movement of the turret once it’s set to use the LookRotation function. Does anyone have any suggestions for how I can ‘break apart’ the LookRotation Quaternion to get the information I need? I’m essentially trying to replace the mouselook code with values that will allow the LookRotation values to be used instead of the mouse input axis. Unless anyone else has a better idea, of course! :slight_smile:

Here’s the code as it currently stands. I know it’s a mess, but I will be cleaning it up and posting the final code once everything is working.

//This script is assigned to an empty object that contains the turret base and barrels as children.
using UnityEngine;
using System.Collections;

public class LargeTurret2 : MonoBehaviour {
	public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
	public RotationAxes axes = RotationAxes.MouseXAndY;
	public float sensitivityX = 15F;
	public float sensitivityY = 15F;
	public Transform myTarget;  //target object
	public GameObject turretBase; //turret base object.  Will rotate horizontally for aim.
	public GameObject turretElevation; //turret elevation object.  Will rotate vertically for aim, and contains the barrels.
	public GameObject gunLead;  //dummy object ahead of the barrels.  Used for the debug line on the current aim, not the target.
	public GameObject shipParent;
	
	//how fast the turret may turn in degrees per second.
	public float turretDegreesPerSecond = 30.0f;
	public float turretElevationDegreesPerSecond = 10.0f;
	
	private float allowFireCone = 5.0f;
	public float minimumX = -135F;
	public float maximumX = 135F;

	public float minimumY = -10F;
	public float maximumY = 60F;
	
	float rotationX = 0F;
	float rotationY = 0F;
	
	private Transform myTransform;  //this is the turret root object
	private Transform baseTransform;  //this is the turret base object
	private Transform elevationTransform;  //This is the turret elevation object
	private bool locked = false;
	
	Quaternion originalBaseRotation;
	Quaternion originalElevRotation;

	void Awake(){
		myTransform = transform; //the current turret object (empty gameobject).  Turret base is attached to this.
		baseTransform = turretBase.transform; //the turret base object.  Turret elevation object is attached to this.
		elevationTransform = turretElevation.transform; //the turret elevation object (empty gameobject).  Barrels are attached to this.
	}
	
	void Update () { //called every frame.
		//DEBUG code.  To be removed later.
		Debug.DrawLine(myTarget.transform.position, myTransform.position, Color.yellow);
		Debug.DrawLine(elevationTransform.position, gunLead.transform.position, Color.red);
		
		Quaternion rotate = Quaternion.LookRotation(myTarget.position - turretBase.transform.position, baseTransform.up);
		
		//Mouselook code.  Testing the angle restrictions.  This is the code that needs to be changed over to computer control, rather than user input.
		if (axes == RotationAxes.MouseXAndY)
		{
			// Read the mouse input axis
			rotationX += Input.GetAxis("Mouse X") * sensitivityX;
			rotationY += Input.GetAxis("Mouse Y") * sensitivityY;

			rotationX = ClampAngle (rotationX, minimumX, maximumX);
			rotationY = ClampAngle (rotationY, minimumY, maximumY);
			
			Quaternion xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up);
			Quaternion yQuaternion = Quaternion.AngleAxis (rotationY, Vector3.left);
			
			baseTransform.localRotation = originalBaseRotation * xQuaternion;
			elevationTransform.localRotation = originalElevRotation * yQuaternion;
		}
		else if (axes == RotationAxes.MouseX)
		{
			rotationX += Input.GetAxis("Mouse X") * sensitivityX;
			rotationX = ClampAngle (rotationX, minimumX, maximumX);

			Quaternion xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up);
			baseTransform.localRotation = originalBaseRotation * xQuaternion;
		}
		else
		{
			rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
			rotationY = ClampAngle (rotationY, minimumY, maximumY);

			
			Quaternion yQuaternion = Quaternion.AngleAxis (rotationY, Vector3.left);
			
			elevationTransform.localRotation = originalElevRotation * yQuaternion;
		}
		
		//Determine if the target is within the fire cone.
		Vector3 dir2 = (myTarget.transform.position - elevationTransform.transform.position).normalized;
		float cone = Mathf.Cos(allowFireCone * Mathf.Deg2Rad);

		if(Vector3.Dot(elevationTransform.forward, dir2) > cone){
			locked = true;
		}
		else{
			locked = false;
		}
		if(locked){
			Debug.Log("Fire!");  //fire event goes here.  Will be coded later.
		}
		else{
			Debug.Log("Don't fire!");
		}
		
		//Manual code goes here.  Not implemented yet.
		
	}

	public static float ClampAngle (float angle, float min, float max)
	{ //used to clamp the resulting angle between the limits established up top.
		if (angle < -360F)
			angle += 360F;
		if (angle > 360F)
			angle -= 360F;
		return Mathf.Clamp (angle, min, max);
	}	

	void Start(){
		//Original turret base and elevations for mouselook code.
		originalBaseRotation = baseTransform.localRotation;
		originalElevRotation = elevationTransform.localRotation;
	}
}

For the turret base, you can get the target point in space and set its Y to zero. Then, use LookRotation to look at that point. Since the rotation will only be about the Y axis, you can read its angle using Quaternion.eulerAngles, clamp it to the desired range and then set it back:-

var targetPoint: Vector3;
  ...

var targetHeading = targetPoint - turretBase.position;
var targetXZ = targetHeading;
targetXZ.y = 0;
turretBase.rotation = Quaternion.LookRotation(targetXZ);
turretBase.eulerAngles.y = Mathf.Clamp(turretBase.eulerAngles.y, startRange, endRange);

You can then do the equivalent thing for the X axis of turretElevation.