Пример #1
0
 def _bonusJob(self):
     if not self.running:
         return
     nextBonus = random.randint(0, 10) 
     if nextBonus <= 5:
         bonus = self._windex(PersistentBonus.probs)
         self.bonus = PersistentBonus(self, (bonus, PersistentBonus.boni[bonus]))
     elif 5 < nextBonus <= 7:
         bonus = self._windex(InstantBonus.probs)
         self.bonus = InstantBonus(self, (bonus, InstantBonus.boni[bonus]))
     else:
         self.bonus = InstantBonus(self, ('newBlock', InstantBonus.boni['newBlock']))
     self.bonusjob = g_player.setTimeout(random.choice([4000, 5000, 6000]), self._bonusJob)
Пример #2
0
class Game(gameapp.GameApp):
    def init(self):
        gameobjects.displayWidth, gameobjects.displayHeight = self._parentNode.size
        gameobjects.bricksPerLine = (int)(self._parentNode.height / (brickSize * PPM))
        gameobjects.preRender()
        self.bonusjob = None
        self.cleanup = None
        self.keepPushingBalls = None
        self.tutorialMode = False
        self.backgroundpic = None
        self.lines = None
        self.preRender() 
        self.machine = statemachine.StateMachine('UPM', 'MainMenu')
        self.machine.addState('MainMenu', ['Playing', 'Tutorial', 'About'], enterFunc=self.showMenu, leaveFunc=self.hideMenu)
        self.machine.addState('Tutorial', ['MainMenu', 'Playing', 'Tutorial'], enterFunc=self.startTutorial, leaveFunc=self.hideTutorial)
        self.machine.addState('Playing', ['MainMenu'], enterFunc=self.startPlaying)
        self.machine.addState('About', ['MainMenu'], enterFunc=self.showAbout, leaveFunc=self.hideAbout)     
        self.showMenu()
    
    def preRender(self):
        self.backgroundpic = avg.SVG('../data/img/char/background_dark.svg', False).renderElement('layer1', self._parentNode.size + (50, 50))
        self.lines = avg.SVG('../data/img/btn/dotted_line.svg', False)
        
    def makeButtonInMiddle(self, name, node, yOffset, pyFunc):        
        path = '../data/img/btn/'
        svg = avg.SVG(path + name + '_up.svg', False)
        height = node.height / 8 
        size = (height * 2.4, height)
        upNode = svg.createImageNode('layer1', {}, size)
        svg = avg.SVG(path + name + '_dn.svg', False)
        downNode = svg.createImageNode('layer1', {}, size)
        position = (node.pivot[0] - upNode.width / 2, node.pivot[1] + yOffset * upNode.height + yOffset * 50)
        return ui.TouchButton(upNode, downNode, clickHandler=pyFunc, parent=node, pos=position)

    def showMenu(self):
        self._createMenuBackground()        
        self.menuScreen = avg.DivNode(parent=self._parentNode, size=self._parentNode.size)
        self.startButton = self.makeButtonInMiddle('start', self.menuScreen, -1, lambda:self.machine.changeState('Playing'))
        self.tutorialButton = self.makeButtonInMiddle('help', self.menuScreen, 0, lambda:self.machine.changeState('Tutorial'))
        self.aboutButton = self.makeButtonInMiddle('about', self.menuScreen, 1, lambda:self.machine.changeState('About'))
        self.exitButton = self.makeButtonInMiddle('exit', self.menuScreen, 2, lambda:exit(0))
  
    def _createMenuBackground(self):
        self.nodeList = []
        picList = [Ball.pic, Mine.leftPic, Mine.rightPic, RedBall.pic] + Ghost.pics.values()
        for i in range (1, 500):
            node = avg.ImageNode(parent=self._parentNode)
            node.setBitmap(random.choice(picList))
            if i <= 250:
                pos = (random.randint(0, int(self._parentNode.width / 3 - ghostRadius * PPM * 2)), random.randint(0, int(self._parentNode.height - ghostRadius * PPM * 2)))
            else:
                pos = (random.randint(2 * int(self._parentNode.width / 3), int(self._parentNode.width)), random.randint(0, int(self._parentNode.height - ghostRadius * PPM * 2)))
            node.pos = pos
            self.nodeList.append(node)
        self.title = avg.WordsNode(
                                    parent=self._parentNode,
                                    pivot=(0, 0),
                                    text="UPM",
                                    pos=(self._parentNode.width / 2 - 100, 50),
                                    wrapmode="wordchar",
                                    font='Impact',
                                    color="00FF00",
                                    fontsize=100,
                                    variant="bold")
                    
    def _destroyMenuBackground(self):
        for node in self.nodeList:
            node.active = False
            node.unlink(True)
            node = None 
        if self.title is not None:
            self.title.active = False
            self.title.unlink(True)
            self.title = None
                     
    def hideMenu(self):
        self._destroyMenuBackground()
        self.menuScreen.unlink(True)
        self.menuScreen = None
        
    def startTutorial(self):
        self.tutorialMode = True
        self.setupPlayground()
        g_player.setTimeout(config.startingTutorial, self.startBall)
        g_player.setTimeout(config.startingTutorial + config.ballTutorial, self.startGhosts)
        g_player.setTimeout(config.startingTutorial + config.ballTutorial + config.ghostTutorial, self.revealTetris)
        g_player.setTimeout(config.startingTutorial + config.ballTutorial + config.ghostTutorial + config.tetrisTutorial, self.revealBoni)
        
    def startPlaying(self):
        self.tutorialMode = False
        self.setupPlayground()
        TetrisBar(self.display)
        TetrisBar(self.display, left=False)
        self.revealTetris()
        g_player.setTimeout(config.tetrisTutorial, self.startMovement)
    
    def startMovement(self):
        self.startBall()
        self.createGhosts()
        self._bonusJob()
        
    def hideTutorial(self):
        self.tutorialMode = False
        
    def showAbout(self):
        self.aboutScreen = avg.DivNode(parent=self._parentNode, size=self._parentNode.size)
        avg.WordsNode(parent=self.aboutScreen, x=5, text='Unnamed Multipong<br/>as envisioned and implemented by<br/>Benjamin Guttman<br/>Joachim Couturier<br/>Philipp Hermann<br/>Mykola Havrikov<br/><br/>This game uses libavg(www.libavg.de) and PyBox2D(http://code.google.com/p/pybox2d/)')
        self.menuButton = self.makeButtonInMiddle('menu', self.aboutScreen, 1, lambda:self.machine.changeState('MainMenu'))

    def hideAbout(self):
        self.aboutScreen.unlink(True)
        self.aboutScreen = None
    
    def setupPlayground(self):
        # libavg setup        
        self.display = avg.DivNode(parent=self._parentNode, size=self._parentNode.size)
        self.renderer = Renderer()     
        background = avg.ImageNode(parent=self.display)
        background.setBitmap(self.backgroundpic) 
        self.display.player = None
        (displayWidth, displayHeight) = self.display.size
        widthThird = (int)(displayWidth / 3)
        fieldSize = (widthThird, displayHeight)
        self.field1 = avg.DivNode(parent=self.display, size=fieldSize)
        self.field2 = avg.DivNode(parent=self.display, size=fieldSize, pos=(displayWidth - widthThird, 0))
        avg.LineNode(parent=self.display, pos1=(0, 1), pos2=(displayWidth, 1))
        avg.LineNode(parent=self.display, pos1=(0, displayHeight), pos2=(displayWidth, displayHeight))   
        self.lines.createImageNode('layer1', dict(parent=self.display, pos=(widthThird, 0)), (2, displayHeight))
        self.lines.createImageNode('layer1', dict(parent=self.display, pos=(displayWidth - widthThird, 0)), (2, displayHeight))  
        # pybox2d setup
        self.world = b2World(gravity=(0, 0), doSleep=True)
        self.hitset = set()
        self.listener = ContactListener(self.hitset)
        self.world.contactListener = self.listener
        self.running = True
        pointsToWin = 999 if self.tutorialMode else config.pointsToWin
        self.leftPlayer, self.rightPlayer = Player(self, self.field1, pointsToWin), Player(self, self.field2, pointsToWin)
        self.leftPlayer.other, self.rightPlayer.other = self.rightPlayer, self.leftPlayer    
        # horizontal lines
        BorderLine(self.world, a2w((0, 1)), a2w((displayWidth, 1)), 1, False, 'redball')
        BorderLine(self.world, a2w((0, displayHeight)), a2w((displayWidth, displayHeight)), 1, False, 'redball')
        # vertical ghost lines
        maxWallHeight = brickSize * brickLines * PPM
        BorderLine(self.world, a2w((maxWallHeight, 0)), a2w((maxWallHeight, displayHeight)), 1, False, 'redball', 'ball') 
        BorderLine(self.world, a2w((displayWidth - maxWallHeight - 1, 0)), a2w((displayWidth - maxWallHeight - 1, displayHeight)), 1, False, 'redball', 'ball')
        self.middleX, self.middleY = self.display.size / 2
        self.middle = a2w((self.middleX, self.middleY))
        BatManager(self.field1, self.world, self.renderer)
        BatManager(self.field2, self.world, self.renderer)
        self.bonus = None
        self.balls = []
        self.redballs = []
        self.towers = []
        self.ghosts = []
        self.mainLoop = g_player.setOnFrameHandler(self.step)
        
    def startBall(self):
        ball = Ball(self, self.renderer, self.world, self.display, self.middle)
        self.balls.append(ball)
        if self.tutorialMode:
            BallTutorial(self).start()
    
    def revealBoni(self):
        BoniTutorial(self).start()        
                
    def revealTetris(self):
        height = (self.display.height / 2) - (brickSize * PPM)
        width = self.display.width
        for i in range (-3, 3):
            form = random.choice(Block.form.values())
            offset = form[1]
            if form == Block.form['SPIECE']:
                offset += 1
            Block(self.display, self.renderer, self.world, (width / 3 - (brickSize * offset * PPM), height - (brickSize * PPM * 3) * i), self.leftPlayer, form, vanishLater=True)
            Block(self.display, self.renderer, self.world, (2 * width / 3, height - (brickSize * PPM * 3) * i), self.rightPlayer, form, vanishLater=True)   
        if self.tutorialMode:
            TetrisTutorial(self).start()
            
    def startGhosts(self):
        self.createGhosts()
        if self.tutorialMode:
            GhostTutorial(self).start()

    def createGhosts(self):
        offset = 2 * ballRadius + 3 * ghostRadius
        self.ghosts.append(Ghost(self.renderer, self, self.display, self.middle + (offset, offset), "blinky"))
        self.ghosts.append(Ghost(self.renderer, self, self.display, self.middle + (-offset, offset), "pinky"))
        self.ghosts.append(Ghost(self.renderer, self, self.display, self.middle - (-offset, offset), "inky"))
        self.ghosts.append(Ghost(self.renderer, self, self.display, self.middle - (offset, offset), "clyde"))   
                     
    def killGhosts(self):
        for ghost in self.ghosts:        
            ghost.destroy()
        del self.ghosts[:]
                        
    def getBalls(self):
        return self.balls
    
    def getRedBalls(self):
        return self.redballs
    
    def getGhosts(self):
        return self.ghosts
    
    def _windex(self, lst):
        wtotal = sum([x[1] for x in lst])
        n = random.uniform(0, wtotal)
        for item, weight in lst:
            if n < weight:
                break
            n = n - weight
        return item
            
    def _bonusJob(self):
        if not self.running:
            return
        nextBonus = random.randint(0, 10) 
        if nextBonus <= 5:
            bonus = self._windex(PersistentBonus.probs)
            self.bonus = PersistentBonus(self, (bonus, PersistentBonus.boni[bonus]))
        elif 5 < nextBonus <= 7:
            bonus = self._windex(InstantBonus.probs)
            self.bonus = InstantBonus(self, (bonus, InstantBonus.boni[bonus]))
        else:
            self.bonus = InstantBonus(self, ('newBlock', InstantBonus.boni['newBlock']))
        self.bonusjob = g_player.setTimeout(random.choice([4000, 5000, 6000]), self._bonusJob)
    
    def end(self, player):
        if not self.running:
            return
        self.running = False
        self.killGhosts()
        self.leftPlayer.killBricks()
        self.rightPlayer.killBricks()
        if self.bonusjob is not None and not self.tutorialMode:
            g_player.clearInterval(self.bonusjob)
        if self.bonus is not None and not self.tutorialMode:
            self.bonus.vanish()
        (displayWidth, displayHeight) = self.display.size
        BorderLine(self.world, a2w((0, 0)), a2w((0, displayHeight)), 1, False) 
        BorderLine(self.world, a2w((displayWidth, 0)), a2w((displayWidth, displayHeight)), 1, False)  
        if not self.tutorialMode:
            player.setEndText('You won')
            player.other.setEndText('You lost')
            self.createWinBalls()                  
        self.cleanup = g_player.setTimeout(40000, self.clearDisplay)
        self.menuButton = self.makeButtonInMiddle('menu', self.display, 0, self.clearDisplay)
    
    def createWinBalls(self):
        for i in range(1, random.randint(2, 5)):
            ball = Ball(self, self.renderer, self.world, self.display, self.middle)
            picList = [Ball.pic, Mine.leftPic, Mine.rightPic, RedBall.pic, Tower.pic] + Ghost.pics.values() + Bonus.pics.values()
            ball.setPic(random.choice(picList))
            self.balls.append(ball)     
        if len(self.balls) <= 60: 
            self.keepPushingBalls = g_player.setTimeout(1000, self.createWinBalls)
                
    def clearDisplay(self):    
        for tower in self.towers:
            tower.destroy()   
        for redball in self.redballs:
            redball.destroy()       
        g_player.clearInterval(self.mainLoop)
        if self.cleanup is not None:
            g_player.clearInterval(self.cleanup)
            self.cleanup = None
        if self.keepPushingBalls is not None:
            g_player.clearInterval(self.keepPushingBalls)            
            self.keepPushingBalls = None
        for ghost in self.ghosts:
            if ghost.movement is not None:
                g_player.clearInterval(ghost.movement)
            if ghost.changing is not None:
                g_player.clearInterval(ghost.changing)
        self.display.active = False
        self.display.unlink(True)
        BorderLine.body = None
        self.machine.changeState('MainMenu')
                
    def addBall(self):
        if len(self.balls) < maxBalls:
            self.balls.append(Ball(self, self.renderer, self.world, self.display, self.middle))
    
    def removeBall(self, ball):
        if len(self.balls) > 1:
            self.balls.remove(ball)
            ball.destroy()
        else:
            ball.reSpawn()

    def _processBallvsBrick(self, hitset):
        copy = hitset.copy()
        for brick in copy:
            brick.hit()
        hitset.difference_update(copy)
        copy.clear() 
        
    def _processBallvsBall(self):
        for ball in self.balls:
            for ce in ball.body.contacts:
                contact = ce.contact
                mine = None
                if contact.fixtureA.userData == 'mine':
                    mine = contact.fixtureA.body.userData                
                elif contact.fixtureB.userData == 'mine':
                    mine = contact.fixtureB.body.userData
                    
                if mine is not None:
                    if ball.lastPlayer != mine.getOwner() and ball.lastPlayer is not None:
                        ball.lastPlayer.penalize()
                        ball.reSpawn()
                        mine.destroy()
                        return

    def _processBallvsGhost(self):
        for ball in self.balls:
            for ce in ball.body.contacts:
                contact = ce.contact
                ghost = None        
                if contact.fixtureA.userData == 'ghost':
                    ghost = contact.fixtureA.body.userData    
                elif contact.fixtureB.userData == 'ghost':
                    ghost = contact.fixtureB.body.userData                  
                if ghost is not None:
                    if ghost.mortal:
                        # ball eats ghost
                        ghost.reSpawn()
                        if ball.lastPlayer is not None:
                            ball.lastPlayer.addPoint()
                        self.addBall()
                        break
                    else:                        
                        # ghost tries to eat ball
                        if ball.lastPlayer is None:
                            break
                        if ghost.getOwner() is not None:
                            if ball.lastPlayer == ghost.getOwner():
                                break
                        player = ball.zoneOfPlayer()
                        if player is not None:
                            player.penalize()
                            self.removeBall(ball)

    def _checkBallPosition(self):
        for ball in self.balls:
            if ball.body.position[0] > (self.display.width / PPM) + ballRadius: 
                if ball.lastPlayer == self.rightPlayer:
                    self.rightPlayer.penalize()
                self.leftPlayer.addPoint()
                ball.reSpawn()
            elif ball.body.position[0] < -ballRadius: 
                if ball.lastPlayer == self.leftPlayer:
                    self.leftPlayer.penalize()
                self.rightPlayer.addPoint()
                ball.reSpawn()
    
    def _outside(self, ball):
        return (ball.body is None or 
                not (-ballRadius <= ball.body.position[0] <= (self.display.width / PPM) + ballRadius))
    
    def _checkRedBallPosition(self):
        killList = [x for x in self.redballs if self._outside(x)]
        self.redballs[:] = [x for x in self.redballs if x not in killList]
        for ball in killList:
            ball.destroy()

    def step(self):
        self.world.Step(TIME_STEP, 10, 10)
        self.world.ClearForces()
        if self.running:
            self._processBallvsGhost()
            self._checkBallPosition()
            self._checkRedBallPosition()
            self._processBallvsBall()
            self._processBallvsBrick(self.hitset)
        self.renderer.draw()