I've been struggling with how to implement scripting in my game engine. I only have a few requirements: It should be intuitive, I don't want to write a custom language, parser and interpreter, and I don't want to use threading. (I'm certain there's a simpler solution; I don't need the hassle of multiple game logic threads.) Here's an example script, in Python (aka pseudocode):
def dramatic_scene(actors):
alice = actors["alice"]
bob = actors["bob"]
alice.walk_to(bob)
if bob.can_see(alice):
bob.say("Hello again!")
else:
alice.say("Excuse me, Bob?")
That epic piece of storytelling poses implementation problems. I can't just evaluate the whole method at once, because walk_to
takes game time. If it returns right away, Alice would start walking up to Bob, and (in the same frame) say hello (or be greeted). But if walk_to
is a blocking call that returns when she reaches Bob, then my game gets stuck, because it's blocking the same thread of execution that would make Alice walk.
I considered making each function enqueue an action -- alice.walk_to(bob)
would push an object onto a queue, which would get popped off after Alice reached Bob, wherever he was. That's more subtly broken: the if
branch is evaluated immediately, so Bob might greet Alice even if his back is turned to her.
How do other engines/people handle scripting without making threads? I'm starting to look in non-game-dev areas, like jQuery animation chains, for ideas. It seems like there should be some good patterns for this sort of problem.
Answer
The way something like Panda does this is with callbacks. Instead of blocking it would be something like
def dramatic_scene(actors):
alice = actors["alice"]
bob = actors["bob"]
def cb():
if bob.can_see(alice):
bob.say("Hello again!")
else:
alice.say("Excuse me, Bob?")
alice.walk_to(bob, cb)
Having an on-complete callback allows you to chain these kinds of events as deeply as you want.
EDIT: JavaScript example since that has better syntax for this style:
function dramatic_scene(actors) {
var alice = actors.alice;
var bob = actors.bob;
alice.walk_to(bob, function() {
if(bob.can_see(alice)) {
bob.say('Hello again!');
} else {
alice.say('Excuse me, Bob?');
}
});
}
No comments:
Post a Comment