利用pygame開發一款遊戲:「跳跳兔」(完結篇)

前言

經過前面九篇文章的編寫,「跳跳兔」遊戲基本已經被編寫出來了,本節在此基礎上進一步完善它,並添加上雲彩背景。python

添加雲彩背景

添加雲彩背景的大體步驟以下。git

  • 1.編寫雲彩類
  • 2.載入雲彩圖片
  • 3.隨機生成雲彩
  • 4.雲彩同步移動

一步步來編寫,首先是建立雲彩類,代碼以下。github

# sprites.py

class Cloud(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = CLOUD_LAYER
        self.groups = game.all_sprites, game.clouds
        pg.sprite.Sprite.__init__(self, self.groups)
        self.game = game
        self.image = random.choice(self.game.cloud_images)
        self.image.set_colorkey(BLACK)
        self.rect = self.image.get_rect()
        # 隨機出現位置
        scale = random.randrange(50, 101) / 100
        self.image = pg.transform.scale(self.image, (int(self.rect.width * scale),
                                                     int(self.rect.height * scale)))
        self.rect.x = random.randrange(WIDTH - self.rect.width)
        self.rect.y = random.randrange(-500, -50)

    def update(self):
        # 雲朵大於2倍高度,就被消除
        if self.rect.top > HEIGHT * 2:
            self.kill()
複製代碼

代碼內容與此前內容很是相似,再也不詳細分析。算法

但你仔細觀察,你會發現,Cloud類的__init__()方法中建立了 self._layer,並經過以下形式將其加入到相應的groups中。app

self.groups = game.all_sprites, game.clouds
pg.sprite.Sprite.__init__(self, self.groups)
複製代碼

這是一個優化點,後文再討論。dom

構建了Cloud類後,接着要作的就是載入圖片、隨機生成以及同步移動了,輕車熟路。ide

# main.py/Game

    def load_data(self): # 加載數據
        # ... 省略無關代碼
        # 加載雲彩圖片
        self.cloud_images = []
        for i in range(1, 4):
            self.cloud_images.append(pg.image.load(os.path.join(img_dir, 'cloud{}.png'.format(i))).convert())
        
    def new(self):
        self.score = 0
        # ... 省略無關代碼
        # 建立雲彩
        for i in range(8):
            c = Cloud(self)
            c.rect.y += 500
        self.run()
        
    def update(self):
         # 玩家到達遊戲框 1/4 處時(注意,遊戲框,頭部爲0,底部爲遊戲框長度,到到遊戲框的1/4處,表示已經到達了頂部一部分了)
        if self.player.rect.top <= HEIGHT / 4:
            # 玩家位置移動(往下移動)
            self.player.pos.y += max(abs(self.player.vel.y), 2)
            # 隨機生成新雲朵
            if random.randrange(100) < 10:
                Cloud(self)
            # 雲彩同步移動
            for cloud in self.clouds:
                cloud.rect.y += max(abs(self.player.vel.y / 2), 2)
            # 敵人位置同步往下移動
            for mob in self.mobs:
                mob.rect.y += max(abs(self.player.vel.y), 2)
            # 平臺在遊戲框外時,將其註銷,避免資源浪費
            for plat in self.platforms:
                # 平臺移動位置(往下移動,移動的距離與玩家相同,這樣玩家才能依舊站立在本來的平臺上)
                plat.rect.y += max(abs(self.player.vel.y), 2)
                if plat.rect.top >= HEIGHT: 
                    plat.kill()
                    # 分數增長 - 平臺銷燬,分數相加
                    self.score += 10
            
複製代碼

woo~,搞定,若是有疑惑,能夠拉下github代碼對照着看。學習

優化

雲彩類添加完了,接着來進行一些優化。優化

首先,對碰撞檢測的優化,若是你仔細觀察,你會發現,玩家對象與敵人對象的本體尚未接觸到,就觸發了碰撞檢測,遊戲就結束了,形成這種現象的緣由是,玩家也好、敵人也好,遊戲中的任何元素都是一個對應大小的長方形,碰撞檢測默認形式就是對這兩個方塊進行檢測,此時兩個元素自己可能沒有接觸,但對應的方塊接觸到了,因此觸發了碰撞檢測。spa

爲了不這種狀況,能夠利用pygame的蒙版機制mask,爲Player、Mob都建立相應的蒙版,具體作法以下。

# sprites.py

class Player(pg.sprite.Sprite):
    def animate(self):
        # ... 省略無關代碼
        self.mask = pg.mask.from_surface(self.image) # 建立蒙版

class Mob(pg.sprite.Sprite):
    
    def update(self):
        # ... 省略無關代碼
        self.rect = self.image.get_rect()
        self.mask = pg.mask.from_surface(self.image) # 建立蒙版
        self.rect.center = center
        # ... 省略無關代碼
複製代碼

檢測時,加上pygame.sprite.collide_mask回調則可

def update(self):
        # ... 省略無關代碼
        # 碰撞檢測 - 若是碰撞到了敵人,遊戲結束
        mob_hits = pg.sprite.spritecollide(self.player, self.mobs, False, pg.sprite.collide_mask)
        if mob_hits:
            self.playing = False
複製代碼

此外還有個須要優化的問題,就是元素圖層關係,增長雲彩對象後,圖層關係的問題顯得明顯,雲彩做爲背景卻會遮擋玩家對象、敵人對象、平臺對象等,這是不合理的,不一樣元素應該在不一樣圖層,從而合理的顯示出來。

首先定義好不一樣元素要出現的圖層。

# settings.py

# 不一樣元素在不一樣層
PLAYER_LAYER = 2 # 玩家
PLATFORM_LAYER = 1 # 平臺
POW_LAYER = 1 # 道具
MOB_LAYER = 2 # 敵人
CLOUD_LAYER = 0 # 雲
複製代碼

而後爲不一樣的元素對象都添加上設置圖層的邏輯

#Sprite.py

class Player(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = PLAYER_LAYER # 對應的圖層
        self.groups = game.all_sprites # 所在的組
        pg.sprite.Sprite.__init__(self, self.groups) # 添加、實例化
        # ... 省略無關代碼

class Platform(pg.sprite.Sprite):
    def __init__(self, game, x, y):
        self._layer = PLATFORM_LAYER # 對應的圖層
        self.groups = game.all_sprites, game.platforms # 所在的組
        pg.sprite.Sprite.__init__(self, self.groups) # 添加、實例化
        # ... 省略無關代碼

class Pow(pg.sprite.Sprite):
    def __init__(self, game, plat):
        self._layer = POW_LAYER
        self.groups = game.all_sprites, game.powerups
        pg.sprite.Sprite.__init__(self, self.groups)
        # ... 省略無關代碼
        
class Mob(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = MOB_LAYER
        self.groups = game.all_sprites, game.mobs
        pg.sprite.Sprite.__init__(self, self.groups)
        # ... 省略無關代碼
        
class Cloud(pg.sprite.Sprite):
    def __init__(self, game):
        self._layer = CLOUD_LAYER
        self.groups = game.all_sprites, game.clouds
        pg.sprite.Sprite.__init__(self, self.groups)
        # ... 省略無關代碼
複製代碼

優化後,再修改一個Game類的new()方法,使用pygame.sprite.LayeredUpdates()來實例化all_sprites對象。

LayeredUpdates(分層更新)是一個精靈組,它能夠處理圖層並順序繪製元素。

# main.py

class Game:
    def new(self):
        self.score = 0
        # self.all_sprites = pg.sprite.Group()
        # 層次添加,避免元素重疊顯示(如背景雲遮擋住平臺與玩家)
        self.all_sprites = pg.sprite.LayeredUpdates()
        self.platforms = pg.sprite.Group()
        self.powerups = pg.sprite.Group() # 急速飛躍道具
        self.mobs = pg.sprite.Group() # 敵人對象
        self.clouds = pg.sprite.Group() # 雲彩對象
        self.player = Player(self)
        self.all_sprites.add(self.player)
        for plat in PLATFORM_LIST:
            p = Platform(self, *plat)
            # self.all_sprites.add(p)
            # self.platforms.add(p)
        self.mob_timer = 0
        # 遊戲的背景音樂
        pg.mixer.music.load(os.path.join(self.snd_dir, 'Happy Tune.ogg'))
        # 建立雲彩
        for i in range(8):
            c = Cloud(self)
            c.rect.y += 500
        self.run()
複製代碼

最終效果以下。

「跳跳兔」至此開發完啦,Pygame系列的文章也暫時告一段落啦。

「跳跳兔」代碼github:github.com/ayuLiao/jum…

Pygame還有不少有趣的功能在「跳跳兔」遊戲中並無體現出來。

正如本系列第一篇文章所說,這些文章只是學習筆記,此外還有下面兩個遊戲的學習筆記,一個是打飛機、一個是RPG打殭屍遊戲。

若是你們感興趣,記得告訴我,我纔有動力繼續分享,後面按我的計劃應該會以漫畫形式分享算法、計算機基礎方面的東西,但願喜歡。

最後,再次聲明一下,學習內容來自:kidscancode.org/,遊戲並非自主原創的…

若是文章對你有所幫助,請點「在看」給做者一點鼓勵,叩謝豪恩。

相關文章
相關標籤/搜索