昨天我們已經實現了這個游戲的三個基本類。
但是現在它還是沒辦法做成一個適合玩的游戲,畢竟只有一架敵機的游戲是很乏味的。所以,我們需要好多子彈,也需要好多敵機。
所以,我們要創建list,這個list存放Bullet或者Enemy的實例。
以Bullet為例:
bullet = [] #創建子彈 for i in range(6): bullet.append(Bullet()) ... for b in bullet:#移動子彈 b.move(time_passed_second) ... for b in bullet:#顯示子彈 screen.blit(b.image, (b.x, b.y))
我們可以用這樣的代碼替換我們原來創建子彈,移動子彈和顯示子彈的部分。但是實際運行結果卻並沒有變化。這是為什么?
因為一個list的子彈都按照了同樣的方法創建和發射了,所有的子彈在同一時間發射了出去,同時到達了屏幕上方,然后又同時發射。這樣的效果和發射一發子彈是沒有區別的。所以我們要讓它按照一定的時間間隔,一個個地發射。
另外,如果到了屏幕頂端就回頭了,重新發射的子彈和按時發射的子彈混在了一起,打亂了發射節奏,所以子彈回收的方法也要更改。我們可以選擇每發子彈只寫它的發射,不寫它的回收,但是這樣每發射一發子彈就會創建一個空間,讀取一次圖片,這樣會消耗內存資源,一般都應該避免。
那么我們必須解決兩個問題,一個是定時發射,一個是回收子彈。
Python有專門的time模塊,但是,在游戲中,我們本來就有幀率固定的循環,只要用一個計數器來計數,每隔多少個循環出發一次,就可以實現定時效果。
比如說,我們定義一個子彈發射的間隔interval_bullet,讓它遞增或者遞減,到達某個數后,就重置間隔,並且運行特定的程序,就可以使子彈定時發射。
如果要重復利用子彈,我們可以讓子彈本身多一個屬性,來表明這個子彈是否應該被激活,只有它是激活狀態,我們去處理它的運動和顯示。
子彈本身是可以重復利用的,我們用一個循環隊列的結構來處理子彈的利用。
依照這樣的方法,我們可以修改Bullet類:
class Bullet(object): def __init__(self): self.x = 0 self.y = -100 self.speed = 600 self.image = pygame.image.load(bullet_image_filename).convert_alpha() self.active = False def move(self, passed_time_second): if self.y < 0: self.active = False else: self.y -= self.speed*passed_time_second def restart(self): self.active = True mouseX, mouseY = pygame.mouse.get_pos() self.x = mouseX - self.image.get_width()/2 self.y = mouseY - self.image.get_width()/2
添加了一個重新激活該子彈的方法restart(),還添加了一個數據屬性active來標記子彈本身是否被激活。然后,我們把添加子彈,移動子彈,顯示子彈部分的代碼改成這樣:
bullet = [] for i in range(6):#子彈總數量 bullet.append(Bullet()) interval_bullet = 25 #發射子彈的幀數間隔 index_bullet = 0 #初始化子彈坐標 ... interval_bullet -= 1 if interval_bullet <= 0: interval_bullet = 25 bullet[index_bullet].restart() index_bullet = (index_bullet + 1) % 6 for b in bullet: if b.active: b.move(time_passed_second)#移動子彈 screen.blit(b.image, (b.x, b.y))#顯示子彈
結果就是這樣了:
子彈完成了以后,飛機還會遠么?
大家可以自己想一想敵機應該怎么去寫,敵機不同的是,前后的間隔應該有更多的隨機性。
我這里就不給出一步步的指南了,把自己實現的代碼整個貼上來,也許大家有更好的控制方式,可以一起交流一下:
# -*- coding: utf8 -*- background_image_filename = 'background.png' mouse_image_filename = 'hero.png' bullet_image_filename = 'bullet.png' enemy_image_filename = 'enemy.png' #指定圖像文件名稱 import pygame #導入pygame庫 from sys import exit #向sys模塊借一個exit函數用來退出程序 from random import randint #引入隨機數 #定義一個Bullet類,封裝子彈的數據和方法 class Bullet(object): def __init__(self): self.x = 0 self.y = -100 self.speed = 600 self.image = pygame.image.load(bullet_image_filename).convert_alpha() self.active = False def move(self, passed_time_second): if self.y < 0: self.active = False else: self.y -= self.speed*passed_time_second def restart(self): self.active = True mouseX, mouseY = pygame.mouse.get_pos() self.x = mouseX - self.image.get_width()/2 self.y = mouseY - self.image.get_width()/2 class Enemy(object):#定義一個Enemy類,封裝敵機的數據和方法 def restart(self): self.x = randint(-30,400) self.y = randint(-100, -50) self.speed = randint(100,400) self.active = True def __init__(self): self.restart() self.active = False self.image = pygame.image.load(enemy_image_filename).convert_alpha() def move(self, passed_time_second): if self.y < 650: self.y += self.speed*passed_time_second else: self.active = False pygame.init() #初始化pygame,為使用硬件做准備 screen = pygame.display.set_mode((480, 650), 0, 32) #創建了一個窗口 pygame.display.set_caption("PlaneFight!") #設置窗口標題 pygame.mouse.set_visible(False) background = pygame.image.load(background_image_filename).convert() mouse_cursor = pygame.image.load(mouse_image_filename).convert_alpha() #加載並轉換圖像 bullet = [] for i in range(6):#子彈總數量 bullet.append(Bullet()) interval_bullet = 25 #發射子彈的幀數間隔 index_bullet = 0 #初始化子彈坐標 enemy = [] for i in range(10):#敵機總數量 enemy.append(Enemy()) interval_enemy = 100 #敵機出現的間隔 index_enemy = 0 #初始化敵機坐標 clock = pygame.time.Clock() while True: #游戲主循環 for event in pygame.event.get(): if event.type == pygame.QUIT: #接收到退出事件后退出程序 pygame.quit() exit() time_passed = clock.tick(100) time_passed_second = time_passed/1000.0 screen.blit(background, (0,0)) #將背景圖畫上去 x, y = pygame.mouse.get_pos() #獲得鼠標位置 interval_bullet -= 1 if interval_bullet <= 0: interval_bullet = 25 bullet[index_bullet].restart()#重置子彈 index_bullet = (index_bullet + 1) % 6 #循環遞增 for b in bullet: if b.active: b.move(time_passed_second)#移動子彈 screen.blit(b.image, (b.x, b.y))#顯示子彈 interval_enemy -= 1 if interval_enemy <= 0: interval_enemy = randint(30,100) enemy[index_enemy].restart() #重置飛機 index_enemy = (index_enemy + 1) % 10 #循環遞增 for e in enemy: if e.active: e.move(time_passed_second) #移動敵機 screen.blit(e.image, (e.x, e.y)) #顯示敵機 x-= mouse_cursor.get_width() / 2 y-= mouse_cursor.get_height() / 2 #計算光標的左上角位置 #screen.blit(bullet.image, (bullet.x, bullet.y)) screen.blit(mouse_cursor, (x, y)) #把各個元素畫上去 pygame.display.update() #刷新一下畫面