DuncanCraft 2000 is a Minecraft clone I made in C# using OpenTK. What originally started as a small weeklong project ballooned into a four-month project with different block types, UI, saving and loading, procedurally generated worlds, lighting, and sounds. Every once in a while, I get the itch to create a voxel game. I call these games DuncanCrafts because eventually they all turn into Minecraft clones.
DuncanCraft 2000 is my first real OpenTK/OpenGL project. I had made other voxel games in Unity, but for this project I really wanted to build one using my own engine. I had learned a little bit of OpenGL and made a small Minecraft clone in C++ before starting this, but C# is my primary language, and I wanted to use it for my next voxel project. The goal was to make a clone of Minecraft Classic, and I basically did it. The only things really missing from my version were water and lava.
The first problem I ran into was drawing a bunch of faces that the player would never see. Like Minecraft, my world is broken up into chunks of 16x128x16 blocks. But the player can't see all these blocks, with some being underground or hidden by other blocks. In the beginning of the project, I would render every face regardless of whether it was visible to the player (super early versions of Minecraft did the same thing) but this caused the game to lag a lot.
My solution was to check each face before rendering it. I would see if there were any blocks adjacent to that face. If there was a block there, I wouldn't add the face to the render queue. If there wasn't, I would add it and the face would become visible to the player. This worked pretty well, but once I made the worlds infinite, I ran into the problem of faces being rendered on chunk borders where they shouldn't be. To solve this, when a new chunk is generated it tells the chunks it touches to regenerate some of their boundary faces. This made sure everything stayed properly hidden even across chunk borders.
The biggest problem I ran into was lighting, and honestly I almost went insane, I had dreams where I was working on it. In the early project, lighting was super simple. Basically every visible face would check if it could see the sun. If it could, it was bright. If it couldn't, it was dark. Very simple, no propagation, and light wouldn't spread out at all. But I decided I wanted Minecraft-style lighting with proper light propagation.
This was so much harder than I expected. Using videos and old Minecraft source code, I was able to replicate it in my game, but only on like one chunk. Solving the problem of light not propagating between chunks caused me to go a little insane. I would kind of solve it, but then the light wouldn't disappear when I broke a torch or covered a whole to the surface. Then I would fix that, but it would cause the light to not spread to diagonal chunks. I would solve that, but then it would make the game unplayable during lighting updates because of the performance hit. I would solve that, but then the lighting wouldn't go away when it should, and the whole cycle would restart.
Eventually I kind of brute forced it. When lighting changes, the system would regenerate the entire chunk’s mesh and its lighting. If the light spread over to a different chunk, it would also regenerate that chunk’s mesh and its lighting. It wasn't the most elegant solution, but thankfully the chunk mesh generation didn't take super long, so the regeneration wasn't super noticeable to the player.