Create and manage multiple scenes

Hi there,

i was wondering, what is the most efficient way to create and handle multiple scenes?
For example, in a Lobby scene i might have a camera, an actor, and some UI, that would be different in another scene, say for example during a match. How can you implement this?

Thanks for your time in advance,
Tom.

I don’t know about the most efficient approach, but what I usually do is create classes to encapsulate such things, and then create, destroy, show, or hide them as called for.

So something like this:

class Scene():
    def __init__(self):
        self.rootNode = NodePath(PandaNode("scene root"))
        # Other initialisation here as appropriate

    def show(self):
        self.rootNode.reparentTo(render)

    def hide(self):
        self.rootNode.detachNode()

    def destroy(self):
        if self.rootNode is not None:
            self.rootNode.removeNode()
            self.rootNode = None
        # Other cleanup here as called for

# Create and show a scene
scene1 = Scene()
scene1.show()

# Now, replace it with another scene

# If it might be used again:
scene1.hide()
# If it's no longer relevant:
scene1.destroy()

scene2 = Scene()
scene2.show()

The above is, to be clear, a simplistic example–in a full game I’d likely have a class managing the scenes, perhaps keeping a list of them, and so would actually discard “scene1” rather than leaving it hanging around as an unused variable.)

1 Like

How do you think that i can handle the “update” function in the scene, the one that runs every frame to do stuff? I set up a basic test, and for example the keyboard events were still occuring even if the scene was hidden using your function. If you want to look at its code:

    def update(self, task) -> None:

        if self.first_frame:
            try:
                self.previous_x = base.mouseWatcherNode.getMouseX()
                self.previous_y = base.mouseWatcherNode.getMouseY()
            except:
                self.previous_x = 0
                self.previous_y = 0

            self.FpsController = FPSController(self.previous_x, self.previous_y, config_data)
            self.first_frame = False


        dt = globalClock.getDt()    

        if self.keyMap[MOVE_FWD]:
            if self.keyMap[RUN]:
                deg = math.radians(base.camera.getH())
                base.camera.setPos(base.camera.getPos() + Vec3(math.sin(deg)*-10*dt, math.cos(deg)*10*dt, 0))
                self.tempActor.setPos(self.tempActor.getPos() +  Vec3(math.sin(deg)*-10*dt, math.cos(deg)*10*dt, 0))
            self.tempActor.getChild(0).setH(180)
            deg = math.radians(base.camera.getH())
            base.camera.setPos(base.camera.getPos() + Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.setPos(self.tempActor.getPos() +  Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.getChild(0).setH(180)
        if self.keyMap[MOVE_BACK]:
            deg = math.radians(base.camera.getH())
            base.camera.setPos(base.camera.getPos() + Vec3(math.sin(deg)*5*dt, math.cos(deg)*-5*dt, 0))
            self.tempActor.setPos(self.tempActor.getPos() +  Vec3(math.sin(deg)*5*dt, math.cos(deg)*-5*dt, 0))
            self.tempActor.getChild(0).setH(180)
        if self.keyMap[MOVE_LEFT]:
            deg = math.radians(base.camera.getH() + 90)
            base.camera.setPos(base.camera.getPos() + Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.setPos(self.tempActor.getPos() +  Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.getChild(0).setH(180)
        if self.keyMap[MOVE_RIGHT]:
            deg = math.radians(base.camera.getH() - 90)
            base.camera.setPos(base.camera.getPos() + Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.setPos(self.tempActor.getPos() +  Vec3(math.sin(deg)*-5*dt, math.cos(deg)*5*dt, 0))
            self.tempActor.getChild(0).setH(180)
        if self.keyMap[WEAPON_SHOOT]:
            print("shot")

        self.UpdateVisualController()
        
        self.world.doPhysics(dt)

        return task.cont

Please note that

self.UpdateVisualController()

is not a Panda3D method but a function that i created to make you camera move as in a FPS game.

What I usually do is to have a central “framework” or “game” class that manages the “scene” or “world” classes. That central class then operates the update-task, and in turn calls the update methods of any relevant “scene”/“world” class-instances.

This should result in only the currently-active “scenes”/“worlds” being updated.

As an alternative, you could simply have the “scene” class remove its update-task when it’s hidden or destroyed, and create that task when it’s shown.

1 Like