Blog

The Grend Digested ยป posted Thu Jun 3 06:14:22 PM EDT 2021

Many ages ago, in a time long forgotten, I had posted a post which foretold the coming of another, greater blog post. One that would shake the foundations of this blog and usher in a new age of Good Content. This promise brought great hope to the disperate colonies desperate for Good Content, but as the eons went by, rumors began to spread... Perhaps there was indeed no Good Content to be found? Had there ever been Good Content to begin? Worry crept over the lands, afraid that no such content would ever be created...

Until now. Worry not, my friends, for that post is here. :O

So, unlike my last post, I haven't done anything that I had intended to do at the conclusion of the last post. I've gotten a bit sidetracked, but I think the new direction I'm going in is better anyway.

What's new:

New map generation, new project? :O

The big news is that I've decided to put the previous 'landscape' thing on hold... I still have plans for it, but I've decided to work on a 3D roguelike using the wave function collapse library I wrote. This will feature winding mazes with real-time action (not turn-based), clever enemies, complex object and environment interactions, limited persistence between runs, and maybe some environment destruction and crafting. This is essentially a more focused version of what I'd been thinking of doing with my landscape thing, and when I get back to that I think it'll naturally build off this project.

You might notice that I didn't make a ludum dare 48 post, and, well, this was what I was planning to use as my entry, but the scope was (obviously) faaaaar to big. Nonetheless I made good progress integrating the WFC library into my engine that weekend.

Quick peek at the level generation

Cool, you might say, but what's the big deal about this "wave function collapse" thing anyway? Is there more to it than an over-the-top name? In essence, WFC is a limited constraint solver, and using it for map generation like this means you can generate complex random levels with guarantees about the local layout of any particular tile. (The original WFC implementation describes itself as a program that "[...] generates bitmaps that are locally similar to the input bitmap.")

It's particularly useful for generating interesting maps with very small specifications. The above level is generated with only 6 models and about ~100 lines of json. All that needs to be specified is the models, valid rotations, and what neighbors a tile has (and their rotations). Thus, the plan is to leverage this to generate lots of uniquely themed, interesting levels with complex interactions, with the time budget of solo indie dev.

Here's a snippet of what the json input specification looks like, for illustration:

{
   "models" : {
      "floor-tile-empty": "floor-tile-empty.gltf",
      "ext-corner": "ext-corner.gltf",
      "ext-wall": "base-wall.gltf",
      "ext-wall-light": "base-wall-light.gltf",
      "hall-wall": "hall-wall.gltf",
      "ext-hall-corner": "hall-corner.gltf"
   },

   "comment" : "left, up, right, down (0, 1, 2, 3)",

   "tiles" : [
      {
         "name" : "floor-tile-empty",
         "model" : "floor-tile-empty",
         "tags" : ["traversable", "floor"],
         "adjacent" : [
            [0, "floor-tile-empty", -1],
            [1, "floor-tile-empty", -1],
            [2, "floor-tile-empty", -1],
            [3, "floor-tile-empty", -1]
         ],
         "rotations" : [0, 1, 2, 3],
         "weight" : 1
      },

      {
         "name" : "ext-corner",
         "model" : "ext-corner",
         "adjacent" : [
            [0, "ext-wall", 3],
            [3, "ext-wall", 0]
         ],
         "rotations": [0, 1, 2, 3],
         "weight" : 1
      },

      {
         "name" : "ext-wall",
         "model" : "ext-wall",
         "adjacent" : [
            [1, "ext-wall", 0],
            [3, "ext-wall", 0],

            [0, "floor-tile-empty", -1]
         ],
         "rotations": [0, 1, 2, 3],
         "weight" : 1
      },

        ...
   ]
}

Not too bad at all. A seperate "models" dictionary makes the tiling rules easily skinnable, and the spec parser automatically sets adjacency rules for both the declaring rule and the neighbor for all rotations, while checking for inconsistent adjacency rules. (eg, "ext-wall" declares a neighbor "floor-tile-empty", so "floor-tile-empty" gets an "ext-wall" neighbor as well, a small improvement that makes specs a lot easier to write.)

There is one major problem, though: plain WFC only ensures /local/ constraints. If you want to do something like, say, make sure there's a traversable path between the entrance and exit, WFC by itself won't cut it. There's a few options to solve this:

I've decided to go with the last, which is what the "tags" field above is used for. Before generating with WFC, a simplified map is generated with binary space partitioning, a very old-school technique. This map is then used to determine where to place the entrance and exits, and the tiles in the WFC generator are initialized with all of the "traversable" tiles being possible. At the moment, this results in overly roomy rooms, but that should be improved as I add stricter rules.

Animation showing some possible BSP map layouts

And that's where I'm at so far. Next steps include generating a Dijkstra map for tiles and generating doors, puzzles and pickups based on that and the BSP.

Vector textures

Inspired by SDF textures, this aims to have vector images that can with multiple colors. It's not quite as flexible as SDF, more of an experimental thing, but it mostly works and I'll probably end up using it eventually. I'll write a post about it in more detail at some point.

Vector texture off, showing the underlying format and resolution.
Vector texture on, with some janky gradients. (Those can be turned off :P)

Graphics dump

Sponza with all the new graphics features enabled, MSAA, anisotropic filtering, dithering, etc. There's still some aliasing, and the shadows are a bit messed up, but altogether I think it's starting to look pretty good.
Demo of an android build, made a few weeks after my last post. Shading with normals to get that 60fps :P

Fin.

So yup, that's all for now. Hopefully I'll be announcing an alpha of this game soon, so stay tuned for that. :D