經過前面九篇文章的編寫,「跳跳兔」遊戲基本已經被編寫出來了,本節在此基礎上進一步完善它,並添加上雲彩背景。python
添加雲彩背景的大體步驟以下。git
一步步來編寫,首先是建立雲彩類,代碼以下。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/,遊戲並非自主原創的…
若是文章對你有所幫助,請點「在看」給做者一點鼓勵,叩謝豪恩。