Read Chris Crawford on Interactive Storytelling Online
Authors: Chris Crawford
It should be obvious that interactive storytelling software, by whatever means it is accomplished, will be big. A lot of data is required to specify the Actors, story components, Verbs available to Actors, Props, Stages, and so forth. Consequently, development environments for interactive storytelling have to be elaborate affairs, which forces the new requirement in Lesson #38.
Lesson #38
The development environment is just as important as the engine.
In other words, building a powerful engine for interactive storytelling isn’t good enough; to be of any utility, that engine must be accompanied by a powerful development environment. My own experience is that the development environment requires at least twice as much effort as the engine. After all, with an engine, you’re just crunching numbers, but with a development environment, you have to provide a good user interface, which is always a demanding task.
The specifics of a development environment will, of course, be tied to the specifics of the engine it feeds data to, but I can offer some general principles in the following sections.
The most profound decision you can make about your development environment is whether it will include algorithmic capabilities for storybuilders. The simple approach is to permit storybuilders to control only data: numbers,
images, sounds, and so forth. This approach is easier for people to understand and quite simple to implement. You merely present check boxes, radio buttons, scrollbars, and other standard data entry components for your storybuilders. You’ll have a lot of these components, to be sure, but they’re conceptually easy to design and understand.
The next level up is including boolean algorithms, which are simple true-false calculations that most people can understand. They enable storybuilders to include simple if-then decisions in their storyworlds. For example, a storybuilder might want to declare that, if an Actor is a gal, the story goes one way, but if the Actor is a guy, it goes another way. If the Actor is old and frail, a certain Event happens, but if he’s young and strong, another Event happens. And so on.
Be warned, however, that making boolean algorithms available to storybuilders makes your development environment much more complex because you now must include expression-editing capabilities. Storybuilders must be able to assemble any combination of boolean variables and boolean operators. Think of all the boolean variables a storyworld might include: variables that specify an Actor’s gender, a Stage’s accessibility to an Actor, a Prop’s visibility, or whether an Actor has already completed an action. Your storybuilder could well want to put together an expression such as this one:
Pretty messy, huh? If you’re going to permit boolean algorithms, you’ve got to be able to handle the resulting expressions.
But wait—it gets worse! Why should your storybuilder be prevented from entering numerical relationships such as this one:
IF (Love[Actor1 for Actor2] > Love[Actor1 for Actor3]) THEN…
Of course, including this type of expression means you have five new operators to offer (=
,>
,<
,≥
,≤
) as well as all the numeric variables. Lots more work for you. Ugh!
But wait—it gets even worse! The preceding expression asks whether Actor1 loves Actor2 more than Actor3. It’s a fairly obvious basis for a choice such as
“Should I leave Actor3 for Actor2?” But what if you also want to include a little natural inertia in Actor1’s decision? In other words, she’s not going to leave Actor2 for Actor2 if she loves Actor2 just a smidgen more than Actor3. She needs to love Actor2 a
lot
more than Actor3 to justify the pain of breaking up with Actor3. So now the formula looks like this:
IF (Love[Actor1 for Actor2] > Love[Actor1 for Actor3] + 10) THEN…
Oops. Now you’ve gotten yourself into arithmetic. And the slippery slope has no natural stopping point; if you permit a simple arithmetic operation such as + 10, how can you deny one like this:
And there you are, deep in the fires of Math Hell.
I suppose you could make some sort of arbitrary constraint, such as limiting storybuilders to the four basic arithmetic operators (+, -,×, ÷), but you can be sure some storybuilders will chafe at the arbitrariness of your restriction. “Just give me square roots; that’s all I need,” they’ll plead. “Just one more division of troops and we’ll finish off those Viet Cong, Mr. President.”
In for a penny, in for a pound. If you’re going to include full arithmetic expressions, why not go whole hog and permit arithmetic modifications such as this one:
This expression means that if Actor2 slaps Actor1, then Actor1’s love for Actor2 will be diminished by 27.
Or how about this obviously useful bit of code:
IF (Actor2 murders brother of Actor1) THEN {
i = 0;
WeFoundAVictim = FALSE;
WHILE ((i < ActorCount) AND (WeFoundAVictim)) {
IF (Actor#i is kin of Actor2) THEN {
WeFoundAVictim = TRUE;
Victim = i;
}
increment i;
}
IF (WeFoundAVictim) THEN {
Plot dark and bloody revenge
}
}
This little code snippet might be hard for nonprogrammers to read, but basically all it does is sweep through the list of Actors, looking for one who is kin to the murderer, and then selecting that kin Actor for dark and bloody revenge. Obviously this capability is useful, but it takes you beyond Math Hell and into the even lower levels of Programming Hell. How deep do you want to go, Dante?
I toiled with these problems for years, and did come up with a few ideas.
First, it’s possible to steer clear of Programming Hell with a scheme using
selection loops
that take algorithmic arguments. Here’s how it works: First you create a standardized function calledPickBestActor
. It has the loop buried inside it, but the storybuilder never knows. From the storybuilder’s point of view, it’s just a function that picks the Actor who best fits some specification. That specification is an arithmetic expression that the storybuilder hands to the function as an argument, like so:
MyChampion = PickBestActor(Strength[])
It says “My champion will be the Actor with the highest value ofStrength
.” You can extend the idea as follows to say “The gal picks the guy with the best overall combination of good looks and money”:
ThePerfectHusband = PickBestActor(GoodLooks[] + Wealth[])
In practice, I have found it necessary to include both a boolean and a numeric argument to the function:
ThePerfectHusband = PickBestActor(GoodLooks[] + Wealth[], IsNotMarried)
The gal picks the guy with the best overall combination of good looks and money
and
who is not already married.
For this function to work, you’ll need to supply versions of it for everything an Actor might want to choose, as in these examples:
This scheme relieves the storybuilder of the cognitive load of writing selection loops; in practice, I have found little need for other kinds of loops.
Even with this scheme in place, however, I have found that math scares away most storybuilders. Most seem capable of handling boolean expressions, but balk at algebraic formulae. This fear is particularly crippling with respect to inclination formulae, which are important components of many interactive storytelling technologies. They specify the degree to which an Actor is inclined to take a particular course of action. Suppose, for example, that an Actor is faced with danger and must choose between fight or flight. The inclination formulae might read like so:
Inclination[Fight] = Courage[] – Prudence[]
Inclination[Flight] = Prudence[] – Courage[]
This kind of math is too difficult for most storybuilders to use on a regular basis. More than any other factor, math fear is what prevented people from using the
Erasmatron. There is, however, a way to ameliorate the problem: Constrain the form of the formula and allow users to specify just two factors to control it.
Figure 17.1
shows how I do it in the Erasmatron.