Stealth Gaming Good Times

Here is a cool thing I did the other day with AI for my stealth game. I made it so that if a guard hears a sound that he doesn’t know what it was, and can’t see the player, he’ll check for torches nearby and if there is one, he’ll go grab it, then investigate the noise (move to the location of the sound). They don’t bother with a torch if the torch has been doused, or if they already have fire arrows, because they can see by that light. The awesome thing is, this accidentally made it so that if a guard doesn’t have a torch, and hears a noise he wants to investigate, he can go steal a torch from a guard who has one. It is lol.

Also, check out this sweet placeholder HUD.

arrows

Procedural stairs, maybe the most frequently useful tool-thing I’ve done yet. Probably coming to a marketplace near you but not literally because the unreal engine marketplace doesn’t exist in physical space

Started making a procedural building generator, starting with rooms. So far it can make a room of any x/y dimensions (z to come) out of existing wall/floor/ceiling meshes while keeping scaling consistent (if not always uniform). If a room’s length or width isn’t a multiple of the length/width of the mesh being scaled, all meshes on that wall/ceiling/floor are scaled to compensate which means they’re often stretched slightly but never more than like 10%, which is fine because modular mesh based level design routinely requires level designers to stretch meshes more than that anyway. Also this uses instanced meshes and can use random meshes if required. You can also elect to use a single scaled mesh for floor/ceiling rather than gridding them like this

Light/shadow stealth in UE4 with Blueprint

Here’s a new video of the stealth game thing:

A few people have asked me how I got the light/shadow stealth thing working, so I wrote this out real quick:

I struggled a bit with the light/shadow system and doubt I have the most efficient solution but it does work and it goes basically like this: I get a list of all the light actors in the world on game start, and update it very rarely, like every 30 seconds (number of actual light actors rarely if ever changes). For any lights where lightdistancefromplayer < attenuationradiusofthelight, I do a trace from the player to the light’s location, and if the trace hits anything (meaning something visible lies between the light and the player – maybe you’re right near a light but on the other side of a wall) I disregard that light.

For the remaining lights (so all lights which are within their attenuation radius from the player and aren’t occluded) and also the directional light if a trace determines it’s unoccluded, I do some math based on the light intensities/attenuation radii/falloff exponents to end up with a LitAmount value for the player between 0 and 1 where 0 is completely dark, 1 fully illuminated, which is the light gem value printed in white at the top of the screen. I also have a var to scale the contribution of the directional light for situations where the intensity doesn’t map super well to the actual desired canonical visibility, like strong moonlight. In the video above, standing in unoccluded moonlight alone makes you just slightly less lit up than is required for the AI to see you at a distance.

This approach doesn’t completely work for times when I’m being illuminated by lightcomponents rather than lightactors, which is often, because I have a lot of blueprints with lightcomponents – the torches and windows in that video mostly – and you can’t get a list of every lightcomponent in the world the way you can every lightactor, and that wouldn’t be super efficient anyway if I had to update that list a lot. So I have a custom component called DummyLightComponent which gets placed on every blueprint that has a lightcomponent, and automatically inherits that lightcomponent’s values for intensity, falloff and attenuation.

Every so often if the DummyLightComponent is within its attenuationdistance from the player it adds itself to an array of dummylightcomponents on the player (this is the usually-0-or-1 value being constantly printed in the video in blue), and removes itself when it becomes irrelevant for distance/whatever reason. The array of dummylightcomponents gets the same math done to it at the playercharacter’s end as described above with the pointlightactors, and contributes to the LitAmount in the same way.

So the downside to this is there’s some amount of overhead for every light source in the game even when it’s not in range, but it’s only to the tune of, every so often (not every tick), checking the light’s distance from the player to see if it’s become relevant to stealth, and going no further if it’s out of range. I have no idea how much overhead that is but I wouldn’t imagine much, particularly if I’m not doing it every tick. However obviously it’s going to grow with how many lights are in the level, which isn’t going to be a negligible amount.

Anyway, I try to mitigate it by having an “irrelevant to stealth” bool on my light-containing actors that I can check if the light is out of player range/not near a situation where stealth is relevant/whatever, in which case the dummylightcomponent is actually removed and doesn’t tick.

Also, if the last time a light checked the player’s distance, it was above a certain amount, it will check less often, tuned more or less so that the time it takes for a light that thinks it’s far from the player to update is slightly less than the time it would normally take for the player to cover the distance to stand near it.

So theoretically, you never get a situation where a light isn’t updating the player’s LitAmount when they’re standing near it and it’s unoccluded, and most lights in the scene aren’t going to have a significant performance hit.

Hope this helps some googlers.