• 3D
  • 3D cone of sight

I've got a 3D grid map, and the enemy has a ray cast going forwards that tells it if it can see the player, or if a 'block' (I'm creating levels out of 3d blocks using a gridmap) is blocking it's vision.

That works fine, but it only works if the player is directly in front of the enemy. If the player is slightly to one side the ray cast misses the player, or catches a block.

So, I'm wondering what is the best way to do a 3D line/conde of sight, or the easiest.

Should I have several raycasts coming out of the enemy at slightly different angles?

I can't work out the code to detect if the player is in front of the enemy.

thanks

Here's a few ways I would try to go about it:

---

Method one (simple): Assign a cone shaped area to your camera and when the enemy enters the area, have your enemy act accordingly. You could also check from the enemy, assigning a cone shaped area in front of it and checking if the player enters it and acting then.

The problem with this method, is that it has no idea if a block is in front of it or not! A way to get around this is to make the cone relatively short, so that the player/enemy wouldn't be able to get into the area through a block.


Method two (complicated): Assign a cone shaped area to your camera and when it detects an enemy, send a raycast towards it. If the raycast hits the enemy, then you can see the enemy, and if the raycast doesn't hit the enemy then there is something in the way. This can also be done from the enemy, you just have to change whom you assign the area to and where you project the raycast from.

The issue that makes this method complicated is figuring out how to angle the raycast towards the target. (I haven't really had a lot of luck with raycast aiming... But maybe it's just me?)


Method three (potentially costly): Like you said, you could send multiple raycasts out of the enemy at slightly different angles, but this could grow costly if you have too many enemies.

One way to get around it, is to check the enemies distance from the player, and only send raycasts out when the player is close.

Another way is to break your game world into chunks and only send raycasts out from the enemies in the active chunk, leaving the other enemies in other chunks without raycasts.

A third way to handle this, is you could send the raycasts out from the player, and when it hits an enemy then have the enemy react. Enemies will only react when you see them though, so they couldn't do things like sneak up from behind or move towards you before you see them.

Of course, if you implement this and don't notice any slowdown, then I wouldn't worry to much about optimizing!


Hopefully these will give you some ideas on how to go about it. I haven't actually tested/used any of these methods, so they are more theoretical than actual working methods, but these are the methods I would try if I was trying to make a 3D cone of sight.

Interesting ideas, thanks. My game is a top down.! See the image for the idea

I've got the ray cast pointing working, which can tell if a block is blocking the vision of the enemy. I just can't work out how to tell if the player is in front of the enemy or not. The enemy can rotate, so I can't use simple z o x axis.

I know I should use the dot product, but can't find anything on how to use it in this situation.

If you need help telling what object is the player, and what object isn't, I would recommend using groups! You can add them in the editor or through gdscript, and you can figure out if the thing in front of the raycast is the player or not using something like this: ` var collider = raycast_result["collider"] if collider.is_in_group("player") == true:

It's the player!

else:

It's a block!

`

This uses Node.is_in_group which should work for 90% of cases.

As far as using dot product goes, maybe this will help? Godot documentation vector math

Thanks.
But, I have the raycast working fine,

I've read that documentation, but it doesn't really explain the use and I don't know how I'd translate it into what I want.

Oh, okay.

I'm afraid to say I don't know a whole lot about vector math. Hopefully someone who knows better will be able to help.

Got it! So, that if anyone else has the same problem in teh future:

var a = enemy.get_transform().basis.z # Enemy's forward vector var b = (player.get_translation() - enemy.get_translation()).normalized() # Vector from enemy to player

if acos(a.dot(b)) <= deg2rad(60): # If the angle is less than or equal to 60 degrees print("Enemy sees player.")