I had the most eventful weekend in a long time!
Unfortunately, majority of the things happening over the weekend were not development-related.
Fortunately, I still had a lot things done over the week itself. So there is a new build featuring new wall types, and a “level selection” menu (still rough around the edges though…). And a sound. Singular… yet. Others will have to wait.
Unfortunately I am unable to upload the build just yet – I currently don’t have access to the machine it is on, but I really hope to change this paragraph with an actual download link sometime today. So stay tuned!
This also means there are going to be no pictures in this post. Though I hope this will only inspire you to download the build to see for yourself!
But what I am going to tell you in this post is a share a piece of thought that works behind the scenes in this game.
The “Maze” you are exploring in this game consists of “tiles”. A pretty common concept for a procedural generated games, but usually is is used in some “rogue-like”s. And this either means the graphics fidelity being pretty low (often even no graphics at all with everything being represented by characters. Not always colored), not that I have anything against such an artistic stile, but it didn’t fit the game I am writing.
And even having graphics, the actual rogue-likes usually try to enhance the visibility of grid, as this allows for more precise tactical decisions. and again – this is not something that would fit my game.
In Maze Crawler immersion into the dungeon is pretty important, so I really didn’t want the tile edges to stand out and that bring some rather non-trivial challenges to programming, as you might imagine.
The earliest prototype (being produced within 48 hour of GameJam) paid little attention to this issue. All the tiles were represented by the same prefab, consisting of a 5×5 “floor” and 4 “walls” that could be switched on or off based in existence of a neighboring tile. And to hide the textures on the walls not matching together, all the corners had pillars placed in them (Which was soon reduced to only corners with walls having pillars, as having them in every corner of such mall tiles, resulted in rather disorienting effect of not being able to grasp the shape of the room quickly… A good effect to use once or twice, but not in every room definitely!). And the hastily-composed normal textures on floor didn’t tile all that well (I haven’t discovered Blenders sculpt mode tiling option at that time yet…) so the edges on the floor tile were all too visible.
Using a texture that tiles properly did fix some of those issues, but (as it often happens) fixing one problem only serves to amplify the existence of others.
While properly tiled texture could fix the floor, and eliminate the need to put semi-columns on flat walls and with some clever texture tuning even eliminate it on the corners, with tiles being only 5 by 5, this brought a lot of repetition patterns into view. Sure, there are ways to negate those issues, like scaling texture, and distorting UVs a bit, but those work mostly for floors and didn’t work as well for walls (especially distortion bit, when combined with need to carefully craft the texture with corners in mind). So I decided to pursue a different approach!
So to properly tile the texture must have similar pattern on opposing edges. But that doesn’t put any constraints on what is in the middle of the texture. So what if we have several texture versions, all with similar borders, but different contents. So of those different textures any two could be placed together, and “tile” correctly with no visible seam between them. Now if we randomize which texture is used, there will be way less repeatable patterns. And having a relatively small tile size actually becomes an advantage here, as more often transits from one texture to another means that there is more chance that an accidental pattern would be broken!
With this in mind it is now a good idea to think how to implement this randomization. The first instinct might be to have one texture be one material, so when piles are dropped, different materials can be assigned to different renderers. But this obviously butchers the DrawCount. Especially with intent of many different textures being in same view, this mans that we will be showing a lot of Draw Calls down our GPU.
So to save on those a standard way would be to use a texture atlas, rather than a set of independent textures. Meaning all different textures are collected into one. Like you can combine 4 or 9 or 16 square textures together (2×2, 3×3 or 4×4) and still get a square. And as a free bonus – if you create those textures in one image, it is easier to make them tile together, since you are effectively trying out a lot of combinations as you make them.
But having a texture atlas is not that helpful, if all your meshes’ UVs target the same spots on the Atlas. So if you have a 3×3 tile atlas, you obviously need 9 versions of the Mesh with UVs being translated to one of 9 subtextures.
The process for one mesh is not that hard actually. Just add a vector to all UVs. But having to repeat it 9 times is… tedious. And having to repeat it 9 times is tedious squared. And even a thought about trying 4×4 for some elements makes you want to admit that 2×2 is good enough.
But once I thought about it for some time, I realized, that all this time I was dredging through manually updating the UVs, I could actually shove all this task on the CPU. After all it IS just a simple translation (and scaling, if the original Mesh used 0-1 UV ranges rather than one of subtextures to begin with, which actually helps to swap a texture atlas for a different one, with different tiling, with same meshes.
I hope this train of thought was interesting, and maybe even helpful to someone.
Please let me know if you have any questions of comments!