How to detect when an object is within an arc?

I’m having an issue trying to detect an object within an arc. What I’m trying to do is, after setting a minimum and maximum angle, detect an object that falls within that range. When I put in angle values like -60 degrees to 60 degrees, it works fine. When I put in a value that’s 180 degrees (-90 to 90), my calculated Forward vector gets set to 0 (because I’m calculating a vector between the 2 angles), and when it’s greater than 180 degrees, the detection becomes flipped.

Below are examples.

Red Lines = Detection Arc.

Green Line = Forward Axis.

Cyan Line = Detected Target.

[148525-arcbug.png*_|148525]


And here is the code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MountedTurret : MonoBehaviour
{
    [System.Serializable]
    public class Turret
    {
        [SerializeField]
        Vector3 _localPosition;

        [SerializeField]
        float _angleMin = -90;

        [SerializeField]
        float _angleMax = 90;

        public float Range = 10f;

        public float AngleMin(Transform t)
        {
            return _angleMin + t.eulerAngles.y;
        }

        public float AngleMax(Transform t)
        {
            return _angleMax + t.eulerAngles.y;
        }

        public Vector3 Position(Transform t)
        {
            return t.position + _localPosition;
        }

        public Vector3 Forward(Transform t)
        {
            var position = Position(t);

            float aMin = AngleMin(t);
            float aMax = AngleMax(t);

            Vector3 vMin = new Vector3(Mathf.Sin(aMin * Mathf.Deg2Rad), 0, Mathf.Cos(aMin * Mathf.Deg2Rad));
            Vector3 vMax = new Vector3(Mathf.Sin(aMax * Mathf.Deg2Rad), 0, Mathf.Cos(aMax * Mathf.Deg2Rad));

            return ((vMin + vMax) * 0.5f).normalized;
        }

        public bool IsInRange(Transform t, Vector3 point)
        {
            var position = Position(t);
            float dist = Vector3.Distance(position, point);
            if(dist <= Range)
            {
                var direction = point - position;
                float angle = Vector3.Angle(Forward(t), direction);
                if(angle >= AngleMin(t) && angle <= AngleMax(t))
                {
                    return true;
                }
            }
            return false;
        }
    }

    public Ship ship;
    public Turret[] turrets;
    public Transform test;

    public void OnDrawGizmos()
    {
        const int segments = 5;
        List<Vector2> arcPoints = new List<Vector2>();
        float angle;
        float arcLength;
        Vector3 position;
        foreach (Turret t in turrets)
        {
            position = t.Position(transform);
            Gizmos.color = Color.green;
            Debug.Log("My Forward is: " + t.Forward(transform));
            Gizmos.DrawRay(position, t.Forward(transform) * t.Range);
            angle = t.AngleMin(transform);
            arcLength = t.AngleMax(transform) - angle;
            for (int i = 0; i <= segments; i++)
            {
                float x = Mathf.Sin(Mathf.Deg2Rad * angle) * t.Range;
                float y = Mathf.Cos(Mathf.Deg2Rad * angle) * t.Range;

                arcPoints.Add(new Vector2(x, y));

                angle += (arcLength / segments);
            }
            //TODO Draw the arc
            Gizmos.color = Color.red;
            var arcPos = new Vector3(position.x + arcPoints[0].x, position.y, position.z + arcPoints[0].y);
            var prevPos = arcPos;
            Gizmos.DrawLine(position, arcPos);
            //TODO For
            for(int i = 0; i < arcPoints.Count; ++i)
            {
                arcPos = new Vector3(position.x + arcPoints_.x, position.y, position.z + arcPoints*.y);*_

Gizmos.DrawLine(prevPos, arcPos);
prevPos = arcPos;
}
arcPos = new Vector3(position.x + arcPoints[arcPoints.Count - 1].x, position.y, position.z + arcPoints[arcPoints.Count - 1].y);
Gizmos.DrawLine(position, arcPos);
}
}

// Update is called once per frame
void Update()
{
foreach (Turret t in turrets)
{
if(t.IsInRange(transform, test.position))
{
Debug.DrawLine(t.Position(transform), test.position, Color.cyan);
}
}
}
}

_*

Hey there,

take a look at this tutorial.

Do a projection as explained by the link and you geet a value that will indicate if your object is in the front or the back when the value “c” is positive/negative.

Let me know if that was too unclear and i can try to help you a bit more specifically.

Thanks to Captain_Pineapple, I was able to figure out the answer, by converting my 2 angles into 2 planes!

Here is the revised IsInRange function, as well as 2 Plane generation functions:

public Plane MinPlane(Transform t)
        {
            var position = Position(t);

            float aMin = AngleMin(t);
            Vector3 vMin = new Vector3(Mathf.Sin(aMin * Mathf.Deg2Rad), 0, Mathf.Cos(aMin * Mathf.Deg2Rad));

            Vector3 normal =  Vector3.Cross(vMin, Vector3.down);

            return new Plane(normal, position);
        }

        public Plane MaxPlane(Transform t)
        {
            var position = Position(t);

            float aMax = AngleMax(t);
            Vector3 vMax = new Vector3(Mathf.Sin(aMax * Mathf.Deg2Rad), 0, Mathf.Cos(aMax * Mathf.Deg2Rad));

            Vector3 normal =  Vector3.Cross(vMax, Vector3.up);

            return new Plane(normal, position);
        }

        public bool IsInRange(Transform t, Vector3 point)
        {
            var position = Position(t);
            float dist = Vector3.Distance(position, point);
            if(dist <= Range)
            {
                var minP = MinPlane(t);
                var maxP = MaxPlane(t);
                var direction = point - position;

                if(Vector3.Dot(minP.normal, direction) > 0 || Vector3.Dot(maxP.normal, direction) > 0)
                {
                    return true;
                }
            }
            return false;
        }