- Home /
My FOV for enemy script is not working
Hello! Good Day! My script works in some kind of way but the problem is distance and when other objects are blocking, the enemy is able to target the player even from far away or with a wall blocking its sight, only the angle of view works.. Here my script :/
void CheckPlayer()
{
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 toPlayer = target.transform.position - transform.position;
if (Vector3.Dot(forward, toPlayer) > 10 && Vector3.Distance(myTransform.position, target.position) < awareness)
{
wander = false; //would turn off random roaming and target player
}
else if (Vector3.Dot(forward, toPlayer) < 10 && Vector3.Distance(myTransform.position, target.position) > awareness)
{
wander = true; //would turn on random roaming
}
}
Answer by Bunny83 · Mar 23, 2019 at 12:51 AM
There are some things confusing. First of all this line:
Vector3 forward = transform.TransformDirection(Vector3.forward);
is just the same as
Vector3 forward = transform.forward;
Next i'm not sure you understand what this actually means: Vector3.Dot(forward, toPlayer) > 10
This will only be true if the player is at least 10 units away from your enemy, but only along the enemy's forward axis. On the other hand this: Vector3.Dot(forward, toPlayer) < 10
would be true whenever the player is too close or behind the enemy.
When you said FOV you probably wanted to define a field of view. For this you need normalized vectors. In this case the Dot product returns the cosine between the two vectors. However it probably would make more sense to use Vector3.Angle which returns the angle between the two vectors in degrees. Something like this:
void CheckPlayer()
{
Vector3 forward = transform.forward;
Vector3 toPlayer = (target.transform.position - transform.position).normalized;
bool inView = Vector3.Angle(forward, toPlayer) < 45;
bool inRange = Vector3.Distance(myTransform.position, target.position) < awareness;
if (inView && inRange)
{
wander = false; //would turn off random roaming and target player
}
else if (!inView && !inRange)
{
wander = true; //would turn on random roaming
}
}
This gives the enemy a 90° field of view (+- 45°). If you use "90" instead it would have a 180° vision. If you want to use Vector3.Dot instead you would need to compare the result to the cosine of the half of your desired angle. Though Vector3.Angle actually does use Vector3.Dot internally but also normalizes the vectors and converts the cosine into an angle.
Note that of course this does not account for objects blocking the view since this can't be solved in an objective way as what "blocked" means is subjective. A common way is to simply perform a raycast towards the target object. If it didn't get through it is considered "not visible". Note that with this approach half or more of the player could "actually" be seen by the enemy but the center where the ray is casted is blocked. Likewise a tiny hole in an otherwise blocking wall would allow the ray to "see through". If it's an important feature, some games cast multiple rays and calculate some kind of awareness value. The more of a player can be seen, the faster it will spot the player
Seems like its working although i think i also have a problem with the boolean it wont set to true but everything else is working fine...
any ideas? why boolean is not turning on? (this inside a void update btw)
if (wander == false) { agent.SetDestination(target.position); attackPlayer();
{
extraRotation();
}
}
if (wander == true)
{
timer += Time.deltaTime;
if (timer >= wanderTimer)
{
Vector3 newPos = RandomNavSphere(transform.position, wanderRadius, -1);
agent.SetDestination(newPos);
extraRotation();
timer = 0;
}
}
Answer by Vollmondum · Mar 20, 2019 at 06:52 PM
toPlayer = Vector3.SqrMagnitude(target.transform.position - transform.position)
Yeah. transform.position - target.position is a vector, endless line, FYT$$anonymous$$
Hmmm just tried this now... Doesn't seem quite to work(red line/errors) is it supposed to be written this way? I don't quite get how you are doing this
void CheckPlayer()
{
Vector3 forward = transform.TransformDirection(Vector3.forward);
Vector3 toPlayer = Vector3.Sqr$$anonymous$$agnitude(target.transform.position - transform.position)
if (Vector3.Dot(forward, toPlayer) > 10 && Vector3.Distance(myTransform.position, target.position) < awareness)
{
wander = false;
}
else
if (Vector3.Dot(forward, toPlayer) < 10 && Vector3.Distance(myTransform.position, target.position) > awareness)
{
wander = true;
}
}
Vector3.Sqr$$anonymous$$agnitude(target.transform.position - transform.position) is already a distance from one spot to another. You don't need anything else. One line to make everything you try to spoil around it.
void CheckPlayer() { Vector3 toPlayer = Vector3.Sqr$$anonymous$$agnitude(target.transform.position - transform.position)
if (toPlayer > awareness)
{
wander = false;
}
else
{
wander = true;
}
}
}
any ideas? why boolean is not turning on? (this inside a void update btw)
if (wander == false)
{
agent.SetDestination(target.position);
attackPlayer();
{
extraRotation();
}
}
if (wander == true)
{
timer += Time.deltaTime;
if (timer >= wanderTimer)
{
Vector3 newPos = RandomNavSphere(transform.position, wanderRadius, -1);
agent.SetDestination(newPos);
extraRotation();
timer = 0;
}
}
Because there's no line saying "wander = true" :)