Hello! It has been a while. Usually this is the point where the solo-developer that hasn't published anything on their project in 9 months announces something about burnout and how they are slowing down on the project and it innevitably ends up cancelled. I know because this is exactly what I have done countless times.
Not today!
I'm pleased to say Build Fight Game has remained in constant - albeit slow - development over the past nine months. I've had a turbulent time within my personal life which made it harder to focus on development, and by the time I'd worked through most of that to the point that I felt ready to throw myself back into this project, I had a full-time job which left me almost no time to work on the game. Fortunately, I have now reduced my hours at work and have been getting back into the swing of things.
The sniper video is still my next planned video. I am going to be retooling much of it because I am not very happy with where the script ended up; I planned it as a half-video-essay-half-devlog thing which outlined all my problems with snipers and then exactly how I address those in Build Fight Game, but I think in the end I was far too authoratative about what is ultimately just a matter of my own taste in games. I will be drastically reducing the more 'analytical' portion of the video to make it more clear that I am not saying snipers are objectively bad, and to focus more on how fun they can be.
I am very proud of the animation work I have done for this upcoming video. Where previously I made the 3D segments in Unity with very stiff pose-to-pose 'animation', for this video I used Blender and several fully animated sequences in a wider variety of environments. The jump in visual quality from my previous videos to this is genuinely staggering. Here's a sneak-peek, I can't wait for everybody to see the rest!
I'm not sure exactly when this video will be ready. It all depends on both the actual development of the game - including systems not directly related to the sniper and Construction class itself - and how fast I can iterate on the actual video itself. I am aiming to not have to do anymore animated sketches beyond the 'talking in front of a screen' type stuff. But that is all external stuff. What have I actually been upto?
The previous voxel system simply was not cutting it. I worked my ass off to try to get it to run fast and work, but ultimately kept running up against the same issues: standard Unity C# can only go so fast. I tried threading as much as I could, but it was not enough. Major overhauls were required.
If only Unity had some sort of system for doing massive amounts of performance intensive work... For doing jobs some might say...
The Unity Job system is designed to allow you to write code that is parallelized by default. It spreads work across all CPU cores to maximise efficiency. Using Jobs also allows access to Unity's Burst compiler, which translates bytecode to super optimized native code. It's effectively a magic solution that - if your code fits the requirements for burst compilation - just makes everything... faster. Why wasn't I using this before??
Didn't really feel like it. Until now, none of my projects needed to be squeezing every drop of performance out of the engine like Build Fight Game does. For that reason, I never took the time to properly learn how to code within the Jobs system (it's weird. I won't get into it). However, it got to a point where BFG's base voxel implementation (written over the course of a few days when this project was still only supposed to be a small temporary thing) was being stretched far too thin. I wanted to do more with the system, to have more complex maps with intricate structures, and found that the system just could not scale to it. Furthermore, as the game got more complex overall I found again and again that the system was just not fast enough. As I spent more and more time trying to patch it up, I realized I would have to start from scratch.
Begrudingly, I spent a long time learning Jobs and applying that to a new voxel system. I originally started this in a seperate project to avoid destroying BFG by tearing out one of its most foundational systems. The Jobs-based voxel system was
blazingly
fast. Here you can see literal thousands of voxels being manipulated, processed, and drawn in a single frame.
With that, I had to spend time porting this to Build Fight Game itself. This was tricky to do, but not in such a way that it's actually interesting to write about. I just had to effectively re-attach all the methods that the game's various systems interfaced with to the new system, and go through checking to adjust any issues that may stem from assumptions made based on the old system. It was a whole lot of trial-and-error, really.
It did achieve exactly what I want to, though, giving a massive performance boost and also eliminating the extreme unpredictability and bugginess of the old system... I feel sick just thinking about it.
With this massively increased performance, I started to think about the game's visual design. I could now draw more voxels faster than ever! Unfortunately for me, they all just look like knock-off Minecraft blocks. My friend/colleague @UnusualOranges has done a great job creating pixel art textures for the game, which are fantastic, however, I was beginning to consider if that is the direction I wanted to take the game's artstyle in. For one thing, the grainy pixel art look was not ideal for an FPS title. Sure, in a game like Minecraft survival where you are not competing against other players and the pace is relatively slow it's fine, but there's a reason why all the Minecraft PVP texture packs use flat colours.
When I first started making BFG, as a placeholder I used these basic almost plastic-looking textures. As much as I think this is really boring and objectively worse than the pixel art look, something about that look appealed to me, and from a practical design perspective the block colours suit themselves to an FPS game. I went back to the drawing board, and had a think about what I wanted BFG to look like.
First-and-foremost, I thought practically. As much as this game is
not a competitive one, having a tightly-designed and fair experience is still important. Crucial to that is being able to recognize players from their environment. Since all the player models use saturated block-colours, the first step to devising a new visual language for BFG was to consider colour. I took inspiration from TF2, a game in which team and player recognition was a major design goal and everything in the game reinforces that (at least in 2007, whether that holds true today is another debate). I created a colour palette to draw from which assigned the most saturated blues and reds to player models, and had a few distinct desaturated environment colours. This was to be the baseline for the new design.
From there, I had to create the actual block textures. This was a challenge. I didn't want completely flat detail-less textures - that's boring and looks amateurish. But, at the same time, voxels are a fixed size and any small details when tiled in the millions just become a blur. They cause compression artificating when posted online, and can just be a general eyesore.
My first attempt at making new textures was... fine. The simple textures certainly fit the design goals, but the tiling is very obvious and at a distance the stripes get ugly. I wasn't really sure how to approach this. Either there is no detail, making block textures are boring; a lot of detail, making the world appear grainy; or a little detail, causing obvious tiling and still proving ugly at a distance.
The fundamental problem is that the voxels are 'small'. Of course, compared to other voxel projects like Teardown they aren't, but at scale, they are. What other games have objects that small in such massive numbers even at a distance? But, I couldn't make the voxels larger, that would just be no fun.
The solution? Make the texture bigger. Instead of a single texture mapped to a single voxel, map a large texture to several voxels. I used a variation of triplanar mapping to achieve this effect, and it truly elevated the entire look of the game. With the same WIP texture scaled up, suddenly the tiling is less obvious while detail shines through.
It doesn't look perfect, most notably where the sides of blocks don't quite match. This could be fixed with some manipulation of the texture, but ultimately I doubt these textures will last until release anyway. This was, however, enough for me to be confident that this approach was the right decision for the game. Now, distant blocks blend into solid colours more strongly, while up-close there is still visibile texture detail. I am in a position now where I feel I could work with an artist to create some truly good looking textures, and give the game its own visual identity.
After working so hard on fixing the game's visuals from a texturing perspective, I realized that the default Unity lighting was not doing me any favours. I dabbled briefly in the past with a very simple block-lighting system, which looked fine but only worked within a single chunk and the 'lighting' was all calculated just as a straight line up, turning the block dark if there was anything in the way. This system got shelved. With the overhauled voxel system, I had enough of a foundation that I felt ready to tackle the lighting issue again.
The basic idea behind the lighting system is that each chunk has a 3D 'luminosity' texture. The chunk fragment shader samples this texture to calculate how bright a pixel should be. The luminosity texture may be more or less detailed than the chunk itself. For instance, up-close a chunk might have a luminosity texture that assigns 16x16x16 values per block (except not actually that much because that would be like 130mb for a single chunk texture), allowing for highly detailed nice looking lighting. Contrariwise, extremely far-off chunks may be represented in their entirety only by a single value.
In principle this is simple enough. The problem comes with structuring the data performantly to be accessed by and processed on the GPU. This is what I have spent the past few weeks working on.
The hardest part has been finding a way to performantly represent the entire world state on the GPU since, unlike the previous shitty system I had made, for this system a point in one chunk must be able to be influenced by a voxel in another chunk.
This problem was made slightly easier to solve due to the new voxel system. Chunks are arranged in such away that they are effectively created within a fixed grid around the player. Each chunk exists in an array with an index that can be used to calculate its position relative to the player. Using this, a fixed-size array and 3D texture can be created that will be guaranteed to encompass the entire world around the viewpoint based on a given chunk view distance. Then, whenever a chunk is initiallized or modified, a section of the array is updated. Finally, every frame, if that array has been updated it is applied to the 3D texture which can be used by the GPU. I somewhat expected this to be catastrophic for performance, since whenever the player moves to another chunk the entire world 'shifts' around them which would in turn update the entire texture, however fortunately it proved to be pretty much fine; copying data from one array to a different array is not that expensive, the expensive operation is actually applying the changes to the texture, but that is only ever done maximum once per frame, no matter how much changes.
This fixed-around-the-viewpoint chunk system also means that there will only ever be a fixed number of luminosity textures at each resolution. This has been a massive performance saver, as by using an object pooling system it is guaranteed that there will be an available texture for each chunk that can just be reset (a relatively inexpensive operation) rather than creating an entirely new texture (which caused very noticable framedrops when generating new chunks).
With that, at last, I think you are up-to-date. Thank you for reading! I hope to see you soon!
peterkirkcaldy@gmail.com