please release me

Aside from the troubles I’ve been having with shader attributes, I’ve also had a lot of issues with generating releases from my WebGL projects. Typically, they consist of a handful of Javascript files, HTML and CSS documents for the UI, a subdirectory for any binary resources like images, a GLSL file containing the shader code, and an index.php to tie them all together. I like having a separate files to edit instead of trying to deal with one big document with all the markup and code, so I sprinkle the index.php with include directives pointing to the other files.

However, the release version—the one I put out here on the web—should consist of as few files as possible. That way, we minimize the number of round trips the browser has to make to the server, and reduce the total load on the sever. It’s possible to do this by hand, and that’s been my solution for some months now: paste the actual files over the PHP includes, concatenate and minimize the Javascript, and so on.

A few days ago, I wrote a tool to automate releases. It’s JS/PHP based, and I had hoped it would become a turnkey solution. Instead, it’s a bit of a turkey.

Given the URL of the project, the release tool loads it into an iframe. Since this is going through the server, all the PHP includes are replaced with the actual files. That’s a good start. I extract the project DOM, concatenate all the scripts and send the result to a closure compiler to minimize it. Again, great stuff, and maybe if I’d stopped there, I might not be tearing out what’s left of my hair.

But no, I had to be lazy. Why can’t it edit the index.php for me? Why can’t it swap all the script tags out and replace them with a single reference to the minimized script?

Well, it can, and it does. The problem is, that’s not all it does. As a consequence of the document existing in the DOM, we lose stuff. The , for example, sits outside the DOM and isn’t represented within it, so that gets lost when we write the file back out. Markup inside the tag is transformed into a hash of special HTML characters. I’ve noticed a few other weird substitutions that I can’t account for.

It’s especially frustrating because it’s ninety-nine percent there but that remaining one percent is so worrisome. I spent most of the afternoon trying to track down mistakes I thought I’d been making when the fact was, they’d been manufactured by my very own release tool.

I haven’t given up, even if I have to scale back its responsibilities. I will be looking into a regex-based substitute, forgoing the DOM completely. If I come up with a release tool that covers that remaining one percent, I’ll go ahead and release it.

broken shards

I’ve discovered that Shard isn’t working everywhere. It seems to be a driver problem, and is possibly related to how different video drivers handle interlaced vertex data. (I have other projects in development showing the same problem.) I’ll be working on it this weekend and see where that gets me.

UPDATE: Looks like the problem’s higher-up than that. I’ve misunderstood how WebGL matches attribute locations in the shader to the actual vertex data. Problem should be fixed soon.

UPDATE2: Turns out that it was all my fault. Somewhere back there, I removed some Foam code that I thought was superfluous, but I’m now certain it was responsible for matching an attribute variable in the shader with its index into the mesh. This was causing weird polygons to appear, because WebGL simply couldn’t tell what was position data and what wasn’t. I have created a new model that leaves no room for error. All is well.

shard

I’ve written a simple WebGL project called Shard. It came out of some tinkering I was doing with 2D textures. I made a few interesting patterns by running aDrunkard’s Walk and rotating the resulting path around its own starting point. When I saw the results, I thought hey, why not try this in 3D?

Why not, indeed. Enjoy.

some semblance of sanity

In the last post, I explained some of what went wrong with Fissure. I’m writing these posts not to pretend that I know how to write a good game, but to explain to myself where, and how, I’ve failed to do so. It’s also good practice for when I have some actually useful information to relate.

After its disastrous first outing, it took me a long time to come back to Fissure. I’d considered just forgetting about it and going on to the next one. But we have to correct our mistakes if we want to learn all we can from them.

In the first half, I mentioned that I’d spent a lot of time practicing flying my capsule to get used to the control scheme I’d adopted. That should have been a big red warning flag to me. Yes, there’s usually a learning curve to a new game. But context matters.

Recently, I bought The Witcher 2 and decided I’d play through the tutorial, just to get the feel of the controls. As some reviews will tell you, this is probably the worst thing to do if you want to learn how to play the game, because the tutorial throws every single combat and magical move the character can execute at you in quick succession. If you can’t figure out how to use one, you can’t progress through the tutorial. I almost gave up but I did pay for the fucking thing, so I figured I’d derive some entertainment from it. And it turns out the actual gameleads you through combat and so on at a reasonable pace.

I was willing to give The Witcher 2 another chance was because I’d paid for it. If I clicked on someone’s browser game out of idle curiosity, and found it painful to control, I would be clicking elsewhere within seconds. Easy come, easy go. If the people that played Fissure had had to pay for it (haw!), maybe they’d have stuck it out like I did and learned to fly it. But that’s hardly an option.

So: fix the controls.

I’ve since noticed that many WebGL developers handle rotation by click-and-drag with the mouse. This is a natural extension to the way it’s handled in most PC games. In the browser, you don’t have access to the raw mouse position deltas, so you’re forced to use click-and-drag instead. I didn’t care for this, but I’ve subsequently gotten used to it. I threw out the arrow keys and replaced them with click-and-drag. This provides a greater degree of control, and ease of familiarity for PC gamers.

Players commented that the controls seemed sluggish and unresponsive, so I’ve removed the gradual increase in thrust and replaced it with constant acceleration. Since I had already tossed out the requirement to ease up on a piece of salvage, players had no need for fine control.

I found that these two changes actually made the game more fun for me. Though I haven’t sprung it on anyone else yet, I’ll follow up in time to check reactions.

control freaking

Games should be frustrating.

It’s not a word we tend to associate with our favorite games. The word we usually choose is challenging, but they’re similiar enough concepts, except one is considered a good thing and the other not. No matter how motivated, no job seeker is ever looking for a bigger frustration, and no lover regards a perpetually limp dick as a challenge. But the purpose of a game is to put obstacles between you and your goal—to frustrate you from your goal, in other words. If it does this well, it’s a challenging game.

In Fissure, you’re supposed to travel around in a cave and locate salvage. You’re inside a small moon, and we assume that you’re deep enough that gravity isn’t a factor. (This effect is called the Shell theorem.) Effectively, the only force acting on your mass is your own thrusters. I had to think up a control scheme to operate a capsule moving in free space.

Now, games always make tradeoffs between accuracy and ease. Guns don’t jam, greasy food gives you health instead of a raging case of the shits, and no one ever slips on a wet sidewalk. Picking the right degree of realism means striking a balance between challenge and frustration. If you can make a game out of repairing a jammed pistol, you add a level of realism and a new degree of challenge.

With Fissure, I had to strike that balance as well. I wanted to make motion part of the challenge—a game mechanic in its own right. I started out with a completely realistic model, applying Newton’s Laws of Motion.

If you want to rotate a space capsule, you can’t just put a foot down to push. You have to generate thrust at a right angle to the axis of rotation. More thrust, or the same thrust applied for a longer time, means a faster rotation. If you want to stopturning, you have to generate a thrust in the opposite direction, and wait until your angular velocity is zero.

Which it won’t be, I promise. There will always be some fraction of momentum left over, and if you try to correct for it, you’ll overcompensate and go spinning the other way around, and have to correct for that, and so on. I figured this would become annoying in very short order, and discarded that model. However, I still wanted Newton somewhere in the game!

The model I settled on allowed simple (and physically unrealistic) rotation via the arrow keys. Push a key, you turn, release the key, you stop. (You’d have to be blowing a serious amount of reaction mass to get an instantaneous change in velocity. That’s why it’s physically unrealistic.) Okay, I can live with that for the sake of the player. For linear motion, however, I kept Newton around. Push WSA or D to activate a thruster. Hold the key down to keep that thruster firing, and you’ll keep accelerating—until you hit the cave wall. The collision is inelastic: energy is absorbed by the cave wall, and by your shields.

The only thing I didn’t like about this scheme is that it didn’t give me fine control. I wanted the player to ease up to a chunk of salvage and press a button to pull it in for processing. So I made the thrusters start with a small acceleration, then gradually build up to a maximum thrust. At some point, I tossed out the requirement to press a button to process the salvage, because I didn’t see the point of introducing another control button for the task. Just as players in other games can run over health packs or ammo, I let the player crash into salvage to process it.

I practiced with this control scheme until I could fly the capsule blindfolded, then I wrote up the rest of the game and showed it to some people. The reaction?

The capsule was impossible to control. Seriously. No one liked it. I admit, I wasn’t expecting that. Hadn’t I compromised accuracy for fun? Hadn’t I created achallenge?

Not enough of one, apparently. It was still too frustrating. In the next post, I’ll talk about what went wrong and how I’ve tried to fix it.

cut and paste your way to self-awareness

I was reading this rant about the problems involved with copying and pasting bits of code from one project to another—it’s a vector for bloat, and coding errors, and just plain non-comprehension of what code is actually supposed to do—and something odd occurred to me.

It’s becoming more and more evident that horizontal gene transfer played a role in the evolution of life on this planet, even that of higher life forms. Now, cut-and-paste is an inelegant metaphor for HGT, but the idea struck me as amusing: we’re the product of billions of years of genomic cut-and-paste.

Skynet may come to pass, but not by design. It will arise from some POS system that’s been worked over by one too many teams of code monkeys pasting bits of other systems into it.

infinity is boring

In the last post I talked about how I created the cave in Fissure, and referred to it as an “infinite sandwich”, because it consists of two layers that extend as far as the real number system will take them. Fantastic, isn’t it? Who wouldn’t want an infinite space to play in?

The developer who has to fill it, for one.

I knew from the start that I wanted to set Fissure in a cave. (The title is kind of a giveaway.) Once I had the setting, I had to figure out what I wanted to do in it, and that’s when the problems started. An early demo featured a swarm of glowing spheres boiling out of the depths to attack the player. I toyed with that for a week and put it away, mostly because it didn’t suit my approach to gaming.

See, I like stories in games. I’m aware there’s some difference of opinion among gamers on that topic. I have nothing against non-story games, and how a game plays is often more essential than its story to get me into the moment. But if there’s no story at all, I always feel like something’s missing. I need a reason. So it’s natural that I’d want to write a game with a story.

So Fissure’s gameplay had to be story-driven. I tossed together a basic scenario. I don’t see many games that let you fly around freely in space, so I wanted that element. How to make it work with a cave? Okay, how about a cave in deep space? Good. What are you doing there? Battling monsters? Why? Are you a professional monster-fighter in deep space? What are the hours like? Do you get insurance?

I try hard not to be such a dedicated anal-retentive in my personal life. But in this game, I wanted real-world concerns to drive the story. I had to concoct something that made sense, albiet in a futuristic sci-fi world.

I came up with Sarah Singham, deep-space salvage operator, and Fissure Base, which exploded. Why? Well, that’s part of the story. Maybe that is the story. Once I had that, I returned to the project. As it was my first game, I wanted to keep the gameplay as simple as possible: fly around and collect salvage to unlock the story. Finishing the thing was more important than making it shine.

As I wrote the gameplay code, infinity kept looking over my shoulder.

It is possible to tell a story in an infinite universe. Writers do it all the time. All you have to do is draw a boundary around the story. Everything outside this line isn’t part of my story, and everything inside it is. Trouble is, every boundary I created felt artificial.

I created a wall of rock around the action, then wondered how the hell Sarah got into the cave in the first place. A teleport? If she’s got a teleport, why the hell does she have to physically go to each bit of salvage? Why can’t she just beam the stuff aboard?

I removed the wall of rock.

Inspired by Elder Scrolls: Oblivion, I tried a soft boundary—a virtual wall. Travel outside the action, and Sarah would remark, I’m going too far outside pickup range. I’d better turn back. I tested this on its own, then with a hard boundary, where you couldn’t actually travel outside the action and would just crash into empty space. Neither one really worked for me.

In the end, I went with the softest boundary of all. If you travel too far outside the action, then nothing will happen to you. Your EM dectector will tell you where you need to go. It’s your choice to go there, and it’s your choice to come back to where the action is. I suspect most players will choose to come back.

Infinity is fun to contemplate, but it’s fucking boring to play in.

the infinite sandwich

My game Fissure takes place inside a cave, or at least that’s what I’d have you believe. It’s actually taking place inside a sandwich. An infinite sandwich. Imagine how much mustard was involved.

Fissure was my first foray into WebGL. I’d played around with OpenGL in C++ for a couple of years—nothing serious, just enough to accumulate a few useful routines and techniques—and when I discovered WebGL it didn’t take long to port everything I knew into JavaScript. Like many 3D hobbyists, I toyed with heightmaps and Perlin noise, and cobbled together a Noise2D object to create landscapes to explore. This object provides a get(x, y) method that returns a height value based on interpolation between adjacent random numbers. The random numbers are rolled up at object creation time. Here’s the relevant code from my Foam library.

FOAM.Noise2D = function(seed, ampl, xsz, xper, ysz, yper) {
	var x, xl;

	this.xSize = xsz;
	this.ySize = ysz || xsz;
	this.xPeriod = xper;
	this.yPeriod = yper || xper;
	this.amplitude = ampl;
	this.prng = new FOAM.Prng(seed);
	this.map = new Float32Array(this.xSize * this.ySize);

	for (x = 0, xl = this.map.length; x < xl; x++)
		this.map[x] = this.prng.get();
};
FOAM.Noise2D.prototype = {

	get: function(x, y) {
		var xf = this.xPeriod * Math.abs(x);
		var xi = Math.floor(xf);
		var mux = xf - xi;

		var yf = this.yPeriod * Math.abs(y);
		var yi = Math.floor(yf);
		var muy = yf - yi;

		var xi0 = xi % this.xSize;
		var yi0 = yi % this.ySize;
		var xi1 = (xi + 1) % this.xSize;
		var yi1 = (yi + 1) % this.ySize;

		var v1, v2, v3, v4;
		var i1, i2;

		v1 = this.map[xi0 + yi0 * this.xSize];
		v2 = this.map[xi0 + yi1 * this.xSize];
		i1 = FOAM.interpolate(v1, v2, muy);

		v3 = this.map[xi1 + yi0 * this.xSize];
		v4 = this.map[xi1 + yi1 * this.ySize];
		i2 = FOAM.interpolate(v3, v4, muy);

		return this.amplitude * FOAM.interpolate(i1, i2, mux);
	}
};

When I decided I wanted to set a game in a cave, I knew I’d have to find a clever way to create a realistic cave. I wanted it to look smooth, not blocky, so voxels were out. I’d need to create it as a continuous surface. It had to be a real 3D cave, twisting and turning in every direction. Lastly, it had to support a simple collision detection system.

After a while, I abandoned any pretense at cleverness, and cheated my way into something that I thought looked and worked well enough.

The sandwich model implements a cave using two surfaces, one above, and one below. I modulate the surfaces using three Noise2D objects as heightmaps: upperWall, lowerWall, and commonGap. Now, the function of the first two is obvious. They provide a nice bumpy-smoothness that simulates the rocky outcroppings of a real cave. But the third one, the commonGap, what’s that all about?

Well, commonGap is the secret sauce in this cave sandwich. It’s long period and large amplitude, as opposed to the short period and small amplitude of the other two. As I mentioned earlier, I wanted a twisty-turny cave, and that’s what commonGap provides. It creates large perturbations that are common to both the upper and lower surfaces.

	// arguments: seed, amplitude, source length, period
	var upperWallMap = new FOAM.Noise2D(3939592, 100, 256, 0.01);
	var lowerWallMap = new FOAM.Noise2D(2194828, 100, 256, 0.01);
	var commonGapMap = new FOAM.Noise2D(9147374, 500, 128, 0.002);

	this.upperWallHeight = function(x, z) { 
		return commonGapMap.get(x, z) + upperWallMap.get(x, z) + caveHeight; 
	};

	this.lowerWallHeight = function(x, z) { 
		return commonGapMap.get(x, z) - lowerWallMap.get(x, z); 
	};

The surfaces described by these heightmaps swoop and dive, creating what look like warrens and passages. However, it’s still a sandwich. The surfaces never meet. The illusion is the cheat.

The use of heightmaps also makes collison detection simple. If your player drops below the lower wall height or rises above the upper wall height, you have a collision.

Once I’d worked this out, I was pretty elated. The Noise2D object is addressable throughout the entire real number system, which meant that I’d not only created a cave sandwich, but an infinite one!

Why this wasn’t a good thing was something I had to learn later, and I’ll explain in the next post.

dead blogs, remembered

I’ve had a few blogs. Most died from neglect, though the last one ended because I really felt I’d written all I was going to write. I’m starting a new one mostly because I’ve been playing with WebGL and I want to show off a few creations. I ought to have some sort of home page. Might as well fill it with words.

I’ve written a game called Fissure. It’s available from the sidebar over there.

I’m writing a new game that is tentatively titled Pavo. I’ll post updates on it here, plus anything else I feel like dredging up.