About Game States

Hi,

I’m trying to put together a game that has the standard start-up logos, a title screen, the actual game, some sort of ranking screen, etc, but all the demos I’ve seen so far for Panda are basically just the gameplay running; I haven’t seem one with title screens, etc.

I’ve tried putting together a simple state manager like so:

class StateManager(DirectObject.DirectObject):
    
    #states: logo, title, gameplay, ranking, scores
    
    #constructor
    def __init__(self):
        #the first state the game is in is logo mode
        self.state = "logo";
        
        #so that updateState doesn't constantly update the scene
        self.doUpdate = True;
        
        taskMgr.add(self.updateState, "Update-State");
        
        
    #update the game state every frame
    def updateState(self, task):
        
        #only do the update once per call to setGameState
        if self.doUpdate:
            #check which state the game is in and update accordingly
            if self.state == "logo":
                #do this
                self.stateText = OnscreenText("Logo State", parent = render2d);
            elif self.state == "title":
                #do this
                self.stateText = OnscreenText("Title State", parent = render2d);
            elif self.state == "gameplay":
                #do this
                assert(True);
            elif self.state == "ranking":
                #do this
                assert(True);
            elif self.state == "scores":
                #do this
                assert(True);
            self.doUpdate = False;
            
        #continue this task
        return Task.cont;
            
    #set the game state
    def setGameState(self, state = None):
        self.state = state;
        self.doUpdate = True;
        
    #get the game state
    def getGameState(self):
        return self.state;

This is just a very bare minimum skeleton of a state manager, but does anyone have some suggestion as to where I go from here? I’m still not completely sure if this is the best way to achieve what I’m going for.

Also, does anyone have some examples/demos that show off menu/option screen/state functionality similar to this? I’m just a bit unsure as to how I should structure the program to achieve this.

Thanks!

Hi!

Im not so experienced with Python, but i do it with ‘Screens’. I just got a baseclass Screen that lookes like this:

class ScreenState:
    def __init__(self):
        self.name = "Noname"
        self.changeScreen = False
        self.nextScreen = None
        
        return

class Screen(DirectObject):
    #every screen can have an overlay...
    self.overlayScreen = None
    
    def __init__(self):
        self.screenState = ScreenState()
        return
    
    def update(self, time):
        if self.overlayScreen != None:
             self.overlayScreen.update()
        return
    
    def getState(self):
        return self.screenState

    def reportAspectRatioChange(self):
        if self.overlayScreen != None:
            self.overlayScreen.reportAspectRatioChange()
        return
    
    def shutdown(self):
        if self.overlayScreen != None:
             self.overlayScreen.shutdown()

        del self.screenState
        return

And in the main game class i do this:

class Game(DirectObject):
    def __init__(self):
        # some initialization here
        
        # start the gameloop
        self.gameTask = taskMgr.add(self.gameLoop, "gameLoop")
        self.gameTask.last = 0

        # Start the first screen.
        self.screen = MenuScreen()
        self.screenState = self.screen.getState()
        
    def gameLoop(self, task):
        if self.aspectRatio != base.getAspectRatio():
            self.screen.reportAspectRatioChange()
            self.aspectRatio = base.getAspectRatio()
            
        self.screen.update(task.time)
        
        # check the status of the screen
        self.checkScreen()
        
        return task.cont
    
    def checkScreen(self):
        self.screenState = self.screen.getState()
        
        if self.screenState.changeScreen == False:
            return
        
        # Change to the easy mode?
        if self.screenState.nextScreen == "Game: Easy":
            self.screen.shutdown()
            del self.screen
            self.screen = None
            self.screen = GameScreen()
            self.screenState = self.screen.getState()
            return
        
        # Change to mainmenu?
        if self.screenState.nextScreen == "Main Menu":
            self.screen.shutdown()
            del self.screen
            self.screen = None
            self.screen = MenuScreen()
            self.screenState = self.screen.getState()
            return

        print "ABORT: Undefined screen-change: %s." % self.screenState.nextScreen
        sys.exit(1)
        
        return

Im still at learning python, but this way im very flexible. I can code all screens in seperate files and every screen can have a subscreen (overlay) if i want to. Im sure there are better more pythonish solutions.

Edit: I did delete some error-checking from the original code. You should always check on errors after instance creation et cetera.

Akta

No need. Panda3D has a Finite State Machine system – it provides all you need:
panda3d.org/manual/index.php/Finite_State_Machines

I’m using it for everything – players, game states (or “screens”), etc. It is very flexible.