Post by H. S. LahmanThese are events but the thing I would push back on is why you need to
"keep track" of them. Normally events are just messages that announce
that somebody did something that somehow changes the state of the
application solution. That message needs to be routed to someone who
cares what happened and has an appropriate response to it. That response
changes the state of the application, a message is issued to announce
it, and someone who cares about it responds, and so on...
So once the event is consumed (received by someone who cares and has an
appropriate response) it essentially ceases to exist.
Does this apply when I have multiple objects interested in the same
event?
For example, if a creature attacks another creature, any other
creatures
who are friends with the target and are within range to see the attack
should get mad at the attacker (or afraid, if the damage done was high
enough). If the creature controlled by the player could have seen the
attack, an appropriate animation should be displayed on the screen and
an
appropriate sound be played.
Post by H. S. LahmanGames usually have some degree of concurrency (e.g., the Physics
subsystem is figuring out current movement while the Rendering subsystem
is throwing stuff on the display for the last movement). Concurrency is
usually handled with asynchronous messaging. Asynchronous messaging is
best managed with object state machines that capture sequencing rules as
transitions. Object state machines come full circle to events and event
queues.
When you say concurrency, you don't mean threads do you? Or would it
matter?
(For the record, this is a single-threaded application that will be
done in
Python.) I also don't quite grasp how state-machines become involved
here.
Post by H. S. LahmanSo your event might persist temporarily on the event queue between the
time it is generated and the time it is consumed. But there it is simply
a message {event ID, <data packet>}. Whoever generates the event knows
how to encode any data packet and whoever receives the event will know
how to decode the data packet. All such dispatching is done based on the
event ID through a state transition table.
Is the state transition table for deciding how to encode/decode a data
packet
or for choosing where to send the event?
Post by H. S. LahmanThe event doesn't do anything; it is just a message. The receiver of the
event does something in response to the condition raised in the event
sender. The event ID tells the receiver which behavior to map to the
event. That behavior will decode the data packet for parametric values.
When I talked about event objects in my first post, I was speaking of
them as
immutable information holders, with the difference between them being
the
information held.
An AI would know how to respond to a creature attacking something, and
the
graphics would know how to animate an attack. The first crucial thing
is
letting the parts know that such a thing happened in the first place.
The
second thing is letting the parts know the specifics they need to know
to do
their response. An AI needs to know what creatures were involved in
an attack
(especially if the creature it controls or one of its friends were the
target)
and how much damage was done (to tell if it is strong enough to deal
with the
attacker). The graphics also needs these details so it knows what
animation
to render and where.
Generating these events would be somewhat easy. A creature would
generate an
event for most of its notable atomic actions, such as attacking or
dying, and
know what information to put into these events. (Remember that I'm
separating
the creatures from the AI/UI. Generally, a Creature can be told to do
things,
and an AI or UI makes decisions/responds to input to figure out what a
Creature should do.)
Post by H. S. LahmanSince that is a matter of private method implementation, one /could/
class Event
{
EventID id;
Buffer* dataPacket; // just contiguous bytes on the heap
}
and let individual senders/receivers encode/decode the buffer. However,
to preserve the developer's sanity in an elaboration environment, you
probably need some more explicit definition of data packet in terms of
types. One way to do that is to subclass Buffer. Another is to make
Buffer an XML string. Yet another is to provide a specification object
whose attributes provide parametric values that drive the encode/decode.
(The category on Invariants and Parametric Polymorphism on my blog
provide some examples of this.)
Whoa. Is Buffer available in Python? ;)
I thought your posts about Invariants on your blog were interesting,
but I
could only follow the Depreciation example. I think there was also an
example
somewhere else in your blog about how to model a tree of Node objects
and
avoiding the checks for null in the case of leaf Nodes. I think the
gist of
it was creating a subclass of Node called Leaf, and also give Node an
attribute value that clients could check instead of checking for
null. Is
that right?
Post by H. S. LahmanThe real issue here is that when a Creature grabs another that changes
the state of the application and other objects need to know that
happened. So the grabbing Creature would send messages to whoever that
is -- the other Creature, the AI, the Physics subsystem, the Rendering
subsystem, etc..
Exactly. You're taking decoupling into account though, right? I
don't
want direct references to the Physics or Rendering systems in Creature
just to
let them know whenever a Creature sits on a whoopie cushion.
Post by H. S. LahmanNote that throwing the Creature is another change in the application
state that is different than grabbing it. That will yield another set of
messages that may or may not go to the same objects (i.e., different
objects may care about throwing than about grabbing).
Yes. Another example would be if I had a door opening. AIs wouldn't
*really*
need to be told directly since they would tell the door opened by
looking at
the map, but a creaking sound should be played by the sound system.
Post by H. S. LahmanNot necessarily. Others would sense the creature using their own sensors,
which might be less inaccurate than the self-feeling, or reverse. (What
irritates me in some RPGs is that when you do something, like stealing a
thing, all NPCs become instantly aware of your action. Why should they?)
Could you explain how these sensors would work/go? With the event
model I've
been wrestling with above an AI would poll the event queue and pick an
action
for its Creature depending on any events it had interest in. The
Creature's
actions would generate more actions to go on the queue. Of course
there has
to be a way of getting rid of old events that everyone has already
seen
before.
As for the thievery example, I'd add a line-of-sight check to
eliminate any
omniscience. ;)
Thinking about Sanford's and Lahman's messages made me think about the
possibility of a concrete Event object that, along with an ID, has a
map of
key/value pairs. The ID number would specify what keys are available.
Event generators would know the ID number and the keys to put into an
event
and what data to associate with each key (this could be made easier
with a
factory of some kind). Event listeners can tell what an event's type
is and
get its information without any downcasting. How does that sound?
P.S. about Lahman's statement about the peer-to-peer collaboration of
object
in an OO system:
Now, I am aware that a lot of your work involved translation and
executable
UML, so I gather you didn't have to worry so much about the stack-
based
execution of so-called 3GL languages. I unfortunately don't have
access to
these technologies, and probably won't ever until there's a "gcc-mda"
command
on most Unix machines. So I'm still going to have to worry about the
order in
which things execute for a while now. ;)