Python貪喫蛇雙人大戰-魔法豆登場

Python貪喫蛇雙人大戰-魔法豆登場

時隔兩月之後,家裏的小朋友再次對我之前改寫的貪喫蛇遊戲(過程可參考我之前寫的 Python貪喫蛇雙人大戰Python貪喫蛇雙人大戰-升級版,代碼可以到此處下載)提出了新的需求(用戶永遠會有新需求)。還好,這回需求不多,就一個:要求增加魔法豆,要是蛇喫到了魔法豆,蛇身可以一次增加5格;魔法豆被喫後自動重新生成,且在屏幕上只出現2個魔法豆。

爲了滿足小朋友的願望,老父親只好又拿起了兩個月沒看的代碼(已經忘的差不多了)。分析了一下需求,並不複雜,很明顯需要增加一個魔法豆的類,然後在交互的地方修改一下就行了。

新增全局量

新增了幾個全局常量如下,方便以後的修改。憑着多年編程的直覺,在命名的時候用了MAGIC1,預測以後大概率還會有MAGIC2,MAGIC3等等。當然,用1,2,3其實很不好,無法從名字看出意義,不過暫時也沒有想到合適的名字,以後要是多了再根據特徵來區分命名吧。(關於命名,可以參考變量名的力量)

MAGIC1_BEAN_NUM = 2
MAGIC1_BEAN_ADD_LEN = 5
MAGIC1_BEAN_COLOR = BLUE

新增魔法豆類

魔法豆與普通的豆子差別不多,所以此類從NormalBeans修改而來,幾乎沒啥區別。關於一次增加多格的過程會在主循環裏去實現,因爲在實現的過程中這個多格不是一次增加的,那樣方向未知,有可能引起碰撞什麼的,不好處理。於是增加多格會分多步實現,每一步還是隻增加一格。效果如下動圖(看那條綠色的蛇):
魔法豆
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-9MvsLGem-1592815344256)(./pic/snake_magic1_bean.gif)]

魔法豆類的代碼如下:

class Magic1Beans: #魔法豆:吃了一次蛇身增加MAGIC1_BEAN_ADD_LEN格
    def __init__(self, color, totalNum):
        self.color = color
        self.totalNum = totalNum
        self.curNum = 0
        self.beans = []
    def generate(self, normalBeanss, snakeBeanss, snakes, magicBeanss):
        while self.curNum < self.totalNum:
            x = random.randrange(0,SCREEN_WIDTH/GRID_SIZE)
            y = random.randrange(1,SCREEN_HEIGHT/GRID_SIZE)
            newBeanPos = [int(x*GRID_SIZE),int(y*GRID_SIZE)]
            #檢查豆子位置是否重複
            if isEmptyInArea([newBeanPos], normalBeanss, snakeBeanss, snakes, magicBeanss):
                #新生成的豆子在不重複的地方
                self.beans.append(Bean(self.color, newBeanPos))
                self.curNum = self.curNum + 1
    def beEaten(self, snakePos):
        for bean in self.beans:
            if bean.beEaten(snakePos):
                self.beans.remove(bean)
                self.curNum = self.curNum - 1
                return True
        return False
    def show(self, playSurface):
        for bean in self.beans:
            pygame.draw.rect(playSurface,self.color,Rect(bean.pos[0],bean.pos[1],GRID_SIZE,GRID_SIZE))  

新增了類當然也需要增加類的實例:

    magic1Beans = Magic1Beans(MAGIC1_BEAN_COLOR,MAGIC1_BEAN_NUM)
    magic1Beans.generate([normBeans],[snake1Beans,snake2Beans],[snake1,snake2],[])

魔法豆不出現在重複的位置

類似於之前的豆子,魔法豆不能與其他豆子出現的位置重複,所以修改了判斷是否有空位置的函數isEmptyInArea,增加了一個參數magicBeanss是魔法豆的列表,函數最後增加了對魔法豆位置的判斷,代碼如下:

def isEmptyInArea(area, normalBeanss=[], snakeBeanss=[], snakes=[], magicBeanss=[]):
    ''' area是位置的列表
    '''
    for pos in area:
        if normalBeanss != []:
            for nbs in normalBeanss:
                for nb in nbs.beans:
                    if nb.pos == pos:
                        return False
                    
        if snakeBeanss != []:
            for sbs in snakeBeanss:
                if sbs != []:
                    for sb in sbs.beans:
                        if sb.pos == pos:
                            return False
        if snakes != []:
            for snake in snakes:
                for snakePos in snake.segments:
                    if snakePos == pos:
                        return False
                    
        if magicBeanss != []:
            for mbs in magicBeanss:
                for mb in mbs.beans:
                    if mb.pos == pos:
                        return False
                    
    return True 

因爲修改了這個函數接口,所以代碼中調用這個函數的地方都要相應的修改,蛇類的重生函數接口需要修改,如下:

    def respawn(self, normalBeanss=[], snakeBeanss=[], snakes=[], magicBeanss=[]):
        self.generate()
        while not isEmptyInArea(self.segments, normalBeanss, snakeBeanss, snakes, magicBeanss):
            self.generate()
        self.vel = SNAKE_VEL_SLOW
        self.velCount = 0

調用處修改如下:

        if snake1VelCount > 1:
            if snake1.moveAndAdd(snake2): #撞到了另一條蛇身
                snake1Beans = SnakeBeans(snake1)
                snake1.respawn([normBeans],[snake1Beans,snake2Beans],[snake2],[magic1Beans])
                continue
        if snake2VelCount > 1:  
            if snake2.moveAndAdd(snake1): #撞到了另一條蛇身
                snake2Beans = SnakeBeans(snake2)
                snake2.respawn([normBeans],[snake1Beans,snake2Beans],[snake1],[magic1Beans])    
                continue
        # 若死亡則重生
        if snake1VelCount > 1:
            if snake1.isDead():
                snake1.respawn([normBeans],[snake1Beans,snake2Beans],[snake2],[magic1Beans])    
        if snake2VelCount > 1:
            if snake2.isDead():
                snake2.respawn([normBeans],[snake1Beans,snake2Beans],[snake1],[magic1Beans])  

普通豆子的生成函數也需要修改,如下:

    def generate(self, snakeBeanss, snakes, magicBeanss):
        while self.curNum < self.totalNum:
            x = random.randrange(0,SCREEN_WIDTH/GRID_SIZE)
            y = random.randrange(1,SCREEN_HEIGHT/GRID_SIZE)
            newBeanPos = [int(x*GRID_SIZE),int(y*GRID_SIZE)]
            #檢查豆子位置是否重複
            if isEmptyInArea([newBeanPos], [self], snakeBeanss, snakes, magicBeanss):
                #新生成的豆子在不重複的地方
                self.beans.append(Bean(self.color, newBeanPos))
                self.curNum = self.curNum + 1

實現一次增加多格

通過新增兩個變量來實現,分別對應兩條蛇:

    snake1Magic1Count = 0
    snake2Magic1Count = 0

這個值表示當前還需要增加的身體長度。當這個值爲0時,意味着不需要增加身體長度,每次moveAndAdd之後需要pop,否則不pop。對於一次要加多格的情況,給這個值增加相應的值就好了,普通豆子加1就行。修改處理代碼如下:

        # 判斷是否需要增加蛇身長度
        if snake1VelCount > 1:
            if snake1Magic1Count > 0:
                snake1Magic1Count -= 1
            if normBeans.beEaten(snake1.headPos):
                normBeans.generate([snake1Beans,snake2Beans],[snake1,snake2],[magic1Beans]) # 如果普通豆子被喫掉,則重新生成豆子
                snake1Magic1Count += 1
            if magic1Beans.beEaten(snake1.headPos):
                magic1Beans.generate([normBeans],[snake1Beans,snake2Beans],[snake1,snake2],[]) # 如果Magic1豆子被喫掉,則重新生成豆子
                snake1Magic1Count += MAGIC1_BEAN_ADD_LEN         
            if snake1Beans != [] and snake1Beans.beEaten(snake1.headPos):
                snake1Magic1Count += 1
            if snake2Beans != [] and snake2Beans.beEaten(snake1.headPos): 
                snake1Magic1Count += 1
            if snake1Magic1Count == 0:
                snake1.pop()
        if snake2VelCount > 1:        
            if snake2Magic1Count > 0:
                snake2Magic1Count -= 1
            if normBeans.beEaten(snake2.headPos):
                normBeans.generate([snake1Beans,snake2Beans],[snake1,snake2],[magic1Beans]) # 如果普通豆子被喫掉,則重新生成豆子
                snake2Magic1Count += 1
            if magic1Beans.beEaten(snake2.headPos):
                magic1Beans.generate([normBeans],[snake1Beans,snake2Beans],[snake1,snake2],[]) # 如果Magic1豆子被喫掉,則重新生成豆子
                snake2Magic1Count += MAGIC1_BEAN_ADD_LEN
            if snake1Beans != [] and snake1Beans.beEaten(snake2.headPos):
                snake2Magic1Count += 1
            if snake2Beans != [] and snake2Beans.beEaten(snake2.headPos): 
                snake2Magic1Count += 1
            if snake2Magic1Count == 0:
                snake2.pop()

繪製刷新

這個簡單,在繪製刷新的時候增加調用魔法豆的顯示函數就行了。

        magic1Beans.show(playSurface)

至此,又可以和我家小朋友一起愉快地玩耍了 😃

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章