Search Unity

Help with turret rotation

Discussion in 'Scripting' started by Justin-Wasilenko, Feb 11, 2016.

  1. Justin-Wasilenko

    Justin-Wasilenko

    Joined:
    Mar 10, 2015
    Posts:
    104
    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.
    LookAt help.jpg

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

    Code (CSharp):
    1.  
    2.     public Vector2 rotationRange = new Vector3(70, 70);
    3.     public float rotationSpeed = 10;
    4.     public float dampingTime = 0.2f;
    5.     public bool relative = true;
    6.  
    7.     public Transform followObject;
    8.  
    9.  
    10.     private Vector3 m_TargetAngles;
    11.     private Vector3 m_FollowAngles;
    12.     private Vector3 m_FollowVelocity;
    13.     private Quaternion m_OriginalRotation;
    14.  
    15.  
    16.     private void Start()
    17.     {
    18.         m_OriginalRotation = transform.localRotation;
    19.     }
    20.  
    21.  
    22.     private void Update()
    23.     {
    24.         // we make initial calculations from the original local rotation
    25.         transform.localRotation = m_OriginalRotation;
    26.  
    27.         // read input from mouse or mobile controls
    28.         float inputH;
    29.         float inputV;
    30.         if (relative)
    31.         {
    32.  
    33.             inputH = followObject.position.x;
    34.             inputV = followObject.position.y;
    35.  
    36.             // wrap values to avoid springing quickly the wrong way from positive to negative
    37.             if (m_TargetAngles.y > 180)
    38.             {
    39.                 m_TargetAngles.y -= 360;
    40.                 m_FollowAngles.y -= 360;
    41.             }
    42.             if (m_TargetAngles.x > 180)
    43.             {
    44.                 m_TargetAngles.x -= 360;
    45.                 m_FollowAngles.x -= 360;
    46.             }
    47.             if (m_TargetAngles.y < -180)
    48.             {
    49.                 m_TargetAngles.y += 360;
    50.                 m_FollowAngles.y += 360;
    51.             }
    52.             if (m_TargetAngles.x < -180)
    53.             {
    54.                 m_TargetAngles.x += 360;
    55.                 m_FollowAngles.x += 360;
    56.             }
    57.  
    58.  
    59.  
    60.             // clamp values to allowed range
    61.             m_TargetAngles.y = Mathf.Clamp(m_TargetAngles.y, -rotationRange.y * 0.5f, rotationRange.y * 0.5f);
    62.             m_TargetAngles.x = Mathf.Clamp(m_TargetAngles.x, -rotationRange.x * 0.5f, rotationRange.x * 0.5f);
    63.         }
    64.         else
    65.         {
    66.  
    67.             inputH = followObject.position.x;
    68.             inputV = followObject.position.y;
    69.  
    70.             // set values to allowed range
    71.             m_TargetAngles.y = Mathf.Lerp(-rotationRange.y * 0.5f, rotationRange.y * 0.5f, inputH / Screen.width);
    72.             m_TargetAngles.x = Mathf.Lerp(-rotationRange.x * 0.5f, rotationRange.x * 0.5f, inputV / Screen.height);
    73.         }
    74.  
    75.         // smoothly interpolate current values to target angles
    76.         m_FollowAngles = Vector3.SmoothDamp(m_FollowAngles, m_TargetAngles, ref m_FollowVelocity, dampingTime);
    77.  
    78.         // update the actual gameobject's rotation
    79.         transform.localRotation = m_OriginalRotation * Quaternion.Euler(-m_FollowAngles.x, m_FollowAngles.y, 0);
    80.     }
    81. }
    82. //}
    83.  
    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.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    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.
     
  3. Justin-Wasilenko

    Justin-Wasilenko

    Joined:
    Mar 10, 2015
    Posts:
    104
    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.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class PlayerTurret : MonoBehaviour
    5. {
    6.     public Transform hub;           // Turret hub
    7.     public Transform barrel;        // Turret barrel
    8.     public Transform target;
    9.     public float dampSpeed;
    10.  
    11.     // Turret tracking
    12.     void Track()
    13.     {
    14.         // create rotations for hub and barrel
    15.         Quaternion targetRotationHub = Quaternion.LookRotation(target.position - hub.position);
    16.         Quaternion targetRotationBarrel = Quaternion.LookRotation(target.position - barrel.position);
    17.  
    18.         // slerp rotations and assign
    19.         hub.rotation = Quaternion.Slerp(hub.rotation, targetRotationHub, Time.deltaTime * dampSpeed);
    20.  
    21.         barrel.rotation = Quaternion.Slerp (barrel.rotation, targetRotationBarrel, Time.deltaTime * dampSpeed);
    22.  
    23.         // Set angles to 0
    24.  
    25.         hub.localEulerAngles = new Vector3(0, hub.localEulerAngles.y, 0);
    26.         barrel.localEulerAngles = new Vector3(barrel.localEulerAngles.x, barrel.localEulerAngles.y, 0);
    27.     }
    28.  
    29.     void Update()
    30.     {
    31.         // Track turret
    32.         Track();
    33.     }
    34.  
    35. }
    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.