Example #1
0
    def __init__( self ):
        self.cfg = ConfigHandler( 'thm.cfg' )
        self.cfg.readConfig()
        self.groups = []
        self.floor = None
        self.space = pymunk.Space()
        self.space.gravity = ( 0.0, 0.0 )
        self.space.damping = 0.0
        #self.space.set_default_collision_handler()
        self.space.add_collision_handler( 1, 2, callSpeshulEffect )
        self.space.add_collision_handler( 2, 2, callSpeshulEffect )
        self.speshulCaller = callSpeshulEffect
        self.postStepQueue = []

        self.gameLogicManager = ActualManager( self )
        self.justEditing = False

        self.spaceGhost = None
        
        #If this is true, devtools will class update EVERYTHING.
        self.forceUpdateEverything = False

        self.boundaryBody = pymunk.Body()
        self.boundaries = []
        
        #A list of int values that represent the index values of a 
        #group in self.groups, each group is drawn in order of the
        # values in this list. Use addGroup() to add one, by default 
        # it puts the group in the last index of self.drawOrder,
        # unless passed a index value.
        self.drawOrder = []
        self.interweaveOrder={}

        self.curInputDict = {}
        
        self.playersGroup = None

        self.namedGroups = { 'playersGroup':self.playersGroup }

        self.lineVisualiser = LineVisualiser( self )

        self.rerenderEverything = False

        self.soundManager = SoundManager( self )

        self.hudList = []
        
        self.fileName = "Untitled"
        self.amountOfEntsOnLoad = None

        self.hardBlockInput = False
        self.inputDictLog = []

        #These to variables are the displacement from the state's (0,0) and the screen's (0,0), so they can be used for panning.
        self.panX, self.panY = 0, 0
        self.limitX1, self.limitX2, self.limitY1, self.limitY2 = None, None, None, None

        #This is the idSource, I use it for give ids to Entitys.
        self.idSource = IdSource()
    
        self.isClient = False
        self.isHost = False
        self.networkRate = 20.0
        self.networkTicker = 0
        self.networkNode = None
        self.networkingStarted = False

        #This is set by the DevMenu init
        self.devMenuRef = None

        self.paused = False
        self.keyboardInputEnabled = False
        self.deleteLastChar = False
        self.checkFocus = False
	self.pausedByFocus = False

        #So this is quite an important boolean.
        #If this is true everything in the PlayState will be drawn in order of the bottom of it's bounding rect, which I will refer
        #to as 'the foot'. If the foot is higher up the screen, the item will be drawn sooner.
        #If this is False, everything will be drawn according to the drawOrder and interweaveOrder system.
        #DrawByFeet is more suitable for some topdown/isometric games.
        self.drawByFeet = False

        self.useSuggestedGravityEntityPhysics = False

        self.stateToSwap = None
Example #2
0
    def __init__(self):
        self.cfg = ConfigHandler('thm.cfg')
        self.cfg.readConfig()
        self.groups = []
        self.floor = None
        self.space = pymunk.Space()
        self.space.gravity = (0.0, 0.0)
        self.space.damping = 0.0
        #self.space.set_default_collision_handler()
        self.space.add_collision_handler(1, 2, callSpeshulEffect)
        self.space.add_collision_handler(2, 2, callSpeshulEffect)
        self.speshulCaller = callSpeshulEffect
        self.postStepQueue = []

        self.gameLogicManager = ActualManager(self)
        self.justEditing = False

        self.spaceGhost = None

        #If this is true, devtools will class update EVERYTHING.
        self.forceUpdateEverything = False

        self.boundaryBody = pymunk.Body()
        self.boundaries = []

        #A list of int values that represent the index values of a
        #group in self.groups, each group is drawn in order of the
        # values in this list. Use addGroup() to add one, by default
        # it puts the group in the last index of self.drawOrder,
        # unless passed a index value.
        self.drawOrder = []
        self.interweaveOrder = {}

        self.curInputDict = {}

        self.playersGroup = None

        self.namedGroups = {'playersGroup': self.playersGroup}

        self.lineVisualiser = LineVisualiser(self)

        self.rerenderEverything = False

        self.soundManager = SoundManager(self)

        self.hudList = []

        self.fileName = "Untitled"
        self.amountOfEntsOnLoad = None

        self.hardBlockInput = False
        self.inputDictLog = []

        #These to variables are the displacement from the state's (0,0) and the screen's (0,0), so they can be used for panning.
        self.panX, self.panY = 0, 0
        self.limitX1, self.limitX2, self.limitY1, self.limitY2 = None, None, None, None

        #This is the idSource, I use it for give ids to Entitys.
        self.idSource = IdSource()

        self.isClient = False
        self.isHost = False
        self.networkRate = 20.0
        self.networkTicker = 0
        self.networkNode = None
        self.networkingStarted = False

        #This is set by the DevMenu init
        self.devMenuRef = None

        self.paused = False
        self.keyboardInputEnabled = False
        self.deleteLastChar = False
        self.checkFocus = False
        self.pausedByFocus = False

        #So this is quite an important boolean.
        #If this is true everything in the PlayState will be drawn in order of the bottom of it's bounding rect, which I will refer
        #to as 'the foot'. If the foot is higher up the screen, the item will be drawn sooner.
        #If this is False, everything will be drawn according to the drawOrder and interweaveOrder system.
        #DrawByFeet is more suitable for some topdown/isometric games.
        self.drawByFeet = False

        self.useSuggestedGravityEntityPhysics = False

        self.stateToSwap = None
Example #3
0
class PlayState:
    """ The PlayState class.
    Maintains a list of all entity groups, can update them all, draw them all,
    return a list of all their sprites, and run the collision system."""
    def __init__( self ):
        self.cfg = ConfigHandler( 'thm.cfg' )
        self.cfg.readConfig()
        self.groups = []
        self.floor = None
        self.space = pymunk.Space()
        self.space.gravity = ( 0.0, 0.0 )
        self.space.damping = 0.0
        #self.space.set_default_collision_handler()
        self.space.add_collision_handler( 1, 2, callSpeshulEffect )
        self.space.add_collision_handler( 2, 2, callSpeshulEffect )
        self.speshulCaller = callSpeshulEffect
        self.postStepQueue = []

        self.gameLogicManager = ActualManager( self )
        self.justEditing = False

        self.spaceGhost = None
        
        #If this is true, devtools will class update EVERYTHING.
        self.forceUpdateEverything = False

        self.boundaryBody = pymunk.Body()
        self.boundaries = []
        
        #A list of int values that represent the index values of a 
        #group in self.groups, each group is drawn in order of the
        # values in this list. Use addGroup() to add one, by default 
        # it puts the group in the last index of self.drawOrder,
        # unless passed a index value.
        self.drawOrder = []
        self.interweaveOrder={}

        self.curInputDict = {}
        
        self.playersGroup = None

        self.namedGroups = { 'playersGroup':self.playersGroup }

        self.lineVisualiser = LineVisualiser( self )

        self.rerenderEverything = False

        self.soundManager = SoundManager( self )

        self.hudList = []
        
        self.fileName = "Untitled"
        self.amountOfEntsOnLoad = None

        self.hardBlockInput = False
        self.inputDictLog = []

        #These to variables are the displacement from the state's (0,0) and the screen's (0,0), so they can be used for panning.
        self.panX, self.panY = 0, 0
        self.limitX1, self.limitX2, self.limitY1, self.limitY2 = None, None, None, None

        #This is the idSource, I use it for give ids to Entitys.
        self.idSource = IdSource()
    
        self.isClient = False
        self.isHost = False
        self.networkRate = 20.0
        self.networkTicker = 0
        self.networkNode = None
        self.networkingStarted = False

        #This is set by the DevMenu init
        self.devMenuRef = None

        self.paused = False
        self.keyboardInputEnabled = False
        self.deleteLastChar = False
        self.checkFocus = False
	self.pausedByFocus = False

        #So this is quite an important boolean.
        #If this is true everything in the PlayState will be drawn in order of the bottom of it's bounding rect, which I will refer
        #to as 'the foot'. If the foot is higher up the screen, the item will be drawn sooner.
        #If this is False, everything will be drawn according to the drawOrder and interweaveOrder system.
        #DrawByFeet is more suitable for some topdown/isometric games.
        self.drawByFeet = False

        self.useSuggestedGravityEntityPhysics = False

        self.stateToSwap = None

    def initNetworking( self ):
        if not self.networkingStarted:
            #pygnetic.init(logging_lvl=logging.DEBUG)
            pygnetic.init(logging_lvl=logging.ERROR)
            self.networkingStarted = True
            registerMessages()

    def hostGame( self ):
        if self.isHost:
            del self.networkNode._server
            gc.collect()
        else:
            self.isHost = True
            self.initNetworking()
        self.networkNode = NetworkServer( self, "", int( self.cfg.getVal("port") ), networkingMode=1 )

        self.addGroup( EntityGroup( 'networkPlayers' ), name='networkPlayers' ) 
        print "Beginning hosting..."

    def connectToGame( self, addr, port ):
        if self.isClient:
            del self.networkNode._client
            gc.collect()
        else:
            self.isClient = True
            self.initNetworking()
        self.networkNode = NetworkClient( self, networkingMode=1 )
        self.networkNode.connect( addr, port )

        self.addGroup( EntityGroup( 'networkPlayers' ), name='networkPlayers' ) 
        print "Connecting..."

    def addBoundary( self, point1, point2 ):
        newSeg = pymunk.Segment( self.boundaryBody, point1, point2, 1 )
        self.boundaries.append( newSeg )
        self.space.add( newSeg )

    def removeBoundary( self, givenSeg ):
        self.boundaries.remove( givenSeg )
        self.space.remove( givenSeg )

    def swap( self, newState ):
        self.stateToSwap = newState

    def addInterweaveGroup( self, group, index ):
        if self.interweaveOrder.get( index, None ) is None:
            self.interweaveOrder[index] = [group]
        else:
            self.interweaveOrder[index].append( group )
        
    def addGroup(self, group, indexValue=None, isPlayerGroupBool=False, name=None, interweaveWithFloor=False):
        """Add's an entity group to the PlayState.

        If indexValue specifies the draw-order, defaults to last.
        isPlayerGroupBool specifies if the group is a group of players
        (ie, a group that will be sent input dictionaries).
        If a "name" is given, set PlayState.name = group.
        interweaveWithFloor means that the entityGroup is drawn with 
        the floor layers instead, drawn after the layer of it's index.
        Multiple entgroups can share a interweave number, and they'll be 
        drawn according to order of their addition. an interweave index of 0
        means it will be drawn AFTER layer 1, the first layer above the background floor"""
        
        group.playState = self
        self.groups.append( group )
        if not interweaveWithFloor:
            newIndex = len( self.groups ) - 1
            if indexValue is None:
                self.drawOrder.append( newIndex )
            else:
                self.drawOrder.insert( indexValue, newIndex )
        else:
            newIndex = len( self.floor.layers ) - 1
            if indexValue is None:
                self.addInterweaveGroup( group, newIndex )
            else:
                self.addInterweaveGroup( group, indexValue )
        
        if isPlayerGroupBool:
            self.namedGroups['playersGroup'] = group
            self.playersGroup = group
        
        if name is not None:
            self.namedGroups[name] = group
            setattr( self, name, group )

    def checkForFocus( self ):
        lostFocus = ( not pygame.mouse.get_focused() ) and self.checkFocus
        self.pausedByFocus = lostFocus

    def pause( self ):
        self.paused = True

    def unpause( self ):
        self.paused = False

    def togglePaused( self ):
        self.paused = not self.paused

    def processNetworkEvents( self, dt ):
        self.gameLogicManager.preNetworkTick( dt )
        if self.isHost or self.isClient:
            if self.networkTicker >= int(60.0/self.networkRate):
                self.networkNode.update( dt )
                self.networkTicker = -1
            self.networkNode.updateTime( dt )
            self.networkTicker += 1
        self.gameLogicManager.postNetworkTick( dt )

    def update( self, dt ):
        """A generic update function.
        Sends input dictionaries to playerGroups.
        Updates all the child groups, runs the collision system."""
        
        self.floor.update( self.panX, self.panY )
        
        self.checkForFocus()
        if self.paused or self.pausedByFocus:
            self.processNetworkEvents( dt )
            return None

        #Game logic
        self.gameLogicManager.preTick( dt )

        if not self.hardBlockInput:
            #I'm doing the same thing even if the host or client is the same, to force identical player behaviour for either.
            if self.isClient or self.isHost:
                self.inputDictLog.append( self.curInputDict )
                if self.networkTicker >= int(60.0/self.networkRate):
                    for eachDict in self.inputDictLog:
                        if self.playersGroup is not None and len( eachDict ) > 0:
                            for eachPlayer in self.playersGroup.sprites():
                                eachPlayer.sendInput( eachDict )
                    
                        for eachElement in self.hudList:
                            eachElement.sendInput( eachDict )
                    self.inputDictLog = []
                if self.isClient:
                    self.networkNode.sendInput( self.curInputDict )
            else:
                if self.playersGroup is not None and len( self.curInputDict ) > 0:
                    for eachPlayer in self.playersGroup.sprites():
                        eachPlayer.sendInput( self.curInputDict )
                
                for eachElement in self.hudList:
                    eachElement.sendInput( self.curInputDict )

        self.curInputDict = {}
        
        
        self.space.step( 1.0/60.0 )
        for eachTriplet in self.postStepQueue:
            eachTriplet[0]( eachTriplet[1], eachTriplet[2] )
        self.postStepQueue = []
        
        for eachGroup in self.groups:
            eachGroup.update( dt )

        for eachElement in self.hudList:
            eachElement.update( dt )

        self.soundManager.update( dt )
	self.processNetworkEvents( dt )
        self.gameLogicManager.postTick( dt )

    def setPan( self, x, y ):
        screenW, screenH = getResolution()
        if self.limitX1 is not None:
            x = min( -self.limitX1, x )
        if self.limitX2 is not None:
            x = max( -(self.limitX2-screenW), x )
        if self.limitY1 is not None:
            y = min( -(self.limitY1), y )
        if self.limitY2 is not None:
            y = max( -(self.limitY2-screenH), y )
        self.panX, self.panY = x, y

    def sendInput( self, inputDict ):
        """Simply sets PlayState.curInputDict to a given input dictionary, 
        for use in PlayState.update()"""
        self.curInputDict = inputDict

    def sprites( self ):
        """Returns a list of all the sprites in all the entity groups in the PlayState."""
        sumList = []
        for eachSpriteList in [ someGroup.sprites() for someGroup in self.groups ]:
            sumList.extend( eachSpriteList )
        return sumList

    def draw( self, surface ):
        """Draw all the child entity groups in PlayState, returning changed area rects"""
        changeRects = []
        changeRects.append( surface.blit( self.floor.layers[0].image, self.floor.layers[0].rect.topleft ) )
        if not self.drawByFeet:
            for eachVal in self.drawOrder:
                changeRects.extend( self.groups[eachVal].draw( surface ) )

            allInterweaveGroups = self.interweaveOrder.values()
            for eachVal in range( 1, len( self.floor.layers ) ):
                eachLayer = self.floor.layers[eachVal]            
                changeRects.append( surface.blit( eachLayer.image, eachLayer.rect.topleft ) )
                groupsToDraw = self.interweaveOrder.get( eachVal-1, None )
                if groupsToDraw is not None:
                    allInterweaveGroups.remove( groupsToDraw )
                    [ changeRects.extend( each.draw( surface ) ) for each in groupsToDraw ]
            #Draw anything left over
            for eachGroupSet in allInterweaveGroups:
                [ changeRects.extend( eachGroup.draw( surface ) ) for eachGroup in eachGroupSet ]

        else:
            yTuples = []
            for eachSprite in self.sprites():
                if eachSprite.flatInDrawByFeet:
                    y = eachSprite.rect.top
                else:
                    y = eachSprite.rect.bottom
                yTuples.append( (y, eachSprite) )
            yTuples.extend( [ (each.rect.bottom, each) for each in self.floor.layers[1:] ] )

            renderList = [ each[1] for each in sorted( yTuples, lambda x, y: cmp( x[0], y[0] ) ) ]
            #I probably shouldn't be doing this.
            tmpDrawGroup = pygame.sprite.LayeredDirty( self.floor.layers[0], renderList )
            changeRects.extend( tmpDrawGroup.draw( surface ) )
            tmpDrawGroup.empty()
            del tmpDrawGroup
        
        changeRects.extend( self.lineVisualiser.draw( surface, (self.panX, self.panY) ) )

        if len(  self.gameLogicManager.lasers ) > 0:
            pt1, pt2 = self.gameLogicManager.getCurAimLine()
            pygame.draw.line( surface, darkGreen, pt1, pt2 )

        for eachShot in self.gameLogicManager.preparedShots:
            pygame.draw.line( surface, green, eachShot[1][0], eachShot[1][1] )

        #for eachMissile in [ each for each in self.genericStuffGroup.sprites() if each.__class__.__name__ == "Missile" ]:
            #pygame.draw.line( surface, darkRed, eachMissile.getPosition(), eachMissile.startPos, 4 )

        for eachElement in self.hudList:
            eachElement.draw( surface )

        changeRects.extend( [ each.rect for each in self.hudList ] )
        
        if self.rerenderEverything:
            w, h = surface.get_width(), surface.get_height()
            changeRects.extend( [ pygame.Rect( 0, 0, w, h ) ] )
            self.rerenderEverything = False
        return changeRects

    #
    #
    #    This function, __getitem__, takes a value, if that value is a string, it looks for a group in PlayState.groups that has that string as entityGroup.name.
    #    If that value is an int, it returns the group at that index value in self.groups.
    #
    
    def __getitem__( self, value ):
        if type( value ) == str:
            for eachGroup in self.groups:
                if eachGroup.name == value:
                    return eachGroup
            raise Exception("No group in PlayState by name: " + value)
        elif type( value ) == int:
            return self.groups[value]

        else:
            raise Exception("PlayState.__getitem__ only takes strs or ints, got: " + str(type( value )) )
Example #4
0
class PlayState:
    """ The PlayState class.
    Maintains a list of all entity groups, can update them all, draw them all,
    return a list of all their sprites, and run the collision system."""
    def __init__(self):
        self.cfg = ConfigHandler('thm.cfg')
        self.cfg.readConfig()
        self.groups = []
        self.floor = None
        self.space = pymunk.Space()
        self.space.gravity = (0.0, 0.0)
        self.space.damping = 0.0
        #self.space.set_default_collision_handler()
        self.space.add_collision_handler(1, 2, callSpeshulEffect)
        self.space.add_collision_handler(2, 2, callSpeshulEffect)
        self.speshulCaller = callSpeshulEffect
        self.postStepQueue = []

        self.gameLogicManager = ActualManager(self)
        self.justEditing = False

        self.spaceGhost = None

        #If this is true, devtools will class update EVERYTHING.
        self.forceUpdateEverything = False

        self.boundaryBody = pymunk.Body()
        self.boundaries = []

        #A list of int values that represent the index values of a
        #group in self.groups, each group is drawn in order of the
        # values in this list. Use addGroup() to add one, by default
        # it puts the group in the last index of self.drawOrder,
        # unless passed a index value.
        self.drawOrder = []
        self.interweaveOrder = {}

        self.curInputDict = {}

        self.playersGroup = None

        self.namedGroups = {'playersGroup': self.playersGroup}

        self.lineVisualiser = LineVisualiser(self)

        self.rerenderEverything = False

        self.soundManager = SoundManager(self)

        self.hudList = []

        self.fileName = "Untitled"
        self.amountOfEntsOnLoad = None

        self.hardBlockInput = False
        self.inputDictLog = []

        #These to variables are the displacement from the state's (0,0) and the screen's (0,0), so they can be used for panning.
        self.panX, self.panY = 0, 0
        self.limitX1, self.limitX2, self.limitY1, self.limitY2 = None, None, None, None

        #This is the idSource, I use it for give ids to Entitys.
        self.idSource = IdSource()

        self.isClient = False
        self.isHost = False
        self.networkRate = 20.0
        self.networkTicker = 0
        self.networkNode = None
        self.networkingStarted = False

        #This is set by the DevMenu init
        self.devMenuRef = None

        self.paused = False
        self.keyboardInputEnabled = False
        self.deleteLastChar = False
        self.checkFocus = False
        self.pausedByFocus = False

        #So this is quite an important boolean.
        #If this is true everything in the PlayState will be drawn in order of the bottom of it's bounding rect, which I will refer
        #to as 'the foot'. If the foot is higher up the screen, the item will be drawn sooner.
        #If this is False, everything will be drawn according to the drawOrder and interweaveOrder system.
        #DrawByFeet is more suitable for some topdown/isometric games.
        self.drawByFeet = False

        self.useSuggestedGravityEntityPhysics = False

        self.stateToSwap = None

    def initNetworking(self):
        if not self.networkingStarted:
            #pygnetic.init(logging_lvl=logging.DEBUG)
            pygnetic.init(logging_lvl=logging.ERROR)
            self.networkingStarted = True
            registerMessages()

    def hostGame(self):
        if self.isHost:
            del self.networkNode._server
            gc.collect()
        else:
            self.isHost = True
            self.initNetworking()
        self.networkNode = NetworkServer(self,
                                         "",
                                         int(self.cfg.getVal("port")),
                                         networkingMode=1)

        self.addGroup(EntityGroup('networkPlayers'), name='networkPlayers')
        print "Beginning hosting..."

    def connectToGame(self, addr, port):
        if self.isClient:
            del self.networkNode._client
            gc.collect()
        else:
            self.isClient = True
            self.initNetworking()
        self.networkNode = NetworkClient(self, networkingMode=1)
        self.networkNode.connect(addr, port)

        self.addGroup(EntityGroup('networkPlayers'), name='networkPlayers')
        print "Connecting..."

    def addBoundary(self, point1, point2):
        newSeg = pymunk.Segment(self.boundaryBody, point1, point2, 1)
        self.boundaries.append(newSeg)
        self.space.add(newSeg)

    def removeBoundary(self, givenSeg):
        self.boundaries.remove(givenSeg)
        self.space.remove(givenSeg)

    def swap(self, newState):
        self.stateToSwap = newState

    def addInterweaveGroup(self, group, index):
        if self.interweaveOrder.get(index, None) is None:
            self.interweaveOrder[index] = [group]
        else:
            self.interweaveOrder[index].append(group)

    def addGroup(self,
                 group,
                 indexValue=None,
                 isPlayerGroupBool=False,
                 name=None,
                 interweaveWithFloor=False):
        """Add's an entity group to the PlayState.

        If indexValue specifies the draw-order, defaults to last.
        isPlayerGroupBool specifies if the group is a group of players
        (ie, a group that will be sent input dictionaries).
        If a "name" is given, set PlayState.name = group.
        interweaveWithFloor means that the entityGroup is drawn with 
        the floor layers instead, drawn after the layer of it's index.
        Multiple entgroups can share a interweave number, and they'll be 
        drawn according to order of their addition. an interweave index of 0
        means it will be drawn AFTER layer 1, the first layer above the background floor"""

        group.playState = self
        self.groups.append(group)
        if not interweaveWithFloor:
            newIndex = len(self.groups) - 1
            if indexValue is None:
                self.drawOrder.append(newIndex)
            else:
                self.drawOrder.insert(indexValue, newIndex)
        else:
            newIndex = len(self.floor.layers) - 1
            if indexValue is None:
                self.addInterweaveGroup(group, newIndex)
            else:
                self.addInterweaveGroup(group, indexValue)

        if isPlayerGroupBool:
            self.namedGroups['playersGroup'] = group
            self.playersGroup = group

        if name is not None:
            self.namedGroups[name] = group
            setattr(self, name, group)

    def checkForFocus(self):
        lostFocus = (not pygame.mouse.get_focused()) and self.checkFocus
        self.pausedByFocus = lostFocus

    def pause(self):
        self.paused = True

    def unpause(self):
        self.paused = False

    def togglePaused(self):
        self.paused = not self.paused

    def processNetworkEvents(self, dt):
        self.gameLogicManager.preNetworkTick(dt)
        if self.isHost or self.isClient:
            if self.networkTicker >= int(60.0 / self.networkRate):
                self.networkNode.update(dt)
                self.networkTicker = -1
            self.networkNode.updateTime(dt)
            self.networkTicker += 1
        self.gameLogicManager.postNetworkTick(dt)

    def update(self, dt):
        """A generic update function.
        Sends input dictionaries to playerGroups.
        Updates all the child groups, runs the collision system."""

        self.floor.update(self.panX, self.panY)

        self.checkForFocus()
        if self.paused or self.pausedByFocus:
            self.processNetworkEvents(dt)
            return None

        #Game logic
        self.gameLogicManager.preTick(dt)

        if not self.hardBlockInput:
            #I'm doing the same thing even if the host or client is the same, to force identical player behaviour for either.
            if self.isClient or self.isHost:
                self.inputDictLog.append(self.curInputDict)
                if self.networkTicker >= int(60.0 / self.networkRate):
                    for eachDict in self.inputDictLog:
                        if self.playersGroup is not None and len(eachDict) > 0:
                            for eachPlayer in self.playersGroup.sprites():
                                eachPlayer.sendInput(eachDict)

                        for eachElement in self.hudList:
                            eachElement.sendInput(eachDict)
                    self.inputDictLog = []
                if self.isClient:
                    self.networkNode.sendInput(self.curInputDict)
            else:
                if self.playersGroup is not None and len(
                        self.curInputDict) > 0:
                    for eachPlayer in self.playersGroup.sprites():
                        eachPlayer.sendInput(self.curInputDict)

                for eachElement in self.hudList:
                    eachElement.sendInput(self.curInputDict)

        self.curInputDict = {}

        self.space.step(1.0 / 60.0)
        for eachTriplet in self.postStepQueue:
            eachTriplet[0](eachTriplet[1], eachTriplet[2])
        self.postStepQueue = []

        for eachGroup in self.groups:
            eachGroup.update(dt)

        for eachElement in self.hudList:
            eachElement.update(dt)

        self.soundManager.update(dt)
        self.processNetworkEvents(dt)
        self.gameLogicManager.postTick(dt)

    def setPan(self, x, y):
        screenW, screenH = getResolution()
        if self.limitX1 is not None:
            x = min(-self.limitX1, x)
        if self.limitX2 is not None:
            x = max(-(self.limitX2 - screenW), x)
        if self.limitY1 is not None:
            y = min(-(self.limitY1), y)
        if self.limitY2 is not None:
            y = max(-(self.limitY2 - screenH), y)
        self.panX, self.panY = x, y

    def sendInput(self, inputDict):
        """Simply sets PlayState.curInputDict to a given input dictionary, 
        for use in PlayState.update()"""
        self.curInputDict = inputDict

    def sprites(self):
        """Returns a list of all the sprites in all the entity groups in the PlayState."""
        sumList = []
        for eachSpriteList in [
                someGroup.sprites() for someGroup in self.groups
        ]:
            sumList.extend(eachSpriteList)
        return sumList

    def draw(self, surface):
        """Draw all the child entity groups in PlayState, returning changed area rects"""
        changeRects = []
        changeRects.append(
            surface.blit(self.floor.layers[0].image,
                         self.floor.layers[0].rect.topleft))
        if not self.drawByFeet:
            for eachVal in self.drawOrder:
                changeRects.extend(self.groups[eachVal].draw(surface))

            allInterweaveGroups = self.interweaveOrder.values()
            for eachVal in range(1, len(self.floor.layers)):
                eachLayer = self.floor.layers[eachVal]
                changeRects.append(
                    surface.blit(eachLayer.image, eachLayer.rect.topleft))
                groupsToDraw = self.interweaveOrder.get(eachVal - 1, None)
                if groupsToDraw is not None:
                    allInterweaveGroups.remove(groupsToDraw)
                    [
                        changeRects.extend(each.draw(surface))
                        for each in groupsToDraw
                    ]
            #Draw anything left over
            for eachGroupSet in allInterweaveGroups:
                [
                    changeRects.extend(eachGroup.draw(surface))
                    for eachGroup in eachGroupSet
                ]

        else:
            yTuples = []
            for eachSprite in self.sprites():
                if eachSprite.flatInDrawByFeet:
                    y = eachSprite.rect.top
                else:
                    y = eachSprite.rect.bottom
                yTuples.append((y, eachSprite))
            yTuples.extend([(each.rect.bottom, each)
                            for each in self.floor.layers[1:]])

            renderList = [
                each[1]
                for each in sorted(yTuples, lambda x, y: cmp(x[0], y[0]))
            ]
            #I probably shouldn't be doing this.
            tmpDrawGroup = pygame.sprite.LayeredDirty(self.floor.layers[0],
                                                      renderList)
            changeRects.extend(tmpDrawGroup.draw(surface))
            tmpDrawGroup.empty()
            del tmpDrawGroup

        changeRects.extend(
            self.lineVisualiser.draw(surface, (self.panX, self.panY)))

        if len(self.gameLogicManager.lasers) > 0:
            pt1, pt2 = self.gameLogicManager.getCurAimLine()
            pygame.draw.line(surface, darkGreen, pt1, pt2)

        for eachShot in self.gameLogicManager.preparedShots:
            pygame.draw.line(surface, green, eachShot[1][0], eachShot[1][1])

        #for eachMissile in [ each for each in self.genericStuffGroup.sprites() if each.__class__.__name__ == "Missile" ]:
        #pygame.draw.line( surface, darkRed, eachMissile.getPosition(), eachMissile.startPos, 4 )

        for eachElement in self.hudList:
            eachElement.draw(surface)

        changeRects.extend([each.rect for each in self.hudList])

        if self.rerenderEverything:
            w, h = surface.get_width(), surface.get_height()
            changeRects.extend([pygame.Rect(0, 0, w, h)])
            self.rerenderEverything = False
        return changeRects

    #
    #
    #    This function, __getitem__, takes a value, if that value is a string, it looks for a group in PlayState.groups that has that string as entityGroup.name.
    #    If that value is an int, it returns the group at that index value in self.groups.
    #

    def __getitem__(self, value):
        if type(value) == str:
            for eachGroup in self.groups:
                if eachGroup.name == value:
                    return eachGroup
            raise Exception("No group in PlayState by name: " + value)
        elif type(value) == int:
            return self.groups[value]

        else:
            raise Exception(
                "PlayState.__getitem__ only takes strs or ints, got: " +
                str(type(value)))