class ParkPanel:
	def __init__(self,bgImage, pos):
		self.isDone = 0
		self.boundRect = bgImage.get_rect()

		self.deviceGroup = RenderUpdates()
		self.rideGroup = RenderUpdates()
		self.carGroup = RenderUpdates()
		self.lineupGroup = RenderUpdates()
		self.highlightGroup = RenderUpdates()
		self.redVisitorGroup = RenderUpdates()
		self.greenVisitorGroup = RenderUpdates()
		self.parkGeography = parkGenerationFunction()
		allobjects.timeOfDay = simulation.startTime

		self.bgImage = bgImage

		for r in self.parkGeography.rides:
			self.rideGroup.add( r )
			self.carGroup.add( r.idleCars )

		for l in self.parkGeography.lineups:
			self.lineupGroup.add( l )
			

		totalVisitors = simulation.InitialNumVisitors(0)
		numGreen = int(totalVisitors*simulation.deviceAcceptanceRate)
		numRed = totalVisitors - numGreen
		for i in xrange( numGreen ):
			device = allobjects.server.NewDevice()
			if device:
				self.deviceGroup.add( device )
				newGuy = GuidedVisitor( device )
			else:
				newGuy = UnGuidedVisitor()
			self.AddVisitor( newGuy )
		for i in xrange( numRed ):
			newGuy = UnGuidedVisitor()
			self.AddVisitor( newGuy )

		events.AddListener( self )
		events.AddEvent( "SelectVisitor" )
		events.AddEvent( "UnSelectVisitor" )
		events.AddEvent( "HighlightRide" )
		events.AddEvent( "UnHighlightRide" )
		events.AddEvent( "HighlightLineup" )
		events.AddEvent( "UnHighlightLineup" )
		self.paused = False
		self.showRed = True
		self.justToggledShowRed = False
		self.showServer = True
		self.justToggledShowServer = False
		self.showGreen = True
		self.justToggledShowGreen = False

		self.redCircle = Surface( (17,17),SRCALPHA,32 )
		pygame.draw.circle( self.redCircle, (255,0,0), (8,8), 8, 1  )
		self.greenCircle = Surface( (17,17),SRCALPHA,32 )
		pygame.draw.circle( self.greenCircle, (0,255,0), (8,8), 8, 1 )

		self.highlight = Sprite()
		self.highlight.image = self.greenCircle
		self.highlight.rect = self.greenCircle.get_rect()

		self.selection = Sprite()
		self.selection.image = self.greenCircle
		self.selection.rect = self.greenCircle.get_rect()

		self.highlightVisitor = None
		self.selectedVisitor = None

	#---------------------------------------------------------------------
	def On_Pause(self):
		log.info( 'parkpanel pause' )
		self.paused = not self.paused

	#---------------------------------------------------------------------
	def On_ShowRed(self):
		self.showRed = not self.showRed
		self.justToggledShowRed = True

	#---------------------------------------------------------------------
	def On_ShowGreen(self):
		self.showGreen = not self.showGreen
		self.justToggledShowGreen = True

	#---------------------------------------------------------------------
	def On_ShowServer(self):
		self.showServer = not self.showServer
		self.justToggledShowServer = True

	#---------------------------------------------------------------------
	def On_MouseClick(self,pos):
		if not self.boundRect.collidepoint( pos ):
			return
		if self.selectedVisitor:
			events.Fire( "UnSelectVisitor", self.selectedVisitor )
			self.selectedVisitor = None
			self.highlightGroup.remove( self.selection )

		self.selectedVisitor = self.FindVisitorNear(pos)

		if not self.selectedVisitor:
			return

		self.highlightGroup.add( self.selection )

		if hasattr( self.selectedVisitor, 'device' ):
			self.selection.image = self.greenCircle
		else:
			self.selection.image = self.redCircle

		events.Fire( "SelectVisitor", self.selectedVisitor )

	#---------------------------------------------------------------------
	def UpdateHighlightGroup(self):
		if self.selectedVisitor:
			self.selection.rect.center = self.selectedVisitor.rect.center
		self.highlightGroup.update()

	#---------------------------------------------------------------------
	def On_MouseMove(self,event):
		pos = event.pos
		if not self.boundRect.collidepoint( pos ):
			return

		self.highlightVisitor = self.FindVisitorNear(pos)
		self.HighlightRideNear(pos)
		self.HighlightLineupNear(pos)

		if not self.highlightVisitor:
			self.highlightGroup.remove( self.highlight )
			return

		if hasattr( self.highlightVisitor, 'device' ):
			self.highlight.image = self.greenCircle
		else:
			self.highlight.image = self.redCircle

		self.highlight.rect.center = self.highlightVisitor.rect.center
		self.highlightGroup.add( self.highlight )

	#---------------------------------------------------------------------
	def AddVisitor(self, visitor, pos=None):
		if hasattr( visitor, "device" ):
			self.greenVisitorGroup.add( visitor )
		else:
			self.redVisitorGroup.add( visitor )
		self.parkGeography.PlaceVisitor( visitor, pos )
		allobjects.allVisitors.add( visitor )

	#---------------------------------------------------------------------
	def DoVisitorEntries( self ):
		if len( allobjects.allVisitors ) >= simulation.capacity:
			return

		totalVisitors = simulation.getEntryRate( allobjects.timeOfDay )
		#print "entering ", totalVisitors
		numGreen = int(totalVisitors*simulation.deviceAcceptanceRate)
		if not allobjects.thousandCounter%2:
			numGreen += 1
		numRed = totalVisitors - numGreen
		pos = self.parkGeography.GetEntryPoint()
		for i in xrange( numGreen ):
			device = allobjects.server.NewDevice()
			if device:
				self.deviceGroup.add( device )
				newGuy = GuidedVisitor( device )
			else:
				newGuy = UnGuidedVisitor()
			self.AddVisitor( newGuy, pos )
		for i in xrange( numRed ):
			newGuy = UnGuidedVisitor()
			self.AddVisitor( newGuy, pos )

	#---------------------------------------------------------------------
	def DoVisitorExits( self ):
		if not allobjects.allVisitors:
			return
		totalVisitors = simulation.getExitRate( allobjects.timeOfDay )
		for i in xrange( totalVisitors ):
			allobjects.allVisitors.sprites()[i].LeaveThePark()

	#---------------------------------------------------------------------
	def RemoveVisitor(self, visitor):
		visitor.kill()

	#---------------------------------------------------------------------
	def FindVisitorNear(self,pos,radius=4):
		for v in self.greenVisitorGroup.sprites():
			if abs( v.rect.centerx - pos[0] ) < radius \
			  and abs( v.rect.centery - pos[1] ) < radius:
				return v
		for v in self.redVisitorGroup.sprites():
			if abs( v.rect.centerx - pos[0] ) < radius \
			  and abs( v.rect.centery - pos[1] ) < radius:
			  	return v
		return None

	#---------------------------------------------------------------------
	def HighlightRideNear(self,pos):
		events.Fire( "UnHighlightRide" )

		for r in self.rideGroup.sprites():
			if r.rect.collidepoint( pos ):
				events.Fire( "HighlightRide", r )
				return

	#---------------------------------------------------------------------
	def HighlightLineupNear(self,pos):
		events.Fire( "UnHighlightLineup" )

		for l in self.lineupGroup.sprites():
			if l.rect.collidepoint( pos ):
				events.Fire( "HighlightLineup", l )
				return

	#---------------------------------------------------------------------
	def SignalKey( self, event, remainingEvents ):
		pass

	#---------------------------------------------------------------------
	def Click( self, pos ):
		pass
	#---------------------------------------------------------------------
	def MouseOver( self, event ):
		pass
		
	#---------------------------------------------------------------------
	def DoGraphics( self, screen, display, timeChange ):
		if self.justToggledShowRed  \
		   or self.justToggledShowGreen \
		   or self.justToggledShowServer:
			screen.blit( self.bgImage, self.boundRect )
			display.flip()
			self.justToggledShowRed = False
			self.justToggledShowGreen = False
			self.justToggledShowServer = False
		else:
			bg = self.bgImage

			self.rideGroup.clear(screen, self.bgImage)
			self.lineupGroup.clear(screen, self.bgImage)
			self.highlightGroup.clear( screen, self.bgImage )
			if self.showRed:
				self.redVisitorGroup.clear( screen, bg )
			if self.showGreen:
				self.greenVisitorGroup.clear( screen, bg )
			if self.showServer:
				self.deviceGroup.clear(screen, self.bgImage )

		self.UpdateHighlightGroup()
		if not allobjects.thousandCounter % 30:
			self.DoVisitorEntries()
			self.DoVisitorExits()

		if not self.paused:
			allobjects.timeOfDay += simulation.speed
			self.carGroup.update()
			self.rideGroup.update()
			self.lineupGroup.update()
			self.redVisitorGroup.update()
			self.greenVisitorGroup.update()
			if self.showServer:
				self.deviceGroup.update()

		changedRects =  self.highlightGroup.draw(screen)
		changedRects += self.rideGroup.draw(screen)
		changedRects += self.carGroup.draw(screen)
		changedRects += self.lineupGroup.draw(screen)
		if self.showRed:
			changedRects += self.redVisitorGroup.draw(screen)
		if self.showGreen:
			changedRects += self.greenVisitorGroup.draw(screen)
		if self.showServer:
			changedRects += self.deviceGroup.draw(screen)

		display.update( changedRects )
Beispiel #2
0
def main():
    """this function is called when the program starts.
	   it initializes everything it needs, then runs in
	   a loop until the function returns."""
    #Initialize Everything
    global screen
    screen = None
    pygame.init()
    screen = pygame.display.set_mode(RESOLUTION)
    pygame.display.set_caption('Example Poutine Window')

    #Create The Backgound
    bg = pygame.Surface(RESOLUTION)
    bg.fill(BGCOLOR)

    #Display The Background
    screen.blit(bg, (0, 0))
    pygame.display.flip()

    #Prepare Game Objects
    clock = pygame.time.Clock()

    label = LabelSprite('foo')
    label.rect.move_ip(100, 100)

    #this will be the callback function of the button
    def buttonWasClicked():
        print "button clicked"

    button = ButtonSprite('bar', None, buttonWasClicked)
    button.rect.move_ip(100, 300)

    tEntry = TextEntrySprite('textentry')
    tEntry.rect.move_ip(100, 400)

    allWidgets = RenderUpdates()
    allWidgets.add(label)
    allWidgets.add(button)
    allWidgets.add(tEntry)

    #Main Loop
    while 1:
        timeChange = clock.tick(40)

        #Handle Input Events
        oldEvents = []
        remainingEvents = pygame.event.get()
        for event in remainingEvents:
            oldEvents.append(remainingEvents.pop(0))
            if event.type == QUIT:
                return
            elif event.type == KEYDOWN and event.key == K_ESCAPE:
                return

            elif event.type == KEYDOWN:
                key = event.unicode.encode("ascii")
                if key and key in string.printable:
                    for s in allWidgets.sprites():
                        if hasattr(s, "OnKeyPressed"):
                            s.OnKeyPressed(key)
                else:
                    key = event.key
                    for s in allWidgets.sprites():
                        if hasattr(s, "OnMetaPressed"):
                            s.OnMetaPressed(key)
            elif event.type == MOUSEMOTION:
                for sprite in allWidgets.sprites():
                    if hasattr(sprite, "OnMouseMove"):
                        sprite.OnMouseMove(event.pos)
            elif event.type == MOUSEBUTTONDOWN:
                for sprite in allWidgets.sprites():
                    if hasattr(sprite, "OnMouseClick"):
                        sprite.OnMouseClick(event.pos)

    #Draw Everything
        allWidgets.clear(screen, bg)
        allWidgets.update()
        changedRects = allWidgets.draw(screen)
        pygame.display.update(changedRects)

#Game Over
    pygame.quit()
Beispiel #3
0
class GameWorld:
    """Hold Game World objects

       Initialize display
       >>> import pygame as pygame
       >>> import random
       >>> from widget import *
       >>> randomizer = Random()

       Create a gameworld
       >>> g = GameWorld(randomizer)
       >>> s = pygame.surface.Surface((30,30))
       >>> w = Widget(s, (0,0,30,30), (0,0))

       Add and test bomberman to world
       >>> g.appendBomber(w)
       >>> g.bomberGroup
       <RenderUpdates(1 sprites)>

       Add and test an immutable to world
       >>> w1 = Widget(s, (0,0,30,30), (0,0))
       >>> g.appendImmutable(w1)
       >>> g.immutableGroup
       <RenderUpdates(1 sprites)>

       Add another bomberman to world
       >>> p2 = Widget(s, (100,100, 30,30), (0,0))
       >>> g.appendBomber(p2)

       Add a bomb to the game world
       >>> bomb = Widget(s, (100,100,30,30), (0,0))
       >>> g.appendBomb(bomb)

       Check the number of objects in game world
       >>> g.universalGroup
       <RenderUpdates(4 sprites)>

       Detonate bomb in game world
       >>> g.detonateBomb(bomb)
       >>> g.bombGroup
       <RenderUpdates(0 sprites)>
       >>> g.universalGroup
       <RenderUpdates(3 sprites)>

       Add bomb to populatedBombGroup
       >>> g.appendPopulatedBomb(bomb)
       >>> g.populatedBombGroup
       <RenderUpdates(1 sprites)>

       Add an explosion to game world
       >>> explosion = Widget(s, (0,0,30,30),(0,0))
       >>> g.appendExplosion(explosion)
       >>> g.explosionGroup
       <RenderUpdates(1 sprites)>

       Add a power up to game world
       >>> powerup = Widget(s,(0,0,30,30),(0,0))
       >>> g.appendPowerUp(powerup)
       >>> g.powerUpGroup
       <RenderUpdates(1 sprites)>

       Remove power up from game world
       >>> g.removePowerUp(powerup)
       >>> g.powerUpGroup
       <RenderUpdates(0 sprites)>

       Test bomberstrafe algorithm
       >>> g.bomberStrafe([98, 100])
       (98, 100)

       >>> g.bomberStrafe([90, 100])
       (80, 100)

       >>> g.bomberStrafe([98, 90])
       (98, 80)

       >>> g.bomberStrafe([139, 140])
       (144, 144)

       Test worldWrap
       >>> g.mapColumns = 19
       >>> bomb = Bomb(s, (0,0,30,30),3,3,3,(0,0))
       >>> bomb.beingPunched = 1
       >>> g.appendBomb(bomb)
       >>> bomb.setPosition((10,100))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (624, 100)

       >>> bomb.setPosition((630,100))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (16, 100)

       >>> g.mapRows = 19
       >>> bomb.setPosition((100, 10))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (100, 656)

       >>> bomb.setPosition((100, 660))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (100, 48)

       Test for new restart game state
       >>> g.cleanState()
       >>> g.populatedBombGroup
       <RenderUpdates(0 sprites)>
       >>> g.bombGroup
       <RenderUpdates(0 sprites)>
       >>> g.bomberGroup
       <RenderUpdates(0 sprites)>
       >>> g.explosionGroup
       <RenderUpdates(0 sprites)>
       >>> g.immutableGroup
       <RenderUpdates(0 sprites)>
       >>> g.powerUpGroup
       <RenderUpdates(0 sprites)>
       >>> g.mutableGroup
       <RenderUpdates(0 sprites)>
       >>> g.universalGroup
       <RenderUpdates(0 sprites)>
       >>> g.dirtyGroup
       <RenderUpdates(0 sprites)>
       >>> g.flyOverGroup
       <RenderUpdates(0 sprites)>

       >>> g.update()
    """
    def __init__(self, randomizer):
        self.randomizer = randomizer

        # Set title
        pygame.display.set_caption("Pybomber")

        # Setup screen
        self.screen = pygame.display.get_surface()

        # Create sprite groups
        self.populatedBombGroup = SpriteGroup()
        self.bombGroup = SpriteGroup()
        self.bomberGroup = SpriteGroup()
        self.explosionGroup = SpriteGroup()
        self.immutableGroup = SpriteGroup()
        self.powerUpGroup = SpriteGroup()
        self.mutableGroup = SpriteGroup()
        self.universalGroup = SpriteGroup()  # For drawing everything.
        self.dirtyGroup = SpriteGroup()
        self.flyOverGroup = SpriteGroup()
        # Load a background
        self.background = pygame.image.load(BACKGROUND).convert()
        self.map = None

        # Draw background on screen
        self.screen.blit(self.background, ((0, 0), RESOLUTION))

        # Number of rows and colums in the current map.
        self.mapRows = 0
        self.mapColumns = 0

    def cleanState(self):
        pygame.display.set_caption("Pybomber")
        self.screen.blit(self.background, ((0, 0), RESOLUTION))

        self.populatedBombGroup = SpriteGroup()
        self.bombGroup = SpriteGroup()
        self.bomberGroup = SpriteGroup()
        self.explosionGroup = SpriteGroup()
        self.immutableGroup = SpriteGroup()
        self.powerUpGroup = SpriteGroup()
        self.mutableGroup = SpriteGroup()
        self.universalGroup = SpriteGroup()  # For drawing everything.
        self.dirtyGroup = SpriteGroup()
        self.groundGroup = SpriteGroup()
        self.flyOverGroup = SpriteGroup()
        self.mapRows = 0
        self.mapColumns = 0
        self.curWidgetID = 0

    def appendBomb(self, sprite):
        self.bombGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def flyBomb(self, bombSprite):
        self.groundGroup.remove(bombSprite)

    def groundBomb(self, bomb):
        self.groundGroup.add(bomb)

    def appendPopulatedBomb(self, sprite):
        self.populatedBombGroup.add(sprite)

    def appendExplosion(self, sprite):
        self.explosionGroup.add(sprite)
        self.universalGroup.add(sprite)

    def appendImmutable(self, sprite):
        self.flyOverGroup.add(sprite)
        self.immutableGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def appendBomber(self, sprite):
        self.bomberGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def appendPowerUp(self, sprite):
        self.powerUpGroup.add(sprite)
        self.universalGroup.add(sprite)

    def appendMutable(self, sprite):
        self.flyOverGroup.add(sprite)
        self.mutableGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def detonateBomb(self, bomb):
        """Detonate bomb"""
        bomb.kill()

    def removeExplosion(self, explosion):
        """Remove explosion from all groups."""
        self.explosionGroup.remove(explosion)
        self.universalGroup.remove(explosion)

    def removeBomber(self, bomber):
        """Remove explosion from all groups."""
        self.bomberGroup.remove(bomber)
        self.groundGroup.remove(bomber)
        self.universalGroup.remove(bomber)

    def removePopulatedBomb(self, sprite):
        self.populatedBombGroup.remove(sprite)

    def removePowerUp(self, powerUp):
        """Remove powerUp from all groups."""
        self.powerUpGroup.remove(powerUp)
        self.universalGroup.remove(powerUp)

    def bomberStrafe(self, bomberPos):
        """Take bomberman's position and find the nearest grid square."""
        posX = 0
        posY = 0

        # Get the location between grid.
        posBetweenGridX = (bomberPos[X] - XOFFSET) % BLOCKSIZE[X]
        posBetweenGridY = (bomberPos[Y] - YOFFSET) % BLOCKSIZE[Y]

        # If location is less than 1/3 way, move back,
        # if over 2/3, move forward.
        inMiddleX = (BLOCKSIZE[X] / 3, 2 * BLOCKSIZE[X] / 3)
        inMiddleY = (BLOCKSIZE[Y] / 3, 2 * BLOCKSIZE[Y] / 3)

        # Fix x
        if posBetweenGridX <= inMiddleX[0]:
            posX = bomberPos[X] - posBetweenGridX
        # Please leave the 0 and 1, they don't mean X and Y.
        elif(posBetweenGridX > inMiddleX[0] and\
             posBetweenGridX < inMiddleX[1]):
            posX = bomberPos[X]
        else:  # > inMiddle[1]
            posX = bomberPos[X] + (BLOCKSIZE[X] - posBetweenGridX)

        # Fix y
        if posBetweenGridY <= inMiddleY[0]:
            posY = bomberPos[Y] - posBetweenGridY
        elif posBetweenGridY > inMiddleY[0] and\
             posBetweenGridY < inMiddleY[1]:
            posY = bomberPos[Y]
        else:  # > inMiddleY[1]
            posY = bomberPos[Y] + (BLOCKSIZE[Y] - posBetweenGridY)

        return posX, posY

    def snapToGrid(self, pos):
        """Take position and find the nearest grid square."""
        posX = posY = 0
        # Get the location between grid.
        posBetweenGridX = (pos[0] - XOFFSET) % BLOCKSIZE[0]
        posBetweenGridY = (pos[1] - YOFFSET) % BLOCKSIZE[1]
        # If location is less than 1/2 way, move back, else move forward.
        if posBetweenGridX <= BLOCKSIZE[X] / 2:
            posX = pos[X] - posBetweenGridX
        else:
            posX = pos[X] + (BLOCKSIZE[X] - posBetweenGridX)
        if posBetweenGridY <= BLOCKSIZE[Y] / 2:
            posY = pos[Y] - posBetweenGridY
        else:
            posY = pos[Y] + (BLOCKSIZE[Y] - posBetweenGridY)
        return posX, posY

    def worldWrap(self, bomb):
        """Send bomb to other side of world if it was punched out of bounds
        """
        x, y = bomb.getPosition()
        if bomb.beingPunched:
            # Check top
            if y < YOFFSET:
                bomb.setPosition((x, self.mapRows * BLOCKSIZE[Y] + YOFFSET))
            # Check bottom
            if y > self.mapRows * BLOCKSIZE[Y] + YOFFSET:
                bomb.setPosition((x, YOFFSET))
            # Check left
            if x < XOFFSET:
                bomb.setPosition((self.mapColumns * BLOCKSIZE[X] + XOFFSET, y))
            # Check right
            if x > self.mapColumns * BLOCKSIZE[X] + XOFFSET:
                bomb.setPosition((XOFFSET, y))

    def update(self):
        """Update sprites in enviornment class

           Attempt to move each sprite, undoing movements
           that produce collisions.
        """
        explosionsToSort = self.explosionGroup.sprites()
        explosionsToSort.sort(lambda x, y: cmp(str(x), str(y)))
        for explosion in explosionsToSort:
            debug(str(explosion.rect.topleft) + " ")
            explosion.update()

        # Update players
        bombersToSort = self.bomberGroup.sprites()
        bombersToSort.sort(lambda x, y: cmp(x.id, y.id))
        for bomber in bombersToSort:
            bomber.update()

        # Update bombs
        bombsToSort = self.bombGroup.sprites()
        bombsToSort.sort(lambda x, y: cmp(x.id, y.id))
        for bomb in bombsToSort:
            bomb.update()

        # Update power-ups
        powerupSorted = self.powerUpGroup.sprites()
        powerupSorted.sort(lambda x, y: cmp(x.id, y.id))
        for powerup in powerupSorted:
            powerup.update()
Beispiel #4
0
class GameView(View):
	def __init__( self, screen, display ):
		self.screen = screen
		self.screenRect = screen.get_rect()
		self.display = display
		self.model = None
		self.currentTime = 0

		self.bgImage = load_png( 'bg_game.png' )

		self.hiGroup = RenderUpdates()
		self.lowGroup = RenderUpdates()
		self.viewOnlyGroup = RenderUpdates()
		self.bubbleGroup = RenderUpdates()

		self.ins_spin = None
		self.ins_press = None
		self.quitButton = None
		self.squeezePrompt = None

		self.groups = [self.lowGroup, self.bubbleGroup, self.hiGroup, self.viewOnlyGroup]
		self.locks = []

		self.stripeOrder = ['violet','blue','green',
		                    'yellow','orange','red']
		self.stripeHeights = {
		                     'violet': 233,
		                     'blue':   189, 
		                     'green':  136,
		                     'yellow': 85,
		                     'orange': 44,
		                     'red':    11,
		                    }
		self.heaterRects = { 
		                    'green':  Rect ( 160, 470, 80, 100 ),
		                    'blue':   Rect ( 265, 470, 80, 100 ),
		                    'violet': Rect ( 370, 470, 80, 100 ),
		                    'red':    Rect ( 475, 470, 80, 100 ),
		                    'orange': Rect ( 580, 470, 80, 100 ),
		                    'yellow': Rect ( 685, 470, 80, 100 ),
		}


		self.purseStatusbars = []

		controller = mvcState.GetController()
		controller.gameEventListeners.append( self )

	def ModelStarted( self, model ):
		self.quitButton = QuitButton()
		self.quitButton.rect.topleft = (10, 530)
		self.viewOnlyGroup.add( self.quitButton )

		self.ins_spin = InstructionSpin()
		self.ins_spin.rect.topleft = (380, 440)
		self.viewOnlyGroup.add( self.ins_spin )

		View.ModelStarted( self, model )
		heater = self.model.manualHeater
		heater.rect.topleft = self.heaterRects['red'].topleft
		self.hiGroup.add( heater )

		cloud = self.model.cloud
		cloud.rect.topleft = (10,40)
		self.hiGroup.add( cloud )
		
		monWid = self.model.playerMoney
		monWid.rect.topleft = (10,490)
		self.hiGroup.add( monWid )

		bladder = self.model.bladder
		bladder.rect.topleft = (410,378)
		bladder.FixBottom( bladder.rect.midbottom )
		self.hiGroup.add( bladder )

		self.squeezePrompt = SqueezePrompt( bladder )
		self.squeezePrompt.rect.topleft = (190,340)

		m = self.model
		stripes = [m.violetstripe, m.bluestripe, m.greenstripe,
		           m.yellowstripe, m.orangestripe, m.redstripe ]
		for i in range( len(stripes) ):
			name = stripes[i].name
			stripes[i].rect.topleft = (146,self.stripeHeights[name])
			self.lowGroup.add( stripes[i] )

		for i in range( len(m.colorPurses) ):
			cName = m.colorPurses[i].colorName
			dimensions = self.heaterRects[cName].move(0,0)
			dimensions.move_ip(0,100)
			dimensions.height = 10
			sb = StatusBar( m.colorPurses[i], 
			         dimensions,
			         outlineImg='sb_outline.png',
			         attrName='amount', 
			         fullAmt=m.colorPurses[i].capacity,
			         innerColor=COLORS[cName]
			        )
			self.purseStatusbars.append( sb )
			self.lowGroup.add( sb )


	def OnBubbleLaunch( self, centerx ):
		#log.debug( 'bubble birth' )
		if self.ins_spin:
			self.ins_spin.kill()
			self.ins_spin = None

		bubble = Bubble( 438 )
		minX = 140
		maxX = 790
		xpos = int(rng.normalvariate( 0,50 )) + centerx
		xpos = min( xpos, maxX )
		xpos = max( xpos, minX )
		bubble.rect.x = xpos
		bubble.rect.bottom = 470
		self.bubbleGroup.add( bubble )

	def Update( self, timeChange ):
		self.viewOnlyGroup.update( timeChange )
		self.bubbleGroup.update( timeChange )

		self.currentTime += timeChange
		#twoSecondsAgo = self.currentTime - 2000
		#halfSecondAgo = self.currentTime - 500

		heaterRange = [444,530]

		for sb in self.purseStatusbars:
			sb.update()

	def OnBladderShoot( self, power, height ):
		if self.ins_press:
			self.ins_press.kill()
		if height > 3:
			gey = Geyser( "tall" )
		else:
			gey = Geyser( "short" )
		colorName = self.stripeOrder[height]
		gey.rect.midtop = (450, self.stripeHeights[colorName])
		self.viewOnlyGroup.add( gey )

		self.viewOnlyGroup.add( self.squeezePrompt )
		#print len(self.viewOnlyGroup)

	def OnBladderShootStop( self ):
		self.viewOnlyGroup.remove( self.squeezePrompt )

	def OnBladderVent( self, power, height ):
		if height > 3:
			gey = Geyser( "tall" )
		else:
			gey = Geyser( "short" )
		colorName = self.stripeOrder[height]
		gey.rect.midtop = (450, self.stripeHeights[colorName])
		self.viewOnlyGroup.add( gey )

	def OnDropBirth( self, drop ):
		self.lowGroup.add( drop )

	def OnStripeHitMaxOpacity(self, stripe):
		yPos = self.stripeHeights[stripe.name]+4
		if yPos in [lock.rect.top for lock in self.locks]:
			#log.debug( 'already have that lock' )
			return
		lock = Lock()
		lock.rect.topleft = (111, self.stripeHeights[stripe.name]+4 )
		self.hiGroup.add( lock )
		self.locks.append( lock )

	def OnHeaterBirth( self, heater ):
		switch= { SolarHeater:'violet',
		          WaterWheelHeater:'blue',
		          WindHeater:'green',
		          FireHeater:'yellow',
		          NuclearHeater:'orange',
		}
		klass = heater.__class__
		heater.rect.topleft = self.heaterRects[switch[klass]].topleft
		self.hiGroup.add( heater )

	def OnBladderVentingImminent( self ):
		if self.ins_press == None:
			self.ins_press = InstructionPress()
			self.ins_press.rect.topleft = (560, 300)
			self.viewOnlyGroup.add( self.ins_press )

	def Kill( self ):
		controller = mvcState.GetController()
		controller.gameEventListeners.remove( self )
		for s in self.viewOnlyGroup.sprites():
			s.kill()
		for s in self.bubbleGroup.sprites():
			s.kill()

	def OnUserQuit( self ):
		self.Kill()

	def OnWin( self, time, money ):
		self.Kill()
Beispiel #5
0
def main():
	"""this function is called when the program starts.
	   it initializes everything it needs, then runs in
	   a loop until the function returns."""
#Initialize Everything
	global screen
	screen = None
	pygame.init()
	screen = pygame.display.set_mode(RESOLUTION)
	pygame.display.set_caption('Example Poutine Window')

#Create The Backgound
	bg = pygame.Surface( RESOLUTION )
	bg.fill( BGCOLOR )

#Display The Background
	screen.blit(bg, (0, 0))
	pygame.display.flip()

#Prepare Game Objects
	clock = pygame.time.Clock()

	label = LabelSprite( 'foo' )
	label.rect.move_ip( 100, 100 )
	#this will be the callback function of the button
	def buttonWasClicked():
		print "button clicked"
	button = ButtonSprite( 'bar', None, buttonWasClicked )
	button.rect.move_ip( 100, 300 )

	tEntry = TextEntrySprite('textentry')
	tEntry.rect.move_ip( 100, 400 )

	allWidgets = RenderUpdates()
	allWidgets.add( label )
	allWidgets.add( button )
	allWidgets.add( tEntry )



#Main Loop
	while 1:
		timeChange = clock.tick(40)

	#Handle Input Events
		oldEvents = []
		remainingEvents = pygame.event.get()
		for event in remainingEvents:
			oldEvents.append( remainingEvents.pop(0) )
			if event.type == QUIT:
				return
			elif event.type == KEYDOWN and event.key == K_ESCAPE:
				return

			elif event.type == KEYDOWN:
				key = event.unicode.encode("ascii")
				if key and key in string.printable:
					for s in  allWidgets.sprites():
						if hasattr( s, "OnKeyPressed" ):
							s.OnKeyPressed( key )
				else:
					key = event.key
					for s in  allWidgets.sprites():
						if hasattr( s, "OnMetaPressed"):
							s.OnMetaPressed( key )
			elif event.type == MOUSEMOTION:
				for sprite in  allWidgets.sprites():
					if hasattr( sprite, "OnMouseMove" ):
						sprite.OnMouseMove( event.pos )
			elif event.type == MOUSEBUTTONDOWN:
				for sprite in  allWidgets.sprites():
					if hasattr( sprite, "OnMouseClick" ):
						sprite.OnMouseClick( event.pos )

	#Draw Everything
		allWidgets.clear( screen, bg )
		allWidgets.update( )
		changedRects =  allWidgets.draw(screen)
		pygame.display.update( changedRects )


#Game Over
	pygame.quit()
Beispiel #6
0
class GameWorld:
    """Hold Game World objects

       Initialize display
       >>> import pygame as pygame
       >>> import random
       >>> from widget import *
       >>> randomizer = Random()

       Create a gameworld
       >>> g = GameWorld(randomizer)
       >>> s = pygame.surface.Surface((30,30))
       >>> w = Widget(s, (0,0,30,30), (0,0))

       Add and test bomberman to world
       >>> g.appendBomber(w)
       >>> g.bomberGroup
       <RenderUpdates(1 sprites)>

       Add and test an immutable to world
       >>> w1 = Widget(s, (0,0,30,30), (0,0))
       >>> g.appendImmutable(w1)
       >>> g.immutableGroup
       <RenderUpdates(1 sprites)>

       Add another bomberman to world
       >>> p2 = Widget(s, (100,100, 30,30), (0,0))
       >>> g.appendBomber(p2)

       Add a bomb to the game world
       >>> bomb = Widget(s, (100,100,30,30), (0,0))
       >>> g.appendBomb(bomb)

       Check the number of objects in game world
       >>> g.universalGroup
       <RenderUpdates(4 sprites)>

       Detonate bomb in game world
       >>> g.detonateBomb(bomb)
       >>> g.bombGroup
       <RenderUpdates(0 sprites)>
       >>> g.universalGroup
       <RenderUpdates(3 sprites)>

       Add bomb to populatedBombGroup
       >>> g.appendPopulatedBomb(bomb)
       >>> g.populatedBombGroup
       <RenderUpdates(1 sprites)>

       Add an explosion to game world
       >>> explosion = Widget(s, (0,0,30,30),(0,0))
       >>> g.appendExplosion(explosion)
       >>> g.explosionGroup
       <RenderUpdates(1 sprites)>

       Add a power up to game world
       >>> powerup = Widget(s,(0,0,30,30),(0,0))
       >>> g.appendPowerUp(powerup)
       >>> g.powerUpGroup
       <RenderUpdates(1 sprites)>

       Remove power up from game world
       >>> g.removePowerUp(powerup)
       >>> g.powerUpGroup
       <RenderUpdates(0 sprites)>

       Test bomberstrafe algorithm
       >>> g.bomberStrafe([98, 100])
       (98, 100)

       >>> g.bomberStrafe([90, 100])
       (80, 100)

       >>> g.bomberStrafe([98, 90])
       (98, 80)

       >>> g.bomberStrafe([139, 140])
       (144, 144)

       Test worldWrap
       >>> g.mapColumns = 19
       >>> bomb = Bomb(s, (0,0,30,30),3,3,3,(0,0))
       >>> bomb.beingPunched = 1
       >>> g.appendBomb(bomb)
       >>> bomb.setPosition((10,100))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (624, 100)

       >>> bomb.setPosition((630,100))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (16, 100)

       >>> g.mapRows = 19
       >>> bomb.setPosition((100, 10))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (100, 656)

       >>> bomb.setPosition((100, 660))
       >>> g.worldWrap(bomb)
       >>> bomb.getPosition()
       (100, 48)

       Test for new restart game state
       >>> g.cleanState()
       >>> g.populatedBombGroup
       <RenderUpdates(0 sprites)>
       >>> g.bombGroup
       <RenderUpdates(0 sprites)>
       >>> g.bomberGroup
       <RenderUpdates(0 sprites)>
       >>> g.explosionGroup
       <RenderUpdates(0 sprites)>
       >>> g.immutableGroup
       <RenderUpdates(0 sprites)>
       >>> g.powerUpGroup
       <RenderUpdates(0 sprites)>
       >>> g.mutableGroup
       <RenderUpdates(0 sprites)>
       >>> g.universalGroup
       <RenderUpdates(0 sprites)>
       >>> g.dirtyGroup
       <RenderUpdates(0 sprites)>
       >>> g.flyOverGroup
       <RenderUpdates(0 sprites)>

       >>> g.update()
    """

    def __init__(self, randomizer):
        self.randomizer = randomizer

        # Set title
        pygame.display.set_caption("Pybomber")

        # Setup screen
        self.screen = pygame.display.get_surface()

        # Create sprite groups
        self.populatedBombGroup = SpriteGroup()
        self.bombGroup = SpriteGroup()
        self.bomberGroup = SpriteGroup()
        self.explosionGroup = SpriteGroup()
        self.immutableGroup = SpriteGroup()
        self.powerUpGroup = SpriteGroup()
        self.mutableGroup = SpriteGroup()
        self.universalGroup = SpriteGroup() # For drawing everything.
        self.dirtyGroup = SpriteGroup()
        self.flyOverGroup = SpriteGroup()
        # Load a background
        self.background = pygame.image.load(BACKGROUND).convert()
        self.map = None

        # Draw background on screen
        self.screen.blit(self.background, ((0, 0), RESOLUTION))

        # Number of rows and colums in the current map.
        self.mapRows = 0
        self.mapColumns = 0

    def cleanState(self):
        pygame.display.set_caption("Pybomber")
        self.screen.blit(self.background, ((0, 0), RESOLUTION))

        self.populatedBombGroup = SpriteGroup()
        self.bombGroup = SpriteGroup()
        self.bomberGroup = SpriteGroup()
        self.explosionGroup = SpriteGroup()
        self.immutableGroup = SpriteGroup()
        self.powerUpGroup = SpriteGroup()
        self.mutableGroup = SpriteGroup()
        self.universalGroup = SpriteGroup() # For drawing everything.
        self.dirtyGroup = SpriteGroup()
        self.groundGroup = SpriteGroup()
        self.flyOverGroup = SpriteGroup()
        self.mapRows = 0
        self.mapColumns = 0
        self.curWidgetID = 0

    def appendBomb(self, sprite):
        self.bombGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def flyBomb(self, bombSprite):
        self.groundGroup.remove(bombSprite)

    def groundBomb(self, bomb):
        self.groundGroup.add(bomb)

    def appendPopulatedBomb(self, sprite):
        self.populatedBombGroup.add(sprite)

    def appendExplosion(self, sprite):
        self.explosionGroup.add(sprite)
        self.universalGroup.add(sprite)

    def appendImmutable(self, sprite):
        self.flyOverGroup.add(sprite)
        self.immutableGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def appendBomber(self, sprite):
        self.bomberGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def appendPowerUp(self, sprite):
        self.powerUpGroup.add(sprite)
        self.universalGroup.add(sprite)

    def appendMutable(self, sprite):
        self.flyOverGroup.add(sprite)
        self.mutableGroup.add(sprite)
        self.universalGroup.add(sprite)
        self.groundGroup.add(sprite)

    def detonateBomb(self, bomb):
        """Detonate bomb"""
        bomb.kill()

    def removeExplosion(self, explosion):
        """Remove explosion from all groups."""
        self.explosionGroup.remove(explosion)
        self.universalGroup.remove(explosion)

    def removeBomber(self, bomber):
        """Remove explosion from all groups."""
        self.bomberGroup.remove(bomber)
        self.groundGroup.remove(bomber)
        self.universalGroup.remove(bomber)

    def removePopulatedBomb(self, sprite):
        self.populatedBombGroup.remove(sprite)

    def removePowerUp(self, powerUp):
        """Remove powerUp from all groups."""
        self.powerUpGroup.remove(powerUp)
        self.universalGroup.remove(powerUp)

    def bomberStrafe(self, bomberPos):
        """Take bomberman's position and find the nearest grid square."""
        posX = 0
        posY = 0

        # Get the location between grid.
        posBetweenGridX = (bomberPos[X]-XOFFSET) % BLOCKSIZE[X]
        posBetweenGridY = (bomberPos[Y]-YOFFSET) % BLOCKSIZE[Y]

        # If location is less than 1/3 way, move back,
        # if over 2/3, move forward.
        inMiddleX = (BLOCKSIZE[X]/3,2 * BLOCKSIZE[X]/3)
        inMiddleY = (BLOCKSIZE[Y]/3,2 * BLOCKSIZE[Y]/3)

        # Fix x
        if posBetweenGridX <= inMiddleX[0]:
            posX = bomberPos[X] - posBetweenGridX
        # Please leave the 0 and 1, they don't mean X and Y.
        elif(posBetweenGridX > inMiddleX[0] and\
             posBetweenGridX < inMiddleX[1]):
            posX = bomberPos[X]
        else: # > inMiddle[1]
            posX = bomberPos[X] + (BLOCKSIZE[X] - posBetweenGridX)

        # Fix y
        if posBetweenGridY <= inMiddleY[0]:
            posY = bomberPos[Y] - posBetweenGridY
        elif posBetweenGridY > inMiddleY[0] and\
             posBetweenGridY < inMiddleY[1]:
            posY = bomberPos[Y]
        else: # > inMiddleY[1]
            posY = bomberPos[Y] + (BLOCKSIZE[Y] - posBetweenGridY)

        return posX, posY

    def snapToGrid(self, pos):
        """Take position and find the nearest grid square."""
        posX = posY = 0
        # Get the location between grid.
        posBetweenGridX = (pos[0]-XOFFSET) % BLOCKSIZE[0]
        posBetweenGridY = (pos[1]-YOFFSET) % BLOCKSIZE[1]
        # If location is less than 1/2 way, move back, else move forward.
        if posBetweenGridX <= BLOCKSIZE[X]/2:
            posX = pos[X] - posBetweenGridX
        else:
            posX = pos[X] + (BLOCKSIZE[X] - posBetweenGridX)
        if posBetweenGridY <= BLOCKSIZE[Y]/2:
            posY = pos[Y] - posBetweenGridY
        else:
            posY = pos[Y] + (BLOCKSIZE[Y] - posBetweenGridY)
        return posX, posY

    def worldWrap(self, bomb):
        """Send bomb to other side of world if it was punched out of bounds
        """
        x, y = bomb.getPosition()
        if bomb.beingPunched:
            # Check top
            if y < YOFFSET:
                bomb.setPosition((x, self.mapRows*BLOCKSIZE[Y] + YOFFSET))
            # Check bottom
            if y > self.mapRows*BLOCKSIZE[Y] + YOFFSET:
                bomb.setPosition((x, YOFFSET))
            # Check left
            if x < XOFFSET:
                bomb.setPosition((self.mapColumns*BLOCKSIZE[X] + XOFFSET, y))
            # Check right
            if x > self.mapColumns*BLOCKSIZE[X] + XOFFSET:
                bomb.setPosition((XOFFSET, y))

    def update(self):
        """Update sprites in enviornment class

           Attempt to move each sprite, undoing movements
           that produce collisions.
        """
        explosionsToSort = self.explosionGroup.sprites()
        explosionsToSort.sort(lambda x, y: cmp(str(x), str(y)))
        for explosion in explosionsToSort:
            debug(str(explosion.rect.topleft) + " ")
            explosion.update()

        # Update players
        bombersToSort = self.bomberGroup.sprites()
        bombersToSort.sort(lambda x, y: cmp(x.id, y.id))
        for bomber in bombersToSort:
            bomber.update()

        # Update bombs
        bombsToSort = self.bombGroup.sprites()
        bombsToSort.sort(lambda x, y: cmp(x.id, y.id))
        for bomb in bombsToSort:
            bomb.update()

        # Update power-ups
        powerupSorted = self.powerUpGroup.sprites()
        powerupSorted.sort(lambda x, y: cmp(x.id, y.id))
        for powerup in powerupSorted:
            powerup.update()
Beispiel #7
0
class EntityMaster:

    bee_ratio = 1 / 5

    def __init__(self, initial_hives: int, default_bees_per_hive: int,
                 play_area_dimensions: int(), flower_spawn_strategy: str,
                 hive_spawn_strategy: str, flower_num: int):

        self.bees = RenderUpdates()
        self.hives = RenderUpdates()
        self.plants = RenderUpdates()
        self.flowers = RenderUpdates()
        self.ui_elements = RenderUpdates()

        self.flower_database = {}
        self.play_area = play_area_dimensions

        self.sim_paused = False

        self.grow_flora(play_area_dimensions)
        self.load_flower_data(
            get_flower_spawn_strategy(flower_spawn_strategy,
                                      play_area_dimensions, flower_num))
        self.populate_hives(
            get_hive_spawn_strategy(hive_spawn_strategy, initial_hives,
                                    play_area_dimensions, self.flowers),
            default_bees_per_hive)
        self.clean_up_spawn()

    @property
    def bee_population(self):
        """
        :return: Total number of bees in the simulation
        """
        return len(self.bees)

    @property
    def flower_population(self):
        """
        :return: Total number of flowers in the simulation
        """
        return len(self.flowers)

    def get_entities(self):
        """
        :return: Entities that need to be rendered next frame
        """
        self.update_game_state()

        return self.plants.sprites() + self.flowers.sprites() + \
               self.hives.sprites() + self.bees.sprites() + self.ui_elements.sprites()

    def update_game_state(self):
        """
        :return: void
        """
        for hive in self.hives:
            hive.last_tick = get_ticks()
            self.handle_hive_highlighting(hive)
            if hive.current_nectar == hive.max_nectar:
                self.hive_purchase_bee(hive)

        for flower in self.flowers:
            if flower.pollen == 0:
                flower.crosshair.kill()
                flower.kill()
                for hive in self.hives:
                    if flower in hive.flowers:
                        hive.flowers.remove(flower)
            else:
                if flower.inspecting_hives.__len__() == 0:
                    self.ui_elements.remove(flower.crosshair)
                else:
                    self.ui_elements.add(flower.crosshair)
                    flower.inspecting_hives[flower.inspecting_hives.__len__() -
                                            1].recolor_crosshair(flower)

        if not self.sim_paused:
            for bee in self.bees:  # If the sim is not paused, we update the states of the bees
                bee.update()
                self.update_bee_crosshair(bee)
                bee.handle_collisions(self.flowers)

        else:
            for bee in self.bees:  # If the sim is paused we only update the crosshairs
                self.update_bee_crosshair(bee)

    def update_bee_crosshair(self, bee):
        """
        Updates the state of the bee crosshair, adding it to the list of rendered entities if necessary
        :param bee:
        :return: void
        """
        if not bee.highlighted:
            bee.crosshair.kill()
        else:
            self.ui_elements.add(bee.crosshair)
            bee.crosshair.follow()

    def handle_hive_highlighting(self, hive):
        """
        Takes care of everything that has to do with hive highlighting, adding the needed ui elements if necessary
        :param hive:
        :return:
        """
        if not hive.highlighted:
            hive.honey_bar.kill()
        else:
            self.ui_elements.add(hive.honey_bar)
            hive.honey_bar.update()

    def add_bee(self, hive, caste):
        if caste == 'worker':
            new_bee = \
                WorkerBee((hive.center.x + randint(-10, 10),
                           hive.center.y + randint(-10, 10)),
                          hive)
        elif caste == 'scout':
            new_bee = \
                ScoutBee((hive.center.x + randint(-50, 50),
                          hive.center.y + randint(-50, 50)),
                         hive)

        self.ui_elements.add(new_bee.crosshair)
        hive.add_bee(new_bee, caste)
        self.bees.add(new_bee)

    def hive_purchase_bee(self, hive):
        """
        Provided hive purchases a bee using some of its honey
        :param hive:
        :return:
        """
        hive.buy_bee()
        bee_roll = random()
        self.add_bee(hive,
                     'scout') if bee_roll >= self.bee_ratio else self.add_bee(
                         hive, 'worker')

    def populate_hives(self, hives, bees_per_hive):
        """
        Populates the hives with bees
        :param hives:
        :param bees_per_hive:
        :return:
        """
        for hive in hives:
            self.hives.add(hive)
            self.spawn_initial_bees(hive, bees_per_hive)

    def spawn_initial_bees(self, hive, bees_per_hive):
        """
        Fills an individual hive with bees
        :param hive:
        :param bees_per_hive:
        :return:
        """
        scouts = int(bees_per_hive * self.bee_ratio)
        workers = bees_per_hive - scouts

        for j in range(workers):
            self.add_bee(hive, 'worker')

        for j in range(scouts):
            self.add_bee(hive, 'scout')

    def clean_up_spawn(self):
        """
        Removes flowers that are colliding with hives and adds UI elements to the hives
        :return:
        """
        for hive in self.hives:
            flowers = self.flowers
            spritecollide(hive, flowers, True, collide_circle_ratio(1))

    def load_flower_data(self, data):
        """
        Loads the list of flowers
        :param data:
        :return:
        """
        self.flower_database = data
        self.flowers = RenderUpdates(data.values())

    def grow_flora(self, play_area):
        """
        Grows the decorative plants
        :param play_area:
        :return: void
        """

        plant_db = grow_plants(play_area,
                               num=randint(90, 150),
                               plant_type="grass",
                               bias="center")

        plant_db = merge_plant_sets(
            plant_db,
            grow_plants(play_area,
                        num=randint(50, 75),
                        plant_type="grassy_plant",
                        bias="edges"))
        plant_db = merge_plant_sets(
            plant_db,
            grow_plants(play_area,
                        num=randint(1, 2),
                        plant_type="pretty_log",
                        bias="edges"))
        plant_db = merge_plant_sets(
            plant_db,
            grow_plants(play_area,
                        num=randint(0, 3),
                        plant_type="stump",
                        bias="edges"))
        plant_db = merge_plant_sets(
            plant_db,
            grow_plants(play_area,
                        num=randint(25, 55),
                        plant_type="leaves",
                        bias="edges"))
        plant_db = merge_plant_sets(
            plant_db,
            grow_plants(play_area,
                        num=randint(15, 25),
                        plant_type="bushy_grass",
                        bias="edges"))

        self.plants = RenderUpdates(list(plant_db.values()))

    def get_hive_at(self, position):
        """
        :param position:
        :return: Hive at given location, None if there are none such.
        """
        for hive in self.hives:
            if hive.scaled_rect.collidepoint(position):
                return hive
        return None