In an effort to get away from relying on references to base, I have been using a BulletinBoard. After some experimented I’ve landed on an approach that I think is quite practical.
It relies on a retrieve function that takes two parameters, a string (the name of the item you’re looking for) and a create function to create the item if it doesnt exist yet.
This ensures that the retrieve function always retrieves the item (or at least a default version of it) and as a side effect only things that are needed are created and they are not created until needed for the first time.
The following are code snippets to illustrate the concept, it is not a full project and will not run.
from direct.showbase.BulletinBoard import BulletinBoard
# https://github.com/panda3d/panda3d/blob/master/direct/src/showbase/BulletinBoard.py
_globalBulletinBoard = BulletinBoard()
def retrieve(postName, createFunction):
if not _globalBulletinBoard.has(postName):
item = createFunction()
_globalBulletinBoard.post(postName, item)
result = _globalBulletinBoard.get(postName)
return result
import panda3d.core as Core
import panda3d.physics as Physics
def retrieve_cTrav():
def createFunction():
cTrav = Core.CollisionTraverser('colTrav')
# cTrav.set_respect_prev_transform(True)
base.cTrav = cTrav
return cTrav
result = GlobalBulletinBoard.retrieve('cTrav', createFunction)
return result
def retrieve_collision_handler_event():
def createFunction():
cHandlerEvent = ImportsPanda.Core.CollisionHandlerEvent()
# --- only when the into node has the indicated tag
# cHandlerEvent.addInPattern('%fn-into-%in%(position)ih')
# cHandlerEvent.addOutPattern('%fn-out-%in%(position)ih')
cHandlerEvent.addInPattern('%fn-into-%in')
cHandlerEvent.addAgainPattern('%fn-again-%in')
cHandlerEvent.addOutPattern('%fn-out-%in')
return cHandlerEvent
result = GlobalBulletinBoard.retrieve('cHandlerEvent', createFunction)
return result
def retrieve_colHandlerPhysics():
def createFunction():
base.enableParticles()
cHandlerPhysics = Physics.PhysicsCollisionHandler()
# cHandlerPhysics.setHorizontal(True)
return cHandlerPhysics
result = GlobalBulletinBoard.retrieve('cHandlerPhysics', createFunction)
return result
def retrieve_activeInputProcessor():
def _create_inputProcessorDoNothing():
result = InputDoNothing()
return result
postName = 'activeInputProcessor'
createFunction = _create_inputProcessorDoNothing
result = GlobalBulletinBoard.retrieve(postName, createFunction)
return result
def task_process_input(task):
curInputProcessor = retrieve_activeInputProcessor()
curInputProcessor.proces()
return task.cont
This one is created as ‘do nothing’ by default, and is intended to be replaced (bulletinBoard.post function) by the relevant InputProcessor depending on the game state. For example InputMainMenu for menu navigation and InputDriving or InputWalking as the situation requires. The process input task is added to the taskMgr at start up and runs every frame. I find it easier to swap the InputProcessor than to to toggle the task off and on.
edit: the bulletinBoard class comes with a builtin ‘hey someone changed the item that this key refers to’ warning, which storing things on base does not. I like storing classes that then store the relevant information, so you can update variables without the alert triggering every frame and still get the warning when you’re overwriting a stored class.