Cave Unknown is a horror game I am working on as a passion project, and plan to release at some point.
The procedural caves are generated with a cellular automaton algorithm, the marching cubes algorithm, a flood fill algorithm and triplanar projection.Â
The audio ray tracer is recursive. From the ray data I dynamically calculate attenuation/absorption and RT60 (reverb time). These parameters are sent to FMOD to process the sounds. One trace can spawn multiple audio sources if multiple rays hit you.
Cellular automata usually generates a grid of binary data. In my implementation I use a float range from 0 to 1. This allows for smoother looking caves, and it also allows for more precise destruction. You can see that in the video above.
I programmed all of it in C++ using Unreal Engine 5. I am currently turning this demo into a full horror game.
Everything you see in the videos below is ready for online multiplayer, including the cave destruction.
Learned how to make cool looking caves using cellular automata with float data.
Learned about procedural mesh calculation like calculating its UVs and its normals.
Learned about the marching cubes algorithm. I now know how to generate a mesh from a grid of data.
This was my first time really using C++ with unreal engine. I learned more about the connection between them and how to use them effectively together.
Learned about the networking implementation of unreal engine, and got better at using it (RPCs, RepNotify, authority, etc.)
I extensively worked with FMOD Studio when I made the audio ray tracer. I learned a lot about how audio works in the real world, so I can simulate it in the game. When making the proximity voice chat I had to insert custom steam voice data into FMOD using its lower level functions (PCMReadCallback).
How to use steam subsystem to create and join online lobbies
So much more
The above video showcases the shape of the caves that I am generating. For this particular method of cave generation I did something very unique that I haven't seen before. I used cellular automata, something that traditionally stores its grid values as 0s and 1s, and I used float values between 0 and 1 instead. The reason for this is that having float values allows me to smooth out the cave using linear interpolation.
Having procedural caves means I can quite easily make the cave destructable, as you can see in this video:
The above video showcases the custom audio ray-tracer that I made. Each time a sound is made, I shoot rays in all directions. Ray can bounce up to a specified amount. Based on what rays hit the player, I can dynamically determine how much reverb, muffling and muting I need to do based on real world physics equations. I even take the speed of sound into account. If you listen with headphones, you can hear sounds reflecting from the walls, so the player will hear a sound from multiple locations, just like in a real cave.