Tutorial 7: Event Handlers and User Data Sometimes
it’s nice to be notified when certain events occur. For example, when two particular Solids
collide you may want to play a sound effect, destroy one of the Solids, make
the Solids stick together, etc. OPAL’s
event handlers allow you do catch these events and handle them in some
application-specific way. To use an
event handler you must derive your own class from OPAL’s base event handler
classes. OPAL will then notify your
derived event handlers at the appropriate times. Besides
event handlers, this tutorial also demonstrates “user data” pointers. Simulators, Solids, Joints, Motors, and
Sensors all have void pointers to some user-defined data. This allows OPAL objects to store
references to application-specific objects.
OPAL does not touch this data anywhere: it simply stores the pointer
for the user. Collision
Event Handler This
event handler gets notified when two Solids collide. Each Solid has its own pointer to a
collision event handler. If this
pointer is NULL, it will ignore collision events; otherwise, its collision
event handler will be notified whenever the Solid collides with another
Solid. Here
is an example of a user’s derived collision event handler:
There
is a lot going on here, so we’ll take it one step at a time. First,
OPAL_CALL is a necessary evil that tells the compiler to use the same calling
convention for your function as the one OPAL uses. Your compiler will probably complain if the
calling conventions don’t match. Just
make sure you put OPAL_CALL before the name of all functions that are
overridden from the base OPAL class.
This goes for all event handlers.
Second, note the use of the user data pointer. This lets the user get access to their own
application objects, in this case a Missile.
The user data pointer must have already been setup (using the Solid
“setUserData” function) prior to the collision. Finally, the CollisionEvent data structure
contains useful information describing the collision, including pointers to
the two Solids that collided (note the names of the pointers: “thisSolid”
refers to the Solid whose event handler was just called), the position of the
collision, the normal of the collision, etc. The
end result of this “MissileCollisionEventHandler” is that when a missile
collides with another Solid, destroys the missile, displays an explosive
particle effect, plays an explosion sound, and applies a force to the other
Solid. A more advanced effect would
use OPAL’s VolumeSensor to find and affect all Solids within some radius of
the explosion. Keep
in mind that this can handle collision events regardless of whether the two
Solids generate physical contacts.
This allows the creation of “trigger volumes,” Solids that do not
affect other Solids physically but can still generate collision events. See the tutorial on contact groups for more
info on disabling physical contact generation between two Solids. Joint Break
Event Handler This
event handler gets notified when a breakable Joint breaks. The following example shows how to play a
sound effect when a Joint breaks:
As
soon as the Joint breaks, it becomes disabled, and this event handler gets
notified. In this example, the event
handler simply plays a sound effect when the Joint breaks. Post Step
Event Handler Sometimes
it is helpful to know exactly when a simulation step is finished. For example, say an application uses a
simulation step size of 0.01. On a
particular frame it tells the OPAL Simulator to simulate everything ahead
0.05 seconds which would internally take five simulation steps of 0.01
seconds each. The application normally
has no way of knowing when each step is finished which may be necessary for,
say, an AI routine that should get updated after every simulation step. The PostStepEventHandler solves this
problem.
Notice
that the Simulator is the object that maintains a pointer to the
PostStepEventHandler. This example
gives the user’s event handler a pointer to a function to be called at the
end of each simulation step. Of course
the use of callback functors like in this example is not required: you could
simply perform all necessary actions within the handlePostStepEvent function. |
OPAL is Copyright © 2004-2005 Alan Fischer, Andres Reinot, and
Tyler Streeter