defignition
defignition
January 12, 2014

The physical universe is a crystalline wonder; a rigid lattice of the natural constants scribbled down on a physics cheat sheet. Gravity on the earth's surface is always going to be 9.80665m/s2. Maybe 9.9m/s2 in the winter; we all pack on a little holiday weight.

A video game's universe is altogether more squidgy; constants are only constant until they're inconvenient.

It can take a lot of fiddling to get these constant definitions just right. You're going to waste a lot of time if you have to quit out of the game, hop back to the text editor, nudge a value, maybe recompile, launch the game, and get back to wherever you were just to find out that 2 should've been a 3.

Interactive development is always, always, always better. It's the difference between reading about snowboarding and actually throwing yourself down a hill. A book's never going to teach you how much time you're gunna spend falling down.

Ideally, we have a tool for tweaking those values while the game is running. Let me drop some hippie wisdom here: this isn't a science; we need to get a feel for what those definitions mean.

Turns out, JavaScript makes this pretty easy. Dang, alright.

look out for the lookup

Any time you're thinking about runtime-adjustable values, you probably want some sort of global key-value table. Instead of hardcoding values wherever, you stuff 'em in the table. This makes them easy to access and means you don't have to go hunting through the entire codebase to figure out where these values are living.

In Jinn, these definitions are attached to the global app object:

app = {
	definitions: {}

	define: (definitions) ->
		for k, v of definitions
			@definitions[k] = v
}

The definitions object is just a plain old JavaScript object. We can define things by attaching properties to that object. define takes a bunch of key/values (another JavaScript object) and sticks 'em on the definitions. Super simple.

Anyway, we can then define a bunch of things:

app.define
	PLAYER_GRAB_OFFSET:		30
	PLAYER_GRAVITY:			40
	NORMAL_REFUEL_RATE:		40
	PLAYER_SPEED:			300
	FUEL_CONSUMPTION_RATE:	100
	MAX_FLY_SPEED:			600
	FLY_ACCELERATION:		400
	MAX_FUEL:				20
	PLAYER_JUMP:			550

And so now, we can reference defined values at runtime:

defs = app.definitions
@player.vel.y += defs.PLAYER_GRAVITY

Now, that's all fine or whatever, but the benefit isn't immediately obvious. Sure, things are maybe organized a little better since definitions aren't just floating around, but really, big whoop.

Things get a little cooler when you realize that we can build things on top of the definitions table. Things like, well, our tweaker.

tweak it till you make it

So, we've got our definitions - a bunch of key/values in the form of properties on a JavaScript object. There's two important things here:
  • JavaScript objects like to be inspected, so much so that you can dynamically iterate over their properties.
  • We're swimming in a sea of HTML and CSS.

It should be pretty obvious how our tweaker is going to work. We'll just build an HTML interface that lets us poke and prod at our definitions.

For every key/value pair on the definitions object, we'll add a textfield to the tweaker. We'll hook that textfield up such that when it's contents change, the definition is, uh, redefined. So, for each definition, we get something like this:

valueEl = $ "<input type=\"text\" value=\"#{value}\">"
valueEl.change ->
	value = app.definitions[name].constructor(
		valueEl.val()
	)
	app.definitions[name] = value

Now, there's something cool happening here. We don't actually know what type the definition values are - they could be numbers, they could be strings. However, in JavaScript, we can easily get something's constructor. If it's a number or a string, that constructor'll be pretty good about coercing any value into the right type:

1.constructor("2") # 2 - a number!
"1".constructor(2) # "2" - a string!

So, without even working for it, we get a handy means of converting an HTML element's value to the type of the existing definition. That's pretty legit.

Anyway, at this point, it's pretty much child's play to iterate over every definition and add it to the tweaker:

el =
	$("<div id=#{ID}>")
		.draggable()

for name, value of app.definitions
	do (name, value) ->
		definitionEl =
			$("<div class=\"definition\">")
				.text("#{name}: ")

		valueEl =
			$ "<input type=\"text\" value=\"#{value}\">"

		valueEl.change ->
			value = app.definitions[name].constructor valueEl.val()
			app.definitions[name] = value

		definitionEl.append valueEl
		el.append definitionEl

$('body').append el

That's, like, twenty lines of code. With it, we get this cool little runtime editor:

tweaker

Now we can tweak to our hearts' content. JavaScript's support for dynamic goings-on as well as its ability to manipulate the DOM lets us quickly and easily build a tool integrated with the heart of the game engine. That's really rad.