How can I make these turret models point at my target

[oops] accidentally hit “create thread” before I could finish it. Give me a few minutes! =D

I’ve been over this problem before. I deleted the code within the file for god knows what reason at this point.

My problem is I have a turret model which needs to orient to point at the target, and I would like to make it do this from any angle on any axis. I don’t know enough about 3d rotations and stuff to do this myself. I did have this working at one point through a method of trial an error. That work has since been lost.

I managed many, many, iterations to get this working but it isn’t turning out.

If someone could just show me what the proper rotations should be in my script and why they work I would be very happy!

A screenie:


Script to orient the turrets:

void Update() {
/*The turret [] array contains references to the 'LookingAtObj' for each turret in the picture.
The other two arrays gunBarrel and gunBase refer to each turret's barrel and base.
*/

    for (int y = 0; y <= NUM_GUNS; y++) {
            turret[y].transform.LookAt(FireGunsScript.worldTarget); //Make the invisible "LookingAt" empty game object look at the world target as a reference to get values from.
            Vector3 tLoke = turret[y].transform.localEulerAngles;
            Vector3 tGlobe = turret[y].transform.eulerAngles;

            if(y <= (NUM_GUNS / 2) ) { //LEFT SIDE GUNS (bottom side of these turrets will face inward toward the ship)
                turretBase [y].transform.localEulerAngles = new Vector3( tGlobe.x, 0, -90); //Rotate along Z axis to set the turret on its side relative to the 'world'
                gunBarrel  [y].transform.localEulerAngles = new Vector3( 0, tGlobe.y, 0);
            } else { //RIGHT SIDE GUNS
                turretBase [y].transform.localEulerAngles = new Vector3( tGlobe.x, 0, +90);
                gunBarrel  [y].transform.localEulerAngles = new Vector3(  0, tGlobe.y, 0);

            }
}         
    
  }
1 Like

Try using transform.LookAt(target.transform.position);

1 Like

That’s the purpose of my usage of that particular function within the script. I didn’t say this but I was trying to separate the XYZ components obtained from that function and put in to “lookingAtObj” to force the turret to rotate along its mechanical axes. IE. The base rotates along its local Y axis and the gun barrel rotates perpendicular to that along its local X Axis. The problem is this only works with the turret when it is oriented with the base horizontal to the game world.

I really need to find a way to automatically force the turret to look at the target when oriented at any angle. Right now I’m just struggling to solve how to do that with the whole thing oriented on its side.

[edit]: So I managed to solve the problem!! I had not configured the turret prefab correctly and some of the code was obviously nonfunctional. Now if only I could find an easy way to place them at any angle and have them aim properly… that is something I would definitely like some help on.

1 Like

I was curious how Quaternion.Lerp would work so I took a whack at your turret-aiming project with some simple Unity primitives. See the attached scene for my results… it puts a sphere on the screen following your mouse around, and then aims the barrel at it with some snappiness, adjustable by the SlewRate variable. You could just tear out the Unity primitives and hang your geometry on the gimbal object and it ought to just work fine.

2113702–138694–gunlooker.unitypackage (4.46 KB)

1 Like

You know what I actually solved the “arbitrary angle/orientation” problem by myself today. I’m quite proud of that because I understand very little about 3d math. I didn’t think it would be anything I could solve on my own. Really I had to do was adjust the code in my scripts and configure the turret prefab. =D

In case anyone is interested in how I did it I will post the prefab/code here like Kurt did:

(You will have to write some code to instantiate your turrets), otherwise just place them in the editor. They will work together to follow the mouse!

2114081–138714–BrainyTurret.unitypackage (164 KB)

1 Like

guess people missed the “independent of parent orientation”… i.e. upside down, right side up, on the side etc. :smile:

I’ve been trying to figure this out, and I’ve gotten a little way there I think. Script is far from complete but the “right way up” and “up side down” turrets both track the orbiting target, you can rotate their parent “ship” and they continue to track until the rotation gets to almost 90 degs, then they go a little mental, 90degs needs to be handled since there isn’t a rotation for the turret to track a point directly above it (if you are going to put in elevation limits on the barrel I guess that would get rolled into this part of the code)… script goes on the TurretBase gameobjects.

this was my test project, magenta cube is the gizmo rendering at 0,0,0 (so off centre “ship”), sphere is a target set to orbit the “ship”. TurretBase are prefabs, one is rotated 180 but they are running the same code.

using UnityEngine;
using System.Collections;

public class TurretBase : MonoBehaviour
{
    public Transform target;

    public Transform lateralTurret;
    public Transform barrel;

    public Vector3 effectiveTargetPosition;
    public Vector3 effectiveTargetElevation;

    void Start()
    {
        lateralTurret = transform.Find("Turret");
        barrel = lateralTurret.Find("Barrel");
    }

    void Update()
    {
        if(target)
        {
            // work out the point where the target is in the plane of the turret
            LinePlaneIntersection(out effectiveTargetPosition, target.position, lateralTurret.up, lateralTurret.up, lateralTurret.position);
            // direction from turret's point of view
            Vector3 targetDirection = effectiveTargetPosition - lateralTurret.position;
            // amount to turn by
            float forwardAngle = Vector3.Angle(lateralTurret.forward, targetDirection);
            // rotate
            lateralTurret.RotateAround(lateralTurret.position, lateralTurret.up, forwardAngle * AngleDir(lateralTurret.forward, targetDirection, lateralTurret.up));


            Debug.DrawRay(target.position, barrel.right * 50, Color.yellow);
            DrawPlane(barrel.right * 50, barrel.position, Color.green);
            // work out the point where the target is in the plane of the barrel
            LinePlaneIntersection(out effectiveTargetElevation, target.position, barrel.right, barrel.right, barrel.position);
            // direction from turret's point of view
            targetDirection = effectiveTargetElevation - barrel.position;
            // amount to turn by
            forwardAngle = Vector3.Angle(barrel.forward, targetDirection);
            // rotate
            barrel.RotateAround(barrel.position, barrel.right, forwardAngle * AngleDir(barrel.forward, targetDirection, barrel.right));
        }
    }

    // taken from somewhere on the web... didn't make a note =(
    // figures out left/right side to overcome lack of perspective in most rotation functions.
    public float AngleDir(Vector3 fwd, Vector3 targetDir, Vector3 up)
    {
        Vector3 perp = Vector3.Cross(fwd, targetDir);
        float dir = Vector3.Dot(perp, up);

        if (dir > 0.0f)
        {
            return 1.0f;
        }
        else if (dir < 0.0f)
        {
            return -1.0f;
        }
        else
        {
            return 0.0f;
        }
    } 



    public void SetTarget(Transform t)
    {
        target = t;
    }

    public void OnDrawGizmos()
    {
            // draw magenta cube where target point is in turrets plane (viewed from above in ortho camera should always be in line with target)
            Gizmos.color = Color.magenta;
            Gizmos.DrawCube(effectiveTargetPosition, new Vector3(0.2f, 0.2f, 0.2f));

            // draw magenta cube where target point is in turrets plane (viewed from above in ortho camera should always be in line with target)
            Gizmos.color = Color.cyan;
            Gizmos.DrawCube(effectiveTargetElevation, new Vector3(0.2f, 0.2f, 0.2f));       
    }

    // intersection function from http://wiki.unity3d.com/index.php/3d_Math_functions
    public static bool LinePlaneIntersection(out Vector3 intersection, Vector3 linePoint, Vector3 lineVec, Vector3 planeNormal, Vector3 planePoint)
    {

        float length;
        float dotNumerator;
        float dotDenominator;
        Vector3 vector;
        intersection = Vector3.zero;

        //calculate the distance between the linePoint and the line-plane intersection point
        dotNumerator = Vector3.Dot((planePoint - linePoint), planeNormal);
        dotDenominator = Vector3.Dot(lineVec, planeNormal);

        //line and plane are not parallel
        if (dotDenominator != 0.0f)
        {
            length = dotNumerator / dotDenominator;

            //create a vector from the linePoint to the intersection point
            vector = SetVectorLength(lineVec, length);

            //get the coordinates of the line-plane intersection point
            intersection = linePoint + vector;

            return true;
        }

        //output not valid
        else
        {
            return false;
        }
    }
    //create a vector of direction "vector" with length "size" from http://wiki.unity3d.com/index.php/3d_Math_functions
    public static Vector3 SetVectorLength(Vector3 vector, float size)
    {

        //normalize the vector
        Vector3 vectorNormalized = Vector3.Normalize(vector);

        //scale the vector
        return vectorNormalized *= size;
    }


    // debug draw plane from unity answers: http://answers.unity3d.com/questions/467458/how-to-debug-drawing-plane.html
    public void DrawPlane(Vector3 normal, Vector3 position, Color c)
    {

     Vector3 v3 ;

     if (normal.normalized != Vector3.forward)
         v3 = Vector3.Cross(normal, Vector3.forward).normalized * normal.magnitude;
     else
         v3 = Vector3.Cross(normal, Vector3.up).normalized * normal.magnitude;;
    
     Vector3 corner0 = position + v3;
     Vector3 corner2 = position - v3;

     Quaternion q = Quaternion.AngleAxis(90.0f, normal);
     v3 = q * v3;
     Vector3 corner1 = position + v3;
     Vector3 corner3 = position - v3;

     Debug.DrawLine(corner0, corner2, c);
     Debug.DrawLine(corner1, corner3, c);
     Debug.DrawLine(corner0, corner1, c);
     Debug.DrawLine(corner1, corner2, c);
     Debug.DrawLine(corner2, corner3, c);
     Debug.DrawLine(corner3, corner0, c);
     Debug.DrawRay(position, normal, Color.red);
     }
}

edit: added in the turret barrel elevation and corrected a mix up between world up and local up in the rotation. Also added a few more debugs into the scene view so it’s a little more clear what’s going on.

1 Like

nvm, you’re setting the orientation via inspector in the start… missed that :roll_eyes:

I consider myself a pretty good scripting person/programmer but damn I wish I could make code as clear as that lefty! =D

And hey I’ve got a question about your script Lefty. Shouldn’t the comment say “angle” instead of distance on Line 86 or am I wrong? The Dot product gets the angle between two vectors right?

Part of my problem is a complete disregard for basic organization xD

Thanks guys!

1 Like

everything after line 76 is code taken from the extensive vector/plane/rotation/whatever collection on the wiki (comment on line 76 has the link)… I make no claim to know what it’s doing :frowning:

it was cleaned and tidied before I posted… was a lot more messy/full of debug lines before then :slight_smile:

2 Likes
Quaternion tmpRotation = turretGO.transform.localRotation;

        Vector3 targetPointTurret = (lookAtTarget.transform.position - turretGO.transform.position).normalized;

        Quaternion targetRotationTurret = Quaternion.LookRotation(targetPointTurret, turretGO.transform.up);

        turretGO.transform.rotation = Quaternion.Slerp(transform.rotation, targetRotationTurret, 1f);

        //replace 1f = Time.deltaTime * turnSpeed if u want a delay time

        turretGO.transform.localRotation = Quaternion.Euler(tmpRotation.eulerAngles.x, turretGO.transform.localRotation.eulerAngles.y, tmpRotation.eulerAngles.z);

        /////////////////////////////////////////

        tmpRotation = gunGO.transform.localRotation;

        Vector3 targetPointBarrels = (lookAtTarget.transform.position - gunGO.transform.position).normalized;

        Quaternion targetRotationBarrels = Quaternion.LookRotation(targetPointBarrels, transform.up);

        gunGO.transform.rotation = Quaternion.Slerp(gunGO.transform.rotation, targetRotationBarrels, 1f);

        //replace 1f = Time.deltaTime * turnSpeed if u want a delay time

        gunGO.transform.localRotation = Quaternion.Euler(gunGO.transform.localRotation.eulerAngles.x, tmpRotation.eulerAngles.y, tmpRotation.eulerAngles.z);