Gameplay code can be a complex beast. In many cases, there are complex, many-to-many relationships between all sorts of different game entities. This can be good for the player, as he or she might enjoy the interesting emergent patterns of behavior created by this kind of game object interconnection.
For the programmer (that is you), who has to think about and write all the code that makes this happen, things look different, though. Having the game entity that creates an event which holds references to all the objects that will react to it could be problematic. This could lead to chaotic, messy code and a great deal of unnecessary coupling between otherwise independent and differing types of objects. The more complex the code, the more you need to create a more modular and maintainable design.
From a software engineering point of view, this situation cries out for a form of publish/subscribe design pattern that allows game entities (and other kinds of objects too, of course) to send and react to messages without knowing about the specific senders or receivers of the message.
Panda3D provides such a neat messaging subsystem, which we will take a look at in this recipe.
This recipe builds upon the project structure described in Setting up the game structure found in Chapter 1. Please follow these instructions before going on with the current recipe.
Follow the following instructions to learn how to use Panda3D's messaging system:
Application.py
so it contains the following code:from direct.showbase.ShowBase import ShowBase from direct.interval.IntervalGlobal import * from direct.showbase.DirectObject import DirectObject from panda3d.core import * class Sender(DirectObject): def start(self): smiley = loader.loadModel("smiley") pause = Sequence(Wait(5), Func(messenger.send, "smiley-done", [smiley])) pause.start() class Receiver(DirectObject): def __init__(self): self.accept("smiley-done", self.showSmiley) def showSmiley(self, smiley): smiley.reparentTo(render) class Application(ShowBase): def __init__(self): ShowBase.__init__(self) self.cam.setPos(0, -10, 0) rec = Receiver() snd = Sender() snd.start()
In our little event sample, we create the classes Sender
and Receiver
that are communicating without ever knowing about each other's existence.
In the start()
method of Sender
, we load the smiley model and wait five seconds before sending the"smiley-done"
message, passing the smiley model reference as a parameter to the messenger.send()
method that adds the message to the global message queue of Panda3D.
By calling accept()
in its constructor, each instance of Receiver
subscribes to the"smiley-done"
message. As soon as a Sender
dispatches this message, the showSmiley()
method will be called. This method reparents the smiley model to the scene root to make it visible.