- Home /
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()
{
}
}
Answer by MakeCodeNow · Feb 15, 2014 at 06:22 PM
If you use transform.localRotation instead of transform.rotation, your "hacky way" should work just fine (provided you're careful about local gimbal lock).
Well, my Hacky way does not exactly work perfectly either. Have you got any sources / code for even a hacky way?
Answer by Talmore · Feb 15, 2014 at 07:14 PM
Unitycookie.com has a multi-part tower defense tutorial that should have some useful information that could be applied to your situation. http://cgcookie.com/unity/cgc-courses/unity-tower-defense-course/
Answer by robertbu · Feb 15, 2014 at 07:22 PM
If the turret will always be aligned with the world axes, you will find some starter code here:
http://answers.unity3d.com/questions/388185/make-the-turret-automatically-rotate-to-look-at-wh.html
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:
http://answers.unity3d.com/questions/562443/turret-slerp-rotation-and-clamping.html
Note there are a few other post with alternate solutions on UA for turret rotation.
Answer by servival · Jun 27, 2015 at 04:02 PM
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);
}
}