# Creating a multiple part turret what locks onto certain axis.

Ok so, I have a game Im trying to work on, the turrets I am using are two parts ( shown in http://puu.sh/6Xg7o.jpg ) and I need to be able to make a " realistic " rotation so that the top part can only rotate up and down while the bottom part only rotates sideways. I know that is quite easy to do, however I also need to make it dynamic so that the turret can be rotated any way, it will be attached to a spaceship which can move upside down or in any direction so I can not just use a " Hacky " method to set the x y z to certain values.

Does anyone have any sources / idea’s of how I would achieve this? I have been trying to do this for quite a while today but angles are not really my thing.

Help would be amazing.

Here is the code I am using right now, setting the local version of the rotation messes up when I rotate the turret.

``````using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class EntityTurret : Entity
{

public GameObject target;

public GameObject baseObj;
public GameObject midObj;
public GameObject topObj;

void Start()
{

}

void Update()
{
transformTowardsTarget();
}

int getDir(Vector3 f, Vector3 tD, Vector3 u)
{
Vector3 perp = Vector3.Cross(f, tD);
float dir = Vector3.Dot(perp, u);
if (dir > 0.0f)
{
return 1;
}
else if (dir < 0.0f)
{
return -1;
}
else
{
return 0;
}
}

int getDirVertical(Vector3 f, Vector3 tD, Vector3 u)
{
Vector3 perp = Vector3.Cross(u, tD);
float dir = Vector3.Dot(perp, f);
if (dir > 0.0f)
{
return 1;
}
else if (dir < 0.0f)
{
return -1;
}
else
{
return 0;
}
}

public static float SignedAngle(Vector3 v1, Vector3 v2, Vector3 n)
{
return (float)Mathf.Atan2(Vector3.Dot(n, Vector3.Cross(v1, v2)), Vector3.Dot(v1, v2)) * 57.29578f;
}

float getAngle(Vector3 p1, Vector3 p2)
{
Vector3 targetDir = (p1 - p2).normalized;
float angle = Vector3.Angle(targetDir, transform.forward);
int dir = getDir(transform.forward, targetDir, transform.up);
switch(dir)
{
case -1:
return 360 - angle;
case 1:
return angle;
default:
return 0;
}
}

float getAngleUp(Vector3 p1, Vector3 p2)
{
Vector3 targetDir = (p1 - p2).normalized;
float angle = Vector3.Angle(targetDir, transform.forward);
int dir = getDir(transform.forward, targetDir, transform.right);
switch (dir)
{
case -1:
return 360 - angle;
case 1:
return angle;
default:
return 0;
}
}

void transformTowardsTarget()
{
Transform t = target.transform;
Vector3 p = t.position;
Vector3 p2 = transform.position;

Vector3 targetDir = (p - p2).normalized;
Vector3 forward = transform.forward;

Vector3 finalRot = new Vector3();

Debug.DrawLine(p2, p, Color.blue);

float yAng = getAngle(p, p2);
float xAng = getAngleUp(p, p2);

Debug.Log(yAng + "," + xAng);

finalRot.y = yAng;
finalRot.z = transform.localRotation.eulerAngles.z;
finalRot.x = transform.localRotation.eulerAngles.x;

midObj.transform.localRotation = Quaternion.Euler(finalRot);

// ALL TEST CODE BELOW ( For reference )

//midObj.transform.LookAt(new Vector3(p.x, transform.position.y, p.z));
//midObj.transform.Rotate(0, 90, 0);

//topObj.transform.LookAt(new Vector3(p.x, p.y, p.z));
//topObj.transform.Rotate(0, 270, 0);

//float angle = Vector3.Angle((p - transform.position), transform.forward);

//Debug.DrawLine(topObj.transform.position, tO.transform.forward, Color.blue);

// Mid Rotation
/*
Vector3 flatVectorToTarget = transform.position - t.position;

flatVectorToTarget.y = 0;

Quaternion newRotation = Quaternion.LookRotation(flatVectorToTarget);

midObj.transform.rotation = newRotation;
midObj.transform.Rotate(0, 90, 0); // rotate offset to make turret properly face target.

// Top Rotation

flatVectorToTarget = transform.position - t.position;

newRotation = Quaternion.LookRotation(flatVectorToTarget);

Debug.DrawLine(topObj.transform.position, t.position,Color.red);
Debug.DrawLine(topObj.transform.position, tO.transform.position, Color.green);

topObj.transform.rotation = newRotation;
topObj.transform.Rotate(0, 90, 0); // rotate offset to make turret properly face target.
*/
/*

Vector3 point = t.position;
point.y = transform.position.y;
midObj.transform.LookAt(point);
*/
//point = t.position;

//topObj.transform.LookAt(point);

}

public override void onEntityInitialized()
{

}

public override void entityTick()
{

}

}
``````

If you use transform.localRotation instead of transform.rotation, your “hacky way” should work just fine (provided you’re careful about local gimbal lock).

Unitycookie.com has a multi-part tower defense tutorial that should have some useful information that could be applied to your situation.
CG Cookie | Learn Blender, Online Tutorials and Help - CG Cookie | Learn Blender, Online Tutorials and Feedback

If the turret will always be aligned with the world axes, you will find some starter code here:

If the turret has arbitrary rotation, you will find a single, short script down in the comments to my answer here. You will need to open the additional comments of my answer to find the script:

Note there are a few other post with alternate solutions on UA for turret rotation.

using UnityEngine;
using System.Collections;
public class AISmoothLookAT : MonoBehaviour {
public Transform target;
public Transform looker;
public Transform Xsmoothlooker;
public Transform Ysmoothlooker;
public float Xspeed = 2f;
public float Yspeed = 2f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
looker.LookAt (target);
float YRotation = looker.eulerAngles.y;
float XRotation = looker.eulerAngles.x;
Xsmoothlooker.rotation = Quaternion.Slerp(Xsmoothlooker.rotation , Quaternion.Euler(0 , YRotation, 0), Time.deltaTime * Xspeed);
Ysmoothlooker.rotation = Quaternion.Slerp(Ysmoothlooker.rotation , Quaternion.Euler(XRotation , YRotation, 0), Time.deltaTime * Yspeed);
}
}