Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Showcase I just made a turret system that work perfectly.

Discussion in 'Scripting' started by Adrielcz, Jul 20, 2023.

  1. Adrielcz

    Adrielcz

    Joined:
    Aug 5, 2020
    Posts:
    3
    The "Sveringe 1917" is an empty game object with the code attached. The relevant turrets for the demonstration are the Main 1 and 2.
    Example 1.png

    You place the turret in each element of the nested class by adding more components for the " public TurretData[] turrets;"
    The turret rotates from -180 to +180 and we can limit this rotation with the Min and Max Rotation Angle. The target can be feed either by you in the inspector or by code if you reference the correct turretData in the array and give the transform target.
    Is rear turret reverts the rotation, so if the turret front is -Z, you don't need to mess up with the parents gameObject so the forward is actually +Z.
    Example 2.png

    The two turrets (Big ones) each follow the nearest cube,if the cube is in a not allowed angle, the turret will lock it the maximun allowed one: Example 4.png
    If the cube moves from an unallowed zone (something like -150) towards an allowed positive zone (+90), it go all the way around and not over the superestructure. imagem_2023-07-20_151200111.png
    And lastly, if the ship himself tilts in the Z or X angle, the turret still follow the parents transforms! Example 7.png
    I'm by no means a good programmer, the heavy lifting was made by the chat GPT, but since I'm an indie dev by about 5 years and never manage to found out a turret that does all of this, I felt the obligation to guide you guys if needed :D. (When I inplement with the AI a gun elevation system, I update this).
    Code (CSharp):
    1. public class HorizontalRotationManager : MonoBehaviour
    2. {
    3.     [System.Serializable]
    4.     public class TurretData
    5.     {
    6.         public Transform turretTransform; // Reference to the turret's Transform
    7.         public float minRotationAngle; // Minimum rotation angle in degrees
    8.         public float maxRotationAngle; // Maximum rotation angle in degrees
    9.         public float rotationSpeed; // Rotation speed in degrees per second
    10.         public bool isRearTurret = false; // Is this turret a rear turret?
    11.  
    12.         public Transform target; // The target GameObject for this turret
    13.     }
    14.  
    15.     public TurretData[] turrets; // Array of TurretData representing all the turrets
    16.  
    17.     void Update()
    18.     {
    19.         foreach (TurretData turretData in turrets)
    20.         {
    21.             if (turretData.target != null)
    22.             {
    23.                 // Get the direction from the turret to the target in world space
    24.                 Vector3 targetDirection = turretData.target.position - turretData.turretTransform.position;
    25.  
    26.                 // Convert the target direction to local space with respect to the turret's parent (turret holder - ship)
    27.                 Vector3 localTargetDirection = turretData.turretTransform.parent.InverseTransformDirection(targetDirection);
    28.  
    29.                 // Calculate the target rotation angle in local space relative to the turret's parent
    30.                 float targetAngle = Mathf.Atan2(localTargetDirection.x, localTargetDirection.z) * Mathf.Rad2Deg;
    31.  
    32.                 // Handle the orientation for rear turrets
    33.                 if (turretData.isRearTurret)
    34.                 {
    35.                     targetAngle -= 180f; // Subtract 180 degrees for rear turrets
    36.                 }
    37.  
    38.                 // Normalize the target angle to the -180 to 180 degrees range
    39.                 targetAngle = Mathf.Repeat(targetAngle + 180f, 360f) - 180f;
    40.  
    41.                 // Get the turret's current angle in local space relative to the turret's parent
    42.                 float currentAngle = Mathf.Repeat(turretData.turretTransform.localEulerAngles.y + 180f, 360f) - 180f;
    43.  
    44.                 // Calculate the relative angle between the turret's current angle and the target angle
    45.                 float relativeAngle = Mathf.DeltaAngle(currentAngle, targetAngle);
    46.  
    47.                 // Check if the relative angle exceeds the allowed range
    48.                 if (relativeAngle < turretData.minRotationAngle || relativeAngle > turretData.maxRotationAngle)
    49.                 {
    50.                     // Check if the target is in an extreme region of the turret's allowed rotation
    51.                     if (targetAngle > turretData.maxRotationAngle)
    52.                     {
    53.                         // Rotate the target angle to the maximum allowed angle
    54.                         targetAngle = turretData.maxRotationAngle;
    55.                     }
    56.                     else if (targetAngle < turretData.minRotationAngle)
    57.                     {
    58.                         // Rotate the target angle to the minimum allowed angle
    59.                         targetAngle = turretData.minRotationAngle;
    60.                     }
    61.                     else
    62.                     {
    63.                         // Calculate the angle to the other side of the turret within the allowed range
    64.                         float oppositeAngle = relativeAngle > 0 ? relativeAngle - 360f : relativeAngle + 360f;
    65.  
    66.                         // Choose the angle that is within the allowed range and closer to the target
    67.                         if (Mathf.Abs(oppositeAngle - targetAngle) < Mathf.Abs(relativeAngle - targetAngle))
    68.                         {
    69.                             targetAngle = oppositeAngle;
    70.                         }
    71.                     }
    72.                 }
    73.  
    74.                 // Use Quaternion.RotateTowards to handle the rotation constraints
    75.                 float targetRotation = currentAngle + Mathf.Clamp(targetAngle - currentAngle, -turretData.rotationSpeed * Time.deltaTime, turretData.rotationSpeed * Time.deltaTime);
    76.                 targetRotation = Mathf.Clamp(targetRotation, turretData.minRotationAngle, turretData.maxRotationAngle);
    77.                 turretData.turretTransform.localRotation = Quaternion.Euler(0f, targetRotation, 0f);
    78.             }
    79.         }
    80.     }
    81. }
    82.  
     
    Last edited: Jul 20, 2023
  2. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    You might want to check my auto-turret. I ultimately want to improve that solution and combine it with some other features I developed in the meantime (namely target leading in 3D, ballistic trajectories, and 2nd order dynamics for the motion itself). It was progressing nicely, but now I have very little time to continue. Hopefully I'll get back to it.
     
    Adrielcz likes this.
  3. Adrielcz

    Adrielcz

    Joined:
    Aug 5, 2020
    Posts:
    3
    Well two things: I think mine is a bit simpler for the scope and lastly (and really more important) Where was you when I needed! Your work is amazing dude! For real bookmarked your link!
     
    Last edited: Jul 26, 2023
  4. orionsyndrome

    orionsyndrome

    Joined:
    May 4, 2014
    Posts:
    3,043
    Sure, I'm glad you've done this from a different angle.
    Thanks for the compliments. You can find links to various interesting stuff in the end of the post I've linked in the signature.
     
    Adrielcz likes this.