Loops can be found in any video game running in real-time. Small incremental steps generally characterize gameplay simulation code. With each of these steps occurs a minimal frame-by-frame change of object transformations, creating the illusion of smooth movement.
Panda3D has its own way of handling code that needs to be called time and time again while the game is running. This recipe's topic is Panda3D's task system.
Please complete the tasks found in Setting up the game structure found in Chapter 1 to get ready for this recipe.
Let's implement an application that uses the task system to execute a piece of code in every frame:
Application.py
and insert the following code:from direct.showbase.ShowBase import ShowBase from panda3d.core import * import random class Application(ShowBase): def __init__(self): ShowBase.__init__(self) self.smiley = loader.loadModel("smiley") self.smileyCount = 0 self.cam.setPos(0, -100, 10) taskMgr.doMethodLater(0.1, self.addSmiley, "AddSmiley") taskMgr.add(self.updateSmileys, "UpdateSmileys", uponDeath = self.removeSmileys) taskMgr.doMethodLater(60, taskMgr.remove, "RemoveUpdate", extraArgs = ["UpdateSmileys"]) def addSmiley(self, task): sm = render.attachNewNode("smiley-instance") sm.setPos(random.uniform(-20, 20), random.uniform(-30, 30), random.uniform(0, 30)) sm.setPythonTag("velocity", 0) self.smiley.instanceTo(sm) self.smileyCount += 1 if self.smileyCount == 100: return task.done return task.again def updateSmileys(self, task): for smiley in render.findAllMatches("smiley-instance"): vel = smiley.getPythonTag("velocity") z = smiley.getZ() if z <= 0: vel = random.uniform(0.1, 0.8) smiley.setZ(z + vel) vel -= 0.01 smiley.setPythonTag("velocity", vel) return task.cont def removeSmileys(self, task): for smiley in render.findAllMatches("smiley-instance"): smiley.removeNode()
To interface with Panda3D's task system, we are using the global taskMgr
object. In total, we are adding three tasks to our application.
First we use doMethodLater()
to add a task that calls the addSmiley()
method after 0.1
seconds. As long as there are less than 100 smileys in the scene, the addSmiley()
method will return task.again
, which will put the task into the task queue again to be called after another tenth of a second has passed.
The second task we add is responsible for updating the positions of the smileys. This will be called every frame until the game is quit or the task is removed from the internal queue of taskMgr
. For the latter case, we define that the removeSmileys()
method should be called that removes all smileys from the scene.
Finally, we enqueue another method to be called later, which is the remove()
method of taskMgr
. This will stop the update task and also remove all smileys from