Turret. Detect if target is inside horizontal and vertical arcs

Hi. I am trying to make a turret control for a spaceship (rts game). I have a coroutine that rotates the turret (a base horizontal axis, and a barrel vertical axis). It works fine, I have used Quaternion.Lookrotation and Quaternion.RotateTowards with a clamp to limit the minimum and maximum angle of both axes.

Then I have another coroutine that checks if there is a new target (the ship has two target lists: one holds ships added with right clicks (attack order), and the other adds ships when they are closer). If there is a target, it tells the first coroutine to target it.

To do this I need a function that returns a bool, depending on whether the target is within the turret arcs (both horizontal and vertical arcs). how can I do this?
The arcs are relative to the ship and can go in all directions so it can tilt on all 3 axes.

The data I have is the transformation of the ship/horizontal turret, the position of the target, the minimum/maximum of both arcs.

I think it should make a projection of the target on the plane of the ship and?
Can you guide me with this?
174675-aa.png

I wrote this long time ago… it’s part of my sight sensor but should work for your case (no guarantee :slight_smile: )

 private bool IsInFOV(Transform fovTransform, UnityEngine.Vector3 targetPosition, float maxHorizontalDegrees, float maxVerticalDegrees)
        {
            //to local space
            UnityEngine.Vector3 sourceDirectionForward = fovTransform.InverseTransformDirection(fovTransform.forward);
            //to local space
            UnityEngine.Vector3 targetLocalSpacePosition = fovTransform.InverseTransformPoint(targetPosition);
            UnityEngine.Vector3 targetLocalSpaceXZDirection = new UnityEngine.Vector3(targetLocalSpacePosition.x, 0, targetLocalSpacePosition.z) - new UnityEngine.Vector3(0, 0, 0);

            float targetLocalDistance = UnityEngine.Vector3.Distance(UnityEngine.Vector3.zero, targetLocalSpacePosition);
            //this.distance = targetLocalDistance;

            float targetAngleV = Mathf.Rad2Deg * (Mathf.Atan(Mathf.Abs(targetLocalSpacePosition.y) / Mathf.Abs(targetLocalDistance)));
            float targetAngleH = UnityEngine.Vector3.Angle(targetLocalSpaceXZDirection, sourceDirectionForward);
            
            if ((targetAngleV <= maxVerticalDegrees/2) && (targetAngleH <= maxHorizontalDegrees/2)) return true;           
            
            return false;
        }

Hope you get it working,

PS. here are parameter descriptions:

fovTransform = transform of the eye

targetPosition = position of the target

maxHorizontalDegrees = Maximum of horizontal (max 360) angle between eye and target in degrees

maxVerticalDegrees = Maximum of vertical (max 180) angle between eye and target in degrees

If anyone is interested in how to rotate the turret, i use this (the objetive assignment is another topic).

  1. turret_horizontal is the transform of the horizontal axis of the turret (the body).

  2. turret_vertical is the transform of the vertical axis of the turret (the canon)

  3. turret_vertical must be child of turret horizontal

    void FixedUpdate() //or a coroutine with yield return new WaitForFixedUpdate
    {
    Quaternion _rot = Quaternion.LookRotation(targetTransform.position - turret_horizontal.position);

    turret_horizontal.rotation = Quaternion.RotateTowards(turret_horizontal.rotation, _rot, _vel_horizontal * Time.fixedDeltaTime);
    turret_horizontal.localEulerAngles = new Vector3(0f, fClampAngle(turret_horizontal.localEulerAngles.y, _ang_min_horizontal, _ang_max_horizontal), 0f);
    
    turret_vertical.rotation = Quaternion.RotateTowards(turret_vertical.rotation, _rot, _vel_vertical * Time.fixedDeltaTime);
    turret_vertical.localEulerAngles = new Vector3(fClampAngle(turret_vertical.localEulerAngles.x, _ang_min_vertical, _ang_max_vertical), 0f, 0f);
    

    }

    public static float fClampAngle(float angulo, float min, float max) //it clamps an angle without euler angles errors
    {
    angulo = Mathf.Repeat(angulo, 360f);
    return (angulo > 180f) ? Mathf.Max(angulo, 360f+min) : Mathf.Min(angulo, max);
    }