A few ways of doing it. Here’s a pretty simple one:
The function is going to take the target we are trying to see, how wide of an angle the object with the script can see within, and how far they can see. If you don’t need any of those aspects, you can remove them.
bool CanSeeTarget(Transform target, float viewAngle, float viewRange) {
Next lets find the direction towards our target:
Vector3 toTarget = target.position - transform.position;
Now we are going to do three checks to find out if we can see the target in that direction. I’ve nested the three checks inside each other for readability, but you could just put them in one if statement connected by “&&” operators if you prefer. First lets check that the angle between our current facing and the target direction is within our viewing angle:
if (Vector3.Angle(transform.forward, toTarget) <= viewAngle)
If thats the case, then lets perform a raycast to check if there is anything blocking our view of the player:
if (Physics.Raycast(transform.position, toTarget, out RaycastHit hit, viewRange))
This returns true if a line between us and the target hits something. There are tons of options you can add to the raycast to ignore certain layers and so on, but here im just feeding in the transform.position for the start of the ray (you might want to swap this for an eye position if you want to get fancy), the direction towards the target, and the view range. I’m also creating a “RaycastHit” output which we can use in our third and final check:
if (hit.transform.root == target)
return true;
We’re checking if the thing our ray hit was the target, and not something else that was blocking the view. Finally if any of those checks failed we end up here:
return false;