Help with turret rotation

I’m trying to fix the rotation on a turret. I have a spaceship that has 360 degree range of rotation and movement. Mounted in the front is the turret. The turret should never rotate in the Z axis, and in X and Y it should be limited to the forward facing 60 degrees or so from the nose of the space ship.

The turret is always following the players gaze, so a reticle attached to the main camera that moves and scales depending on it’s depth. The player can look in 360 degrees, and also rotate in 360 degrees. But the turret should always be trying to get to where the reticle is and be limited in it’s rotation.

Using only LookAt, it allows the shooting in the direction. But when the space ship rotates and the reticle doesn’t, the turret will rotate. But it should only move when the players gaze moves. Also using LookAt isn’t limiting the angles.

So I tried to adapt the SimpleMouseRotation script, but it also doesn’t provide the wanted results.

So here is one block of code I was working with:

    public Vector2 rotationRange = new Vector3(70, 70);
    public float rotationSpeed = 10;
    public float dampingTime = 0.2f;
    public bool relative = true;

    public Transform followObject;


    private Vector3 m_TargetAngles;
    private Vector3 m_FollowAngles;
    private Vector3 m_FollowVelocity;
    private Quaternion m_OriginalRotation;


    private void Start()
    {
        m_OriginalRotation = transform.localRotation;
    }


    private void Update()
    {
        // we make initial calculations from the original local rotation
        transform.localRotation = m_OriginalRotation;

        // read input from mouse or mobile controls
        float inputH;
        float inputV;
        if (relative)
        {

            inputH = followObject.position.x;
            inputV = followObject.position.y;

            // wrap values to avoid springing quickly the wrong way from positive to negative
            if (m_TargetAngles.y > 180)
            {
                m_TargetAngles.y -= 360;
                m_FollowAngles.y -= 360;
            }
            if (m_TargetAngles.x > 180)
            {
                m_TargetAngles.x -= 360;
                m_FollowAngles.x -= 360;
            }
            if (m_TargetAngles.y < -180)
            {
                m_TargetAngles.y += 360;
                m_FollowAngles.y += 360;
            }
            if (m_TargetAngles.x < -180)
            {
                m_TargetAngles.x += 360;
                m_FollowAngles.x += 360;
            }



            // clamp values to allowed range
            m_TargetAngles.y = Mathf.Clamp(m_TargetAngles.y, -rotationRange.y * 0.5f, rotationRange.y * 0.5f);
            m_TargetAngles.x = Mathf.Clamp(m_TargetAngles.x, -rotationRange.x * 0.5f, rotationRange.x * 0.5f);
        }
        else
        {

            inputH = followObject.position.x;
            inputV = followObject.position.y;

            // set values to allowed range
            m_TargetAngles.y = Mathf.Lerp(-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH / Screen.width);
            m_TargetAngles.x = Mathf.Lerp(-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV / Screen.height);
        }

        // smoothly interpolate current values to target angles
        m_FollowAngles = Vector3.SmoothDamp(m_FollowAngles, m_TargetAngles, ref m_FollowVelocity, dampingTime);

        // update the actual gameobject's rotation
        transform.localRotation = m_OriginalRotation * Quaternion.Euler(-m_FollowAngles.x, m_FollowAngles.y, 0);
    }
}
//}

Looking for some help on how to keep the turrets local rotation limited to only X and Y, while the object it is attached to rotates around space, and the object its point at is also rotating.

Not sure what your scene setup is, but generally the “big win” on these sorts of setups is to insert extra blank game objects between the root game object and the turret, in a hierarchy.

Essentially think of each game object as a “hinge” or a “pivot,” and try to only change one of the axes of rotation at each stage of the “chain” going from root to the turret.

I cannot really be more specific than that without full knowledge of your object setups, but generally by breaking the problem down into discrete “pivot points” like this, you can get the effect you want with less transform and rotational fussing around.

Thanks for your reply Kurt, So what i have done, is the turret is broken into 2 parts. the hub, and the barrel. The hub should only rotate on the Y axis, and the barrel is on the X and Y only.

The disered effect is like on the B-17 bomber from world war 2. The top turret is what I’m trying to do. But where the B-17 is a slow bomer and isn’t going to be rotating very fast, my spaceship can.

using UnityEngine;
using System.Collections;

public class PlayerTurret : MonoBehaviour
{
    public Transform hub;           // Turret hub
    public Transform barrel;        // Turret barrel
    public Transform target;
    public float dampSpeed;

    // Turret tracking
    void Track()
    {
        // create rotations for hub and barrel
        Quaternion targetRotationHub = Quaternion.LookRotation(target.position - hub.position);
        Quaternion targetRotationBarrel = Quaternion.LookRotation(target.position - barrel.position);

        // slerp rotations and assign
        hub.rotation = Quaternion.Slerp(hub.rotation, targetRotationHub, Time.deltaTime * dampSpeed);

        barrel.rotation = Quaternion.Slerp (barrel.rotation, targetRotationBarrel, Time.deltaTime * dampSpeed);

        // Set angles to 0

        hub.localEulerAngles = new Vector3(0, hub.localEulerAngles.y, 0);
        barrel.localEulerAngles = new Vector3(barrel.localEulerAngles.x, barrel.localEulerAngles.y, 0);
    }

    void Update()
    {
        // Track turret
        Track();
    }

}

This produces the desired effect, without the angle limit. But the side effect is by setting the angles to 0 it produces a small noticeable jitter, and once in a while I get a gimbal flip depending on the ships rotation.