Gas Food Lodging now supports Fullscreen and Pointer Lock! No more dragging and dropping that mouse. Press F at the title prompt to activate the new mode, and see the wonders explode across a slightly larger screen area!
September 2012
make a drunken noise
I like a bit of structured noise. Photoshop (and the GIMP) call it difference clouds, but to me it’s always been drunkwalk, because that’s the algorithm I use to make it. For past games, I wrote a C program to iterate random steps across an array and place the results in an image file, like so.
I’d load that image from the server and hand it off to WebGL as a texture, doing a little Perlinization in the fragment shader to colorize and stretch it. However, what I really wanted was client-side generation. I wanted to make them on the fly and use them for a load of other purposes. Heightmaps, for example. There’s a smoothness to drunkwalk noise that just pulling random numbers out of the air doesn’t get you. You’ve got to add that stuff up.
So I finally added a drunkwalk noise generator to my toolkit.
walk: function (img, seed, reps, blend, c, p0, p1, p2, p3) { var w = img.width; var h = img.height; var il = Math.round(w * h * reps); var rng = this.rng; var dt = img.data; var dnelb = 1 - blend; var x, y, i, j; rng.reseed(seed); x = Math.floor(rng.get(0, w)); y = Math.floor(rng.get(0, h)); for (i = 0; i < il; i++) { j = x + w * y; dt[j] = Math.round(dt[j] * dnelb + c * blend); if (rng.get() < p0) { x++; if (x >= w) { x = 0; } } if (rng.get() < p1) { y++; if (y >= h) { y = 0; } } if (rng.get() < p2) { x--; if (x < 0) { x = w - 1; } } if (rng.get() < p3) { y--; if (y < 0) { y = h - 1; } } } }
To generate a typical chunk of structured noise, you’d pass parameters like this.
walk(tex, seed, 8, 0.02, 255, 0.5, 0.5, 0.5, 0.5);
We assume the tex object resembles a native ImageData object in having height, width, and data properties. However, the data format is a single byte luminance channel (as opposed to the four-byte RGBA format). You can still pass this right into WebGL as a texture, and colorize it in the shader.
You can pass a custom seed, which will generate the same pattern each time, or a zero to select a random pattern. (The rng object is a static RNG handing out numbers from zero to one.)
The reps parameter is the most important. Good patterns require a large number of steps, and the larger the size of the array, the more steps you need. Thus, I specify the number of steps as a multiple of the area.
The blend parameter works like an alpha-blending value, determining how much each step will blend between the intensity present in the channel and the intensity given by the c parameter. In this case, I’m blending between 0 and 255.
The p0-p3 values let you alter the probability that your “drunk” will stumble in one direction or another on each step. Changing the probabilities alters the structure of the resulting image.
Performance isn’t bad, thanks to JIT compilation. I can generate about ten 64×64 images (with a reps value of 8) without noticing any slowdown on a 2GHz AMD64.
You may note that the algorithm enforces boundary conditions in an odd way. If a step takes us off the “side” of the array (i.e., x > width), we resume on the opposite side (x == 0). This creates a natural tiling effect that makes texturing a breeze.
a belated update
So I spent a couple of months alternately writing a new game, and making some improvements to my game toolkit. The improvements took, the game didn’t. That’s okay. I’ve learned a lot.
The most important lesson, in fact, wasn’t technical. As a developer, I’m used to working from a plan, a spec, a target. Even if the target is soft, it’s still there, guiding me. As a writer, on the other hand, I’m used to sitting down and banging out something—Pat stood on the edge of the road, watching for a blue car—and just seeing where it can go.
As a gamemaker, I’ve followed the writer pattern, and not the developer pattern. I say: hey, I’d like to explore a cave. Float in space. Talk to a robot. No plan, just an idea. See where it leads.
For the last couple of months, however, I’ve tried to follow the developer pattern. Didn’t work. The hell with it. Back to the writer pattern.
So, here’s a screenshot from a thing I’ve been banging on this week. Don’t know exactly what it is, or where it’s going. Can’t wait to find out.