Hello
I just make a field of view mesh, so I can check if any object is in it. I use Physics.OverlapSphereNonAlloc
to check overlap, then remove object whose center is not in the field of view. I use a ray cast from origin to the object center to check if there’s any occlusion. However, they all treat the object as a point instead of an object with volume. How do I return true
as long as any portion of an object overlaps the mesh? Or any portion is the the mesh and not occlued by others?
This is the part for checking if it’s in the field of view
bool IsInsight(GameObject gameObject)
{
Vector3 direction = gameObject.transform.position - transform.position;
if (Vector3.Dot(direction, transform.up)<-detectHeight/2 | Vector3.Dot(direction, transform.up)>detectHeight/2)
return false;
direction.y = 0;
Vector3 directionNormalToTransformUp = Vector3.Dot(direction, transform.right) * transform.right +
Vector3.Dot(direction, transform.forward) * transform.forward;
float deltaAngle = Vector3.Angle(directionNormalToTransformUp, transform.forward);
if (deltaAngle > detectAngle)
return false;
if (Physics.Linecast(transform.position, gameObject.transform.position, LayerMask.NameToLayer("Hider")))
return false;
return true;
}
The image is as attached [1]
This is the complete code
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Mathematics;
using Unity.MLAgents.Actuators;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.UIElements;
[ExecuteInEditMode]
public class TargetDetectingAgent : NavigationAgent
{
public float detectHeight;
public float detectAngle;
public float detectDistance;
private int segment=10;
public Color meshColor=Color.cyan;
private Collider[] detectColliders;
private LayerMask hiderLayer;
private int count;
private List<GameObject> detectObjects;
private Mesh mesh;
private void Awake()
{
moveInput.Enable();
dirInput.Enable();
MapGenerator mapGenerator = FindObjectOfType<MapGenerator>();
mapSize = mapGenerator.CalculateMapSize()/2;
PlayerSpawner playerSpawner = FindObjectOfType<PlayerSpawner>();
path = new NavMeshPath();
destinationSpawner = GameObject.Find("DestinationSpawner");
detectColliders = new Collider[playerSpawner.numberOfHider];
detectObjects = new List<GameObject>(playerSpawner.numberOfHider);
}
private void OnValidate()
{
mesh = CreateMesh();
}
private void OnDrawGizmos()
{
if (mesh)
{
Gizmos.color = meshColor;
Gizmos.DrawMesh(mesh, transform.position,transform.rotation);
}
Gizmos.DrawWireSphere(transform.position,detectDistance);
Gizmos.color = Color.magenta;
foreach (var obj in detectObjects)
{
Gizmos.DrawSphere(obj.transform.position, 0.7f);
}
}
private void Update()
{
Scan();
}
void Scan()
{
count=Physics.OverlapSphereNonAlloc(transform.position, detectDistance, detectColliders, 1<<LayerMask.NameToLayer("Hider"),
QueryTriggerInteraction.Collide);
detectObjects.Clear();
for (int i=0;i<count;i++)
{
GameObject obj = detectColliders*.gameObject;*
if (IsInsight(obj))
{
detectObjects.Add(obj);
}
}
}
bool IsInsight(GameObject gameObject)
{
Vector3 direction = gameObject.transform.position - transform.position;
if (Vector3.Dot(direction, transform.up)<-detectHeight/2 | Vector3.Dot(direction, transform.up)>detectHeight/2)
return false;
direction.y = 0;
Vector3 directionNormalToTransformUp = Vector3.Dot(direction, transform.right) * transform.right +
Vector3.Dot(direction, transform.forward) * transform.forward;
float deltaAngle = Vector3.Angle(directionNormalToTransformUp, transform.forward);
if (deltaAngle > detectAngle)
return false;
if (Physics.Linecast(transform.position, gameObject.transform.position, LayerMask.NameToLayer(“Hider”)))
return false;
return true;
}
Mesh CreateMesh()
{
Mesh mesh = new Mesh();
int numTriangle = segment*4+4;
int numVeritices = numTriangle * 3;
Vector3[] vertices=new Vector3[numVeritices];
int[] triangles=new int[numVeritices];
int x=0;
float deltaAngle = detectAngle * 2 / segment;
float currentAngle = -detectAngle;
Vector3 bottomCenter = Vector3.zero + Vector3.down * detectHeight / 2;
Vector3 bottomLeft= Quaternion.Euler(0, -detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;;
Vector3 bottomRight= Quaternion.Euler(0, detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;;
Vector3 topCenter= Vector3.zero + Vector3.up * detectHeight / 2;
Vector3 topLeft = Quaternion.Euler(0, -detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
Vector3 topRight = Quaternion.Euler(0, detectAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
//Triangles on left side
vertices[x++] = bottomCenter;
vertices[x++] = bottomLeft;
vertices[x++] = topLeft;
vertices[x++] = bottomCenter;
vertices[x++] = topLeft;
vertices[x++] = topCenter;
//Triangles on right side
vertices[x++] = bottomCenter;
vertices[x++] = topRight;
vertices[x++] = bottomRight;
vertices[x++] = bottomCenter;
vertices[x++] = topCenter;
vertices[x++] = topRight;
for (int i=0;i<segment;i++)
{
bottomLeft = Quaternion.Euler(0, currentAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;
bottomRight = Quaternion.Euler(0, currentAngle+deltaAngle, 0) * Vector3.forward * detectDistance +
Vector3.down * detectHeight / 2;
topLeft = Quaternion.Euler(0, currentAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
topRight = Quaternion.Euler(0, currentAngle+deltaAngle, 0) * Vector3.forward * detectDistance +
Vector3.up * detectHeight / 2;
//Triangles on far side
vertices[x++] = bottomRight;
vertices[x++] = topRight;
vertices[x++] = bottomLeft;
vertices[x++] = topRight;
vertices[x++] = topLeft;
vertices[x++] = bottomLeft;
//Triangles on top
vertices[x++] = topRight;
vertices[x++] = topCenter;
vertices[x++] = topLeft;
//Triangles at bottom
vertices[x++] = bottomRight;
vertices[x++] = bottomLeft;
vertices[x++] = bottomCenter;
//Update currentAngle
currentAngle += deltaAngle;
}
for (int i = 0; i < vertices.Length; i++)
triangles = i;
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
return mesh;
}
}