2
\$\begingroup\$

I have a bunch of patrolling enemies that fire projectiles when the player is in projectile range - a specific radius. Which method is the most efficient and elegant?

  1. overlapSphere
  2. sphereCast
  3. triggers
  4. square magnitude
  5. anything else?

I am using Unity.

\$\endgroup\$
2
  • 4
    \$\begingroup\$ The best answer to efficiency & performance questions is to try multiple options and profile them yourself - then you know for sure how they perform on your target hardware for your use case/enemy count and in the context of the rest of your game. As for elegance, that's a matter for your personal coding style and taste. ;) I can say SphereCast isn't what you want though, since it fires a sphere along a ray rather than just checking in a radius of a point (which OverlapSphere does) \$\endgroup\$
    – DMGregory
    Dec 16, 2015 at 5:32
  • \$\begingroup\$ I second what @DMGregory said. In my case, I'd use square magnitude since it is the most efficient algorithmically, and the easiest to implement. Although, if I were to have different range shapes, then I would use triggers. But for a radius definitely square magnitude, which involves just a couple of lines of code. \$\endgroup\$
    – EvilTak
    Dec 16, 2015 at 19:43

2 Answers 2

1
\$\begingroup\$

I haven't actually done any profiling, but the off-hand guestimate based on the way the physics engine should be optimized and some knowledge on the approximate complexity of various operations, my suggestion is:

Because you have one player, it will be very cheap for each of your enemies to check the square magnitude during their update tick. Very very cheap. Although it does go against the idea that the enemies shouldn't always know where the player is. But for a quick-and-dirty check prior to more intensive checking, it will work.

However, this won't necessarily be good for objects that have to check against multiple actors. E.g. an automatic door that opens whenever a guard patrols by it, or the player gets near. Or in a game I'm working on, guards that attack any intruder. And the player isn't always the only intruder (nor are the other intruders necessarily friendly to the player!). So what I do is:

  1. first do a overlapSphere. overlapSphere is cheap. The physics engine is likely performing a squareMagnitude call on every collider in the scene (there are other optimizations, such as maintaining a quadtree of the scene, so it doesn't have to check every collider, just some, as well as having a good layer mask; a bitwise AND will be faster than squareMagnitude) and returns a list of the ones that passed.
  2. For every collider returned, do a frustum check. This will vary by enemy, some can only see in front of them, some can see in all directions, but not very far up and down (e.g. can't see above themselves), another can only see above and below, but not horizontally. This is pretty cheap.
  3. Finally, on the remaining colliders, perform a raycast. Raycasts are expensive (relative to any of the above methods), but super accurate. sphereCast (and capsuleCast) also falls into this category, but is more useful for knowing if an object of a given size will reach. Good for knowing if an AI can walk down a narrow passage or fit under a low hang. But a small sized sphere in a sphereCast might be "friendlier" to the player than a raycast, as it means they can peek out around corners a little more (the larger the sphere the more they can peek out).

You can get away with a lot of raycasts in a frame without bogging down the FPS, but you definitely don't want every enemy performing a raycast on every ally every frame. Its just not needed. As the game I'm working on is a stealth game, I actually perform 5 raycasts: one against the center of the player (as you're going to be doing) and then four more towards approximated corners of the player's bounding box (relative to the enemy's view direction), which does the opposite of the spherecast I mentioned earlier: it makes it tougher on the player to stay out of sight. I have other mechanics in place to avoid this being harshly punishing (not only does the player have to be visible, the AI needs to perform a successful ID verification to recognize the player as hostile and the results are cached for a couple of seconds, avoiding even more raycasts: the raycast is irrelevant if the AI already "knows" that the player isn't hostile!).

All of this said, however:

Unless you're seeing a problem with frame rate, you're likely performing a premature optimization. For your usage, overlapSphere (followed by a raycast so things don't try to shoot through walls, assuming that's relevant) will be the best. Cheap enough and accurate enough to be good enough.

Watch your profiler and make optimizations based on where the lag is coming from. Often it will be from something you don't expect. (Hint: manage your garbage well).

\$\endgroup\$
0
\$\begingroup\$

I have used Raycasts in most cases, this is because it applies well in a lot of cases, fast rendered, exact, and easy to debug.

Raycast documentation

Little tutorial on Raycasting

Although I find that using some of your above called options a good choice in some situations like; - Whenever I build a maze like game, I use triggers to trigger doors/events. - With a racing game I mostly use overlapping colliders to detect it, since this would be less aggresive on your performance and racing games aren't always known for the best collision detection (not including multi million games like GRID.)

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .