23
\$\begingroup\$

I'm making an FPS game where, even when a target's whole body is behind a wall or box, but its finger or foot exposed, the AI should be able to detect it and shoot its finger.

So far the way I've thought of to implement this it so traverse all the targets, find who is near a wall, and compare their position with the corner of wall. But I don't know how to check whether its finger is exposed.

I could use a raycast forward from the AI's gun, but would I need to add a collider to every small body part of every target?

\$\endgroup\$
2
  • 10
    \$\begingroup\$ are you sure you want the enemies to be that good? And are you sure you want an exposed ankle to be lethal? \$\endgroup\$ Mar 3 '20 at 13:45
  • 13
    \$\begingroup\$ @ratchetfreak The question doesn't mention lethality. \$\endgroup\$
    – Mast
    Mar 4 '20 at 5:54
68
\$\begingroup\$

This isn't common in all shooter games, but some do go to this level of detail. In Splinter Cell games, for instance, AI can detect Sam's individual body parts.

When an AI is performing a detection check, we fire rays to selected bone positions in Sam's animated skeleton, and tally up how much of him is visible. (We also evaluate lighting per bone, so they only detect you if they can see enough of you in the light)

You don't need a collider on each bone to do this; you just need to do a raycast with a fixed length, or a point-to-point linecast. If you get no hits, that means no other object intercepts the line of sight, and the destination point is visible.

Doing it this way lets you control the sensitivity, by choosing which bones to test, and setting a threshold for how many exposed bones are needed to count as visible/shootable. Maybe having your whole hand exposed up to the wrist, or whole arm out to the elbow should be a liability, but having just a finger exposed doesn't count. (This also lets you manage the cost of doing these checks, by setting an upper cap on how many rays to fire)

Keep in mind that players' controls might be precise enough to keep their arms and legs tucked in if they're careful, but they probably don't have the fidelity to control placement of their toes and fingers, which are driven by animation. Nor does the typical gameplay view help them notice when those little bits might be sticking out. So penalizing the player for too small a misalignment might not make your game feel more realistic, but instead make it feel like the game is cheating and letting AI shoot through walls.

\$\endgroup\$
4
  • 3
    \$\begingroup\$ Also make sure to check the arm bone before the hand bone, and the hand bone before the finger bone, etc. Go from the most likely bone to be visible to the least likely and from the simplest check to the most complex (e.g. the head may be one bone but the hand could be a bunch of fingers). \$\endgroup\$
    – Kevin
    Mar 4 '20 at 10:37
  • 26
    \$\begingroup\$ "So penalizing the player for too small a misalignment might not make your game feel more realistic, but instead make it feel like the game is cheating and letting AI shoot through walls." <-- this indeed makes a game extremelly frustrating, or unplayable for casual players, as they are shot without any way to protect themselves, without knowing what and were it is coming from (the shooter may be obscured by something but can see your toes). \$\endgroup\$ Mar 4 '20 at 12:53
  • \$\begingroup\$ A way to make this more fair would be if getting shot in other than the head or chest can't reduce your HP below a certain amount. In real life, you'd bleed out eventually, but otherwise being shot in the arm over and over isn't going to kill you. \$\endgroup\$
    – Matthew
    Mar 5 '20 at 19:26
  • \$\begingroup\$ It could easily also be extended to even test for "sub-object" parts: when you just do multiple ray casts for each bone (based on angular size/bone size and distance?) and then test for a "minimum amount visible". \$\endgroup\$
    – paul23
    Mar 6 '20 at 14:13
23
\$\begingroup\$

If you really want to detect any exposed part of the player, the extreme approach is to simply render the scene from the gun's perspective using replacement shaders, such as the player rendering as plain white while everything else renders black - any pixels which are white in the result show a potential target. You can even use multiple colour channels to make the AI aware of seeing the player behind glass (e.g. glass renders as red with a multiply shader, so white means visible and exposed, red means visible but not exposed, and black means not visible).

To introduce some amount of forgiveness you could only have the AI take a shot if a large enough area is detected (maybe a few tens of pixels depending on the render resolution). This can be accomplished with segmentation techniques back on the CPU, or with a blur+threshold if you have GPU cycles to spare.

This is pretty similar to the technique used to cast shadows from light sources, which is analogous to what you are trying to achieve. Note that (as with light source shadows) this doesn't scale well to hundreds of enemies, though you could have enemies take it in turns to "see", with a few being rendered each frame. Also if there is only one target (the player), you can use some smarts to restrict the area which is actually rendered to only cover the computed limits of the player's bounding box.


As pointed out already, this seems pretty cruel to the player, so make sure it's actually a fun mechanic in your game before committing to it!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ For the scaling, one way to address that is to create timed "attack slots" (like 1-10 per frame or second), and but all the enemies on an attack schedule (like round robin). This limits how many can attack at once, and how many checks you have to do. (It can also have the side effect of making the enemies more aggressive as they die off, which could be a good thing) \$\endgroup\$
    – Tezra
    Mar 5 '20 at 13:29
3
\$\begingroup\$

I assume your current way of detecting visibility is checking a clear line to the centre of the bounding box?

If so, then one viable approach would be to keep doing this, but additionally choose a few random points belonging to the player model to check. This might even add a bit of realism to the experience: the AI will instantly detect the fully exposed player, but it may take from a second to notice the hand sticking out up to a minute to see the finger. After first hit, you'd probably want to remember the previously-random point, so that the AI keeps seeing the poor player.

\$\endgroup\$
2
\$\begingroup\$

Building on previous answers, the most common solutions are to raycast multiple times, although I believe your approach of querying for enemies that are near walls can get buggy over time (if you add cover that is not "a wall", i.e. a character standing near a car that simply occludes LoS but is not a proper cover)


Most games do a gradual checking from cheapest to most expensive (assuming your detection works with a view cone for simplicity):

  • Spacial partition, AABB or sphere collider (filter which characters are in range)
  • Visibility culling (filter which characters are within the view cone, removes characters in range but behind or on the sides)
  • Raycasting to bones (filter which characters are visible)

Choosing the bones depends on the kind of game you're working on, what feel you want the players to have when playing and how the AI behaviour can help to enforce a certain playstyle.

  • Last of Us casts a single raycast to the hip when the character is standing and switches to raycast to the head when the character is crouching. This works well with a carefully designed level where there are no gaps at waist height for the enemies to see your hip when you don't see them Check Figure 34.4
  • Splinter Cell casts on 8 different bones and has a minimum requirement of visible bones for detection (eg. 3 out of 8). This brings out the ability to change the visibility threshold for certain areas (eg. if it's dark enemies need 5/8) or for enemy types (eg. snipers only need 1/8) Check Figure 28.1
  • Like pointed out by @Dave, if you really want to detect/shoot on ANY visible little bit, rendering it to a texture is probably the best way to go although you'll have very unhappy players that get shot from "nowhere". It might work when if it supports the character's backstory and there is an "excuse" for it to be so accurate, if it's a super killing machine or a ruthless legendary sniper.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.