- Home /
Field of view, using raycasting
I am making a AI script. I have already made it so the script checks if the enemy can see the player, based on a raycast that checks if there are any obsticals obscuring the enemy's view of the player.
function CanSeePlayer() : boolean{
var hit : RaycastHit;
var rayDirection = playerObject.transform.position - transform.position;
if (Physics.Raycast (transform.position, rayDirection, hit)) {
if (hit.transform.tag == "Player") {
Debug.Log("Can see player");
return true;
}else{
Debug.Log("Can not see player");
return false;
}
}
}
The problem is that this gives the enemy a 360 degree view, how can i restrict it so the enemy can only see the player if the player is within a 135 degree cone in front of the enemy?
Answer by Mattivc · Apr 22, 2010 at 12:20 PM
I found a solution to the problem, i used Vector3.Angle to detect how far away from the front of the enemy the player is. The code ended up looking like this for anyone that might be interested:
function CanSeePlayer() : boolean{
var hit : RaycastHit;
var rayDirection = playerObject.transform.position - transform.position;
if(Physics.Raycast (transform.position, rayDirection, hit)){ // If the player is very close behind the player and in view the enemy will detect the player
if((hit.transform.tag == "Player") && (distanceToPlayer <= minPlayerDetectDistance)){
return true;
}
}
if((Vector3.Angle(rayDirection, transform.forward)) < fieldOfViewRange){ // Detect if player is within the field of view
if (Physics.Raycast (transform.position, rayDirection, hit)) {
if (hit.transform.tag == "Player") {
//Debug.Log("Can see player");
return true;
}else{
//Debug.Log("Can not see player");
return false;
}
}
}
}
Physics.Raycast has a overloaded method that let you put in the distance which should take out that useless if statement comparing distances and shortened the raycast to the desired length.
Shouldn't you be dividing fieldOfViewRange
by 2 when you check for your angle? For ex: your AI's fov is 90 dgs facing forward, but then angle between your AI's forward and the direction between your AI and the player is 60 dgs, in this case 60 is less than 90 but the player is actually outside the view cone! So ins$$anonymous$$d of checking for 90, it should be 45 (half the cone). 60 is not less than 45, so it's out of view.
I think the OP needs a 135 degree fov. So he should've put in that and it would work. You require 180 for the above case to work.
Answer by agentsmith · Jul 01, 2010 at 12:30 AM
Thanks Mattivc!! This helped me a lot... I tried to figure out what some of your variables are since not all of them were declared in your code snippet. Here's my slightly modified version if anyone wants to check out. Just attach this javascript script to the enemy, drag your player to the playerObject variable, and be sure the player is tagged "Player"
var playerObject : GameObject; // the player var fieldOfViewRange : float; // in degrees (I use 68, this gives the enemy a vision of 136 degrees) var minPlayerDetectDistance : float; // the distance the player can come behind the enemy without being deteacted var rayRange : float; // distance the enemy can "see" in front of him private var rayDirection = Vector3.zero;
function CanSeePlayer() : boolean { var hit : RaycastHit; rayDirection = playerObject.transform.position - transform.position; var distanceToPlayer = Vector3.Distance(transform.position, playerObject.transform.position);
if(Physics.Raycast (transform.position, rayDirection, hit)){ // If the player is very close behind the enemy and not in view the enemy will detect the player
if((hit.transform.tag == "Player") && (distanceToPlayer <= minPlayerDetectDistance)){
//Debug.Log("Caught player sneaking up behind!");
return true;
}
}
if((Vector3.Angle(rayDirection, transform.forward)) < fieldOfViewRange){ // Detect if player is within the field of view
if (Physics.Raycast (transform.position, rayDirection, hit, rayRange)) {
if (hit.transform.tag == "Player") {
//Debug.Log("Can see player");
return true;
}else{
//Debug.Log("Can not see player");
return false;
}
}
}
}
function OnDrawGizmosSelected () { // Draws a line in front of the player and one behind this is used to visually illustrate the detection ranges in front and behind the enemy Gizmos.color = Color.magenta; // the color used to detect the player in front Gizmos.DrawRay (transform.position, transform.forward rayRange); Gizmos.color = Color.yellow; // the color used to detect the player from behind Gizmos.DrawRay (transform.position, transform.forward -minPlayerDetectDistance);
}
I came across this while looking for something else, but was a question mark I had for quite some time. Thanks, both of you :)
I tried using this script and get the debug rays but it seems like the CanSeePlayer function never starts. I'm not sure what I'm doing wrong. I put a debug line at the top of it and it never shows in the console!
Answer by Augur · Jun 12, 2014 at 08:09 PM
The original question was just about finding the player in front of the enemy, which was exactly what I needed. I took the work of Mattivc and the suggestions of Jfcool10 and vexe and converted it into c# in case anyone else stumbles on this question.
protected bool CanSeePlayer()
{
RaycastHit hit;
Vector3 rayDirection = Player.transform.position - transform.position;
if ((Vector3.Angle(rayDirection, transform.forward)) <= fieldOfViewDegrees * 0.5f)
{
// Detect if player is within the field of view
if (Physics.Raycast(transform.position, rayDirection, out hit, visibilityDistance))
{
return (hit.transform.CompareTag("Player"));
}
}
return false;
}
Answer by jmunozar · Sep 11, 2014 at 05:22 AM
I know this has already been answered but here's a fast, light and easy to use implementation without any physics code of the FOV for 2D http://www.pencilsquaregames.com/2014/09/light-easy-and-fast-field-of-view-2d/ it can be easily be expanded to 3D with some extra thinking.
Answer by andreyakladov · Oct 06, 2020 at 09:04 PM
this is a simple OverlapSphere-based implementation of horizontal field of view:
IEnumerator FindVisibleTargetsWithDelay()
{
while (true)
{
yield return new WaitForSeconds(visibleTargetsUpdateTimeInterval);
FindVisibleTargets();
}
}
void FindVisibleTargets()
{
mostRelevantTarget = null;
visibleTargets.Clear();
var targets = Physics.OverlapSphere(transform.position, radius, targetMask, QueryTriggerInteraction.Ignore);
foreach (var col in targets)
{
var target = col.transform;
var direction = (target.position - transform.position);
var horizontalAngle = Vector3.Angle(Vector3.ProjectOnPlane(transform.forward, Vector3.up), Vector3.ProjectOnPlane(target.position, Vector3.up) - Vector3.ProjectOnPlane(transform.position, Vector3.up));
if (horizontalAngle < angle/2)
{
var distance = Vector3.Distance(transform.position, target.position);
if (!Physics.Raycast(transform.position, direction, distance, obstacleMask))
{
var targetInfo = new TargetInfo(target, horizontalAngle, distance);
visibleTargets.Add(targetInfo);
if (mostRelevantTarget == null)
{
mostRelevantTarget = targetInfo;
}
else
{
var mrTarget = mostRelevantTarget.Value;
if (targetInfo.distance < mrTarget.distance)
{
mostRelevantTarget = targetInfo;
}
}
}
}
}
}
Your answer
Follow this Question
Related Questions
Enemy Ai Field of View 0 Answers
Problems with raycast obstacle avoidance 1 Answer
AI Avoiding Obstacles Problem 1 Answer
AI create path, help. 1 Answer
How can I find if a raycast has passed through two points? 2 Answers