Re: Game object class design problem



Lorenzo Gatti wrote:

More or less the same. The only two really different types that have
come up in this thread are Things and Places (Things can own or
provide Places for other Things, but cannot be places themselves);
other distinctions such as Item vs Creature are "intuitive" but might
not be entirely correct (there are overlaps such as using a very small
dragon like a flamethrower or scheduling turns and behaviour for a
portable clockwork device).

I'm thinking you left out actions. I'm treating them as a third
fundamental type, although I know many games leave them implicit in
flow-of-control. Treating them as a type buys me a lot of flexibility
in scheduling, modifying, and rescheduling actions.

My current architecture has at its root floortiles, actors and actions.
A floortile is a place; maps are composed of them. Actors are things;
Everything that can be *on* a floortile - monsters, players, weapons,
doors, traps, ammo, magic items, etc, is an actor. Actions are changes
that affect things or places (or relationships between them). Moving,
attacking, deciding what to do next, healing, opening, closing, etc, are
all actions. They're represented as closures - records that have a function
pointer and a set of arguments.

So there's a map for managing places, an actor table for managing actors,
and a schedule for managing actions. Many actions (not all) place one or
more additional actions into the schedule, and the game proceeds by
repeating a tight loop where it gets the next event from the schedule and
executes it.

Actors have dynamic sets of attributes, some of which are triggers. A
trigger specifies an action and an actor's role within that action. The
roles are subject, object, agent, agency, timingref; For an ATTACKRWA
action (attack with ranged weapon and ammo) with a bow and a greek-fire
arrow, these roles are, in order, the attacker, target, bow, arrow, and a
null-actor reference. The timingref indicates whose speed determines the
timing of this action. The null-actor reference means that any further
damage events (in this case from the burning of the pitch on the arrow)
happens on absolute (game) time rather than at the speed of any particular
actor. Anyway, when a trigger comes up, a closure associated with the
trigger is called. In this case, the arrow has an 'ATTACKRWA-agency'
trigger, so when it is the 'agency' in an ATTACKRWA action, the trigger
closure is called and runs before the general code that does the action.
The trigger closure, when called, can't directly change anything in the
game (because it's not an event closure). But it can and does schedule two
more events: the first sets the target on fire, and the second destroys the
arrow. In OO terms, it's a 'before' method.

Trigger attributes of actors are also used in the same way people using
languages other than C use function overrides: For example PICKNEXTACTION
(the action that happens to an actor when it's his/her turn and s/he must
decide what to do next) is a null action; Actors that make 'turn-based'
actions (the player, monsters, burning fires, dispersing smoke, collapsing
ceilings, thinning air, etc) have 'PICKNEXTACTION-subject' triggers,
pointing to different routines, that schedule their appropriate actions.
So when PICKNEXTACTION is called, and they're in the subject role, those
routines are triggered, and decide what actions to schedule for them. Thus
mice and turtles both get the 'coward but fights if cornered' AI, the
player gets the 'display the dungeon and get an input' AI, most trolls get
the 'kill the player and take his stuff' AI, and Bob Goblin gets
the 'greedy little extortionist' AI.

Of course, I'm doing it all in C, because I like the old-fashioned
hardcore-ness of C and the way I can synthesize my own OO models from
scratch. It's not the easiest or fastest way to do it, but it gives
me a sense of real craftsmanship and may be the most fun.

Bear


.



Relevant Pages