This site uses strictly necessary cookies. More Information

X# 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.

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[i].x, position.y, position.z + arcPoints[i].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);
}
}
}
}
```

**Answer** by VRKeith
·
Nov 10, 2019 at 04:09 PM

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;
}
```

**Answer** by Captain_Pineapple
·
Nov 10, 2019 at 12:16 PM

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.

It's a bit hard to follow, because, for some reason, the page isn't loading a script that looks up the math symbols, so everything looks like: [\begin{split}\L{ g \vec{v} }^2 = \\ ( g \vec{v} ) \cdot ( g \vec{v} ) = \\ g^2 \VL{v}^2 = 1\end{split}]

So, trying to follow here, we want to see if the object is in front or back via a dot product, but I'm not putting together where to do this. Should I make planes out of the angles and use that for the dot product?

### Your answer

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.