I've been working on a prototype for a horror game, based on the idea that you aren't allowed to look at the "monster". Some technical and design info after the video.
CW for a jumpscare/loud noise at the very end of the video
The original idea just started with the monster killing you when you looked at it, which seemed to me like an interesting design for a horror game since it means you have to listen carefully for where the monster is in order to avoid looking in its direction. To that end, I've been messing with steam audio/phonon a bit for accurate spatialization but I still have a lot of work to do on that.
It also means the AI can have a somewhat unusual design, where its goal isn't to find the player but instead to stand in places that the player is likely to look towards. Right now the AI is fairly simple - it chooses to walk to a spot either in front of the player, behind the player, or near an active objective (the buttons in the video and certain "screens" that display important information).
After implementing the basic enemy AI I realized that there could be some interesting uses for visibility checks in puzzles. This resulted in the many "displays" that change depending on whether you're looking at them, and the glass material that blocks visibility checks. I've got a few (currently unimplemented) ideas of how to use these for more puzzle designs beyond the simple "button code" example above so stay tuned :)
On the technical side, knowing whether the player is looking at a particular actor is done with the use of custom depth/stencil in order to give near-pixel-perfect accuracy for whether the player can see something. I've created a subsystem that is assigned a certain range of stencil values, and the subsystem assigns out those values every frame to actors that want to know whether the player is looking at them.
When there are too many actors to assign each one a unique value, the subsystem instead cycles through the list of actors changing which ones are being checked for visibility every frame. Additionally, the list of actors to check is culled by a number of functions including some basic broad visibility checks (don't check actors that are behind the player, don't check actors that are far away).
Here's what it looks like when I severely limit the number of values available for checking visibility and slow down the process (no jumpscares this time, just showing what visibility checks look like):
It's practically impossible to tell by eye, but each of the "squares" on the render target have a slightly different value, which allows the system to know exactly which ones are on screen.
All that said, the visibility system is somewhat inefficient at the moment. It depends on a scene capture with post processing material that writes custom depth to a render target, and then reading that render target back on the CPU to dispatch visibility information to the relevant actors. This means an extra render of the scene which is definitely not necessary - ideally I'd be running a shader during the regular render pass and output a small buffer with visibility information. But that's a project for a later time - I'm just happy this works as well as it does.
Anyway, that's all for now. Not sure where I'll go with this (or when...) but I think it's neat :)