Events occur either when the user does something (such as clicking a mouse or pressing a key) or when sent by the script using messenger.send()
Defining a class that can Handle Events
The first step is to import the DirectObject
module:
from direct.showbase import DirectObject
With DirectObject loaded, it is possible to create a subclass of DirectObject. This allows the class to inherit the messaging API and thus listen for events.
class myClassName(DirectObject.DirectObject):
class Hello(DirectObject.DirectObject):
def __init__(self):
self.accept('mouse1', self.printHello)
def printHello(self):
print('Hello!')
h = Hello()
Event Handling Functions
An object may accept an event an infinite number of times or accept it only once. If checking for an accept within the object listening to it, it should be prefixed with self. If the accept command occurs outside the class, then the variable the class is associated with should be used.
myDirectObject.accept('Event Name', myDirectObjectMethod)
myDirectObject.acceptOnce('Event Name', myDirectObjectMethod)
Finally, there are some useful utility functions for debugging. The messenger typically does not print out when every event occurs. Toggling verbose mode will make the messenger print every event it receives
messenger.toggleVerbose()
print(messenger)
messenger.clear()
Sending Custom Events
Custom events can be sent by the script using the code
messenger.send('Event Name')
A Note on Object Management
When a DirectObject accepts an event, the messenger retains a reference to that DirectObject. To ensure that objects that are no longer needed are properly disposed of, they must ignore any messages they are accepting.
One solution (patterned after other parts of the Panda3D architecture) is to define a “destroy” method for any custom classes you create, which calls “ignoreAll” to unregister from the event-handler system.
import direct.directbase.DirectStart
from direct.showbase import DirectObject
from panda3d.core import *
class Test(DirectObject.DirectObject):
def __init__(self):
self.accept("FireZeMissiles", self._fireMissiles)
def _fireMissiles(self):
print("Missiles fired! Oh noes!")
# function to get rid of me
def destroy(self):
self.ignoreAll()
foo = Test() # create our test object
foo.destroy() # get rid of our test object
del foo
messenger.send("FireZeMissiles") # No missiles fire
base.run()
Coroutine Event Handlers
It is permissible for any event handler to be a coroutine (i.e. marked as an async def
), which permits use of the await
keyword inside the handler. Usage is otherwise identical to a regular event handler.
class Test(DirectObject):
def __init__(self):
self.accept('space', self.on_space)
async def on_space(self):
await Task.pause(1.0)
print("The space key was pressed one second ago!")