2015/11/6用Python寫游戲,pygame入門(6):控制大量的對象


昨天我們已經實現了這個游戲的三個基本類。

但是現在它還是沒辦法做成一個適合玩的游戲,畢竟只有一架敵機的游戲是很乏味的。所以,我們需要好多子彈,也需要好多敵機。

所以,我們要創建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()
    #刷新一下畫面


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM