Input state for single DirectObject

Note: you usually don’t need this, there is global inputState, this snippet is tied to single object.
For example if you have pong like game, and you use panda’s internal input state, all players will be controlled by input from any of them. There is way to go around that behaviour( like adding playerId to inputState), but that sounds like improper way of doing things

You can copy and paste code in your favorite editor and try running it


from direct.showbase.DirectObject import DirectObject
from direct.showbase.ShowBase import ShowBase

class Player(DirectObject):
    def __init__(self):
        #set is python collection, just like list and dictionary
        #if you want to know more, google it
        self.inputStates = set()
        self.NP = loader.loadModel("smiley")
        self.NP.reparentTo(render)
        # in real program, you will probably want to read controls from
        # config file (i use yaml)
        controls = {'keyboard': {'forward': 'w',
                                'turbo': 'q',
                                'right': 'd',
                                'back': 's',
                                'left': 'a'} }
        
        #i usually call this from other function which creates more than
        # instance of player and send different controls for it
        self.setupControls(controls)
        
        
    def setupControls(self, controls):
        
        taskMgr.add(self.processInput, "Process Input")
        
        #keyboard shortcuts
        #action = "left"
        #key = "a"
        for action, bind in controls["keyboard"].items():
            
            #if bind is clicked, we set input state (third arguments must be list,
            # and it will pass all elements in that
            # list as argument to function called - self.setInputState)
            self.accept(bind, self.setInputState, [action])
            #if bind is released, we want to remove input state
            self.accept(bind + "-up", self.removeInputState, [action])

    def setInputState(self, action):
        #accepts String
        #comment next line, i am using it for debugging purposes
        print "Player setting state %s" % (action)
        # we add string which represents action to set
        # left, turbo, jump for example
        # dont worry about doubles, if you have two keys that move left there will
        # be only one "left" in set
        self.inputStates.add(action)
        
    def removeInputState(self, action):
        #accepts String
        #this try block is needed in case that there are 2 keys mapped to same action
        #when you release first, action will get removed from input states set
        #and when you release second, you would get error, here we just pass silently
        try:
            self.inputStates.remove(action)
        except:
            pass
    
    def state(self, state):
        #accepts String
        #function which checks if there is state in inputStates and return True/False
        return state in self.inputStates
    
    def processInput(self, task):

        self.dt = globalClock.getDt()
        speed = 40
        turboModifier = 4

        if self.state('turbo'):
            speed = speed * turboModifier
        
        if self.state('left'):
            self.NP.setX(self.NP, -self.dt * speed)
        if self.state('right'):
            self.NP.setX(self.NP, self.dt * speed)
        if self.state('forward'):
            self.NP.setY(self.NP, self.dt * speed)
        if self.state('back'):
            self.NP.setY(self.NP, -self.dt * speed)
            
        return task.cont
            

class Game(ShowBase):

    def __init__(self):
        ShowBase.__init__(self)
        x = Player()
        
x = Game()
x.run()