Today I have some things to tell you that are technical mumbo-jumbo-ey. This one is really juicy and I promise I'm giving away all my secrets, so ignore at your own peril!
As programmers, we are used to dealing with nitty gritty details. For instance, if you show "openFile" and "OpenFile" to many programmers they will interpret "openFile" as a verb (i.e., "open the file") and "OpenFile" as a noun (i.e., "the open file"). A silly and sort-of wrong example, but it shows how tiny details change meaning for a programmer.
@p
My programmer brain spends a lot of time wrapping itself around such minutae that it starts to seem normal, which of course it isn't. The danger is that I will lose perspective and see only tiny details.
@p
This is why programmers sometimes do not finish making games. We spend all our time on bump mapping, when we should just have everything flat-shaded!
One thing I didn't appreciate until recently is the difference between a parameter and a variable. We often think of functions in terms of arguments. Naeively, to draw an alien to the screen we could do:
$bitmapData = readBitmap ("alien.png");
@p
drawBitmap ($bitmapData, 5, 10);
It probably makes sense, however, to have a Sprite class that captures some of the details:
$bitmapData = readBitmap ("alien.png");
@p
$alien = new Sprite ($bitmapData);
Let's loosely define a parameter as something which we do not change that often, and a variable as somthing that does. In this example, we have parameterized our bitmap data; the alien's (x, y) position might change every frame, but his graphic does not.
As programmers, we tend to see everything in terms of arguments. Ha, ha! That is actually a pretty good pun! Anyways.
What I mean is that as seers-of-detail we take the above and realize that "all we've done" is reorganize things. $bitmapData is still being passed as an argument to $alien->draw (5, 10), it's just implicit:
$bitmapData = readBitmap ("alien.png");
@p
$alien = new Sprite ($bitmapData);
@p
Sprite::draw ($alien, 5, 10);
It's important for a programmer to understand the above code, but we lose the big picture if we think it means that there is no difference between parameters and variables. Worse, I don't think we can draw a line exactly between them-- something else that programmers relish.
@p
My point is there is a degree of variable-ness and parameter-ness to the inputs or context of a program, class, or function. Programming, in part, is carving up the parameter space cleverly into smaller and smaller chunks until we have a model that does what we want. In the broadest possible sense, the most "parametery" parameters are like the laws of physics (and aren'tprogrammers more willing than most to accept that these are somehow "reset" at the big bang/big crunch?)
As every game programmer knows, particles make things awesome (just ask Rob Fearson). Writing a particle system is normally an issue of setting certain parameters: the rate of particle generation, the size, the rate that their size changes, the initial velocity, the acceleration due to gravity, the rate of "spread", controls on the initial position or size when they are first emitted, their color, the rate of change of their color, the rate of change of their alpha, and so on. A heckuvalot.
@p
All of these we normally think of as parameters. We might have a few that are realtime adjustable, for instance the "origin" might be a variable so that the particles can track a moving object, or perhaps even the overall rate of emission-- then a spaceship can emit more fire as it moves faster.
@p
As a real-world example, the particle system in The Real Texas has 28 (or, if you count a vector as 3 parameters instead of 1) 46 parameters. Only the "origin" that the particles are emitted from is a variable.
@p
But the trouble with particle systems is tuning. With so many possibilities, it can take forever to get them looking proper! Most combinations of arguments are useless. But many combinations of arguments give great and varied effects, too! You can create very nice effects if you can get the arguments just so.
@p
We could put all these into an interactive simulation with sliders and so on to adjust, and that would give us some artistic control. I think this is a good solution if you can afford it (or use a game development environment that already has such a thing for you.) But maybe you can not/do not have such creature comforts!
At run-time, these parameters do not change and so are truly parameters. But at tuning-time, they do change, and a lot. So when we are adding a frost effect for the Cloak of Ice, we should think of these parameters as variables. Tuning is hard because there are so many variables!
@p
This is important: when viewed at from run-time, they are all parameters because none change. But viewed at from tuning-time, they are all variables because they all change. It's an important conceptual leap to see the development process as part of the program.
@p
Anyhow, let's reduce them.
One strategy is coupling. To couple two variables, we recognize a relationship between them. Suppose we have two variables, emitAreaRadius which describes how large of an area to emit from and emitRate which describes how many particles-per-second to emit. We can rearrange these to be emitAreaRadius and emitDensity, and then just calculate:
emitRate = emitAreaRadius * emitDensity.
At first glance, it may not appear that we have the number of variables. In practice, however, we did, because at tuning-time we are going to fix one, for example size, and adjust the other. We have made one of these variables more parameter-like at tuning-time.
Another strategy is grouping. Suppose we have three tuning-time variables that control the color. One might be alpha fade rate, another one initial color, and another one describing a rate of desaturation (so that a bright orange flame particle turns into grey ash.) What we can do is group these together into a single tuning-time variable, colorType. When we set colorType, we are going to automatically set all of these tuning-time variables accordingly. This is helpful because we might want to make larger or smaller fires.
This is really just a variation on Trix 2. When adding a particle effect to a jet engine, we might specify all 46 tuning-time variables as part of that object. But a better solution would be to create a super group containing all these tuning-time variables together, and call it for instance "jetEngineFire". Then we just create a jet engine and set it to "jetEngineFire", and can re-use this for other objects.
I use this same approach everywhere in designing assets in my games. For instance, a 3D model can be thought of as having a thousand design-time variables (every vertex, together with texture and color coordinates) or just a few (thickness, texture type, height). Clearly, at design-time the second is preferable. If you are into that kind of thing, this is really just another way of looking at procedural generation.
@p
Hope this helps you! As a final bit of advice, I'd suggest to not over-design or look for a perfect parameterization of some function with many variables, but just cut things down to managable complexity and then run with it. Part of throwing out detail is that there is no holy grail, no perfect way to make the cut. At the same time, as you create more and more managable models you are going to see better ways to describe things.
@p
Good luck!
2010-11-11