python飛機大戰系列文章(按順序)
(一)通過pygame 將自己的圖像添加到遊戲中
(二)通過pygame讓遊戲人物 動起來
(三)通過pygame處理用戶的鼠標鍵盤操作(事件和監聽
(四)詳解pygame中的精靈和精靈組
(五)通過pygame搭建遊戲框架
(六)通過pygame讓遊戲背景圖像實現交替滾動
(七)通過pygame來設置飛機大戰中 敵機 的速度、位置等
(八)通過pygame來操控遊戲人物的移動
(九)通過pygame使遊戲人物發射子彈
(十)通過pygame來進行碰撞檢測
原理
在遊戲中,需要如何將遊戲的背景實現交替滾動?
- 利用運動是相對的
遊戲啓動後,背景圖像會連續不斷地向下方移動,在視覺上就會產生英雄的飛機不斷向上方飛行的錯覺,這在很多跑酷類遊戲中是常見的
如果只是單單一張背景圖向下移動,如下圖所示,可以看到,如果只是一張背景圖向下移動的話,那麼遊戲主界面上方就會出現沒有背景圖的情況(紅色區域)
那麼要怎麼解決這個問題呢??
- 用兩張一樣的背景圖,另一張疊放在屏幕的正上方(如下圖)
讓兩張背景圖像同時向下移動,那麼上文所說的“紅色區域”就會被“暫時”遮住,但是在第1張背景圖完全移出背景圖像之後,第2張背景就又會產生沒有背景圖的情況
那麼怎麼解決這個問題呢?
當第一張圖像完全移出屏幕後,立馬又移到第二張圖像的正上方,這樣循環,週而復始,就可以實現背景圖的循環滾動了
解決辦法
- 創建兩張背景圖像精靈,第一張完全和圖像屏幕重合,第二張在屏幕的正上方
- 兩張圖一起向下方運動:
self.rect.y += self.speed
- 當任意背景精靈的
rect.y >= 屏幕高度
說明已經完全移出了屏幕 - 將移動到屏幕下方的這張圖像設置到屏幕的正上方
rect.y = -rect.height
(將y值設置成圖像高度的負值)
具體代碼
因爲之前的GameSprite類中的update方法只是讓遊戲精靈的y值跟遊戲精靈的速度進行了相加,但是並沒有根據精靈移出屏幕進行判斷,我們想要的是當一個圖像移出屏幕之後,將圖像再移動到屏幕的正上方,從而實現交替滾動
所以如果在繼承中,父類提供的方法不能滿足子類的需求,我們需要怎麼做?
- 從父類中派生出一個子類
- 在子類中針對特有的需求,重寫父類方法,對父類的方法進行擴展
我們可以派生出一個背景類,在背景類中重寫update方法
plane_sprites.py 代碼爲:
import pygame
#屏幕大小的常量
SCREEN_RECT = pygame.Rect(0,0,480,700)
#刷新的幀率
FRAME_PER_SEC = 60
class GameSprite(pygame.sprite.Sprite):
"""飛機大戰遊戲精靈"""
def __init__(self, image_name, speed=1):
#調用父類的初始化方法
super().__init__()
#定義對象屬性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
#在屏幕垂直方向上移動
self.rect.y += self.speed
class Background(GameSprite):
"""遊戲背景精靈"""
def update(self):
#調用父類的方法實現:垂直移動
super().update()
#判斷是否移出屏幕,若移出屏幕,應該將圖像設置到圖像上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
plane_main.py 代碼爲:
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飛機大戰主遊戲"""
def __init__(self):
print("遊戲初始化")
#創建遊戲窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
#創建遊戲的時鐘
self.clock = pygame.time.Clock()
#調用私有方法,精靈和精靈組的創建
self.__create_sprites()
def __create_sprites(self):
#創建背景精靈和精靈組
bg1 = Background('./images/background.png')
bg2 = Background('./images/background.png')
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
def start_game(self):
print("遊戲開始")
while True:
#設置刷新幀率
self.clock.tick(FRAME_PER_SEC)
#事件監聽
self.__event_handler()
#碰撞檢測
self.__check_collide()
#更新/繪製精靈組
self.__update_sprites()
#更新顯示
pygame.display.update()
def __event_handler(self):
for event in pygame.event.get():
#判斷是否退出遊戲
if event.type == pygame.QUIT:
PlaneGame.__game_over()
def __check_collide(self):
pass
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
#沒有使用對象屬性和類屬性,所以定義爲靜態方法
@staticmethod
def __game_over():
print("遊戲結束")
pygame.quit()
exit()
if __name__ == '__main__':
#創建遊戲對象
game = PlaneGame()
#啓動遊戲
game.start_game()
改進
def __create_sprites(self):
#創建背景精靈和精靈組
bg1 = Background('./images/background.png')
bg2 = Background('./images/background.png')
bg2.rect.y = -bg2.rect.height
self.back_group = pygame.sprite.Group(bg1, bg2)
上面的代碼中,創建的兩個背景精靈,傳入了相同的圖像文件路徑,精靈的初始位置應該由精靈自己負責,而不是由主程序負責。
- 根據面向對象設計原則,應該將對象的職責,封裝到類的代碼內部
- 儘量簡化程序調用一方的代碼調用
is_alt判斷是否是另一張圖像
- False 表示第一張圖像,需要與屏幕重合
- True 表示另一張圖像,在屏幕正上方
修改後的代碼爲:
class Background(GameSprite):
"""遊戲背景精靈"""
def __init__(self, is_alt=False):
# 調用父類方法實現精靈的創建(image/rect/speed)
super().__init__("./images/background.png")
# 判斷是否是交替圖像,如果是,需要設置初始位置
if is_alt:
self.rect.y = -self.rect.height
def update(self):
#調用父類的方法實現:垂直移動
super().update()
#判斷是否移出屏幕,若移出屏幕,應該將圖像設置到圖像上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
def __create_sprites(self):
#創建背景精靈和精靈組
bg1 = Background()
bg2 = Background(is_alt=True)
self.back_group = pygame.sprite.Group(bg1, bg2)
完整代碼如下:
plane_sprites.py
import pygame
#屏幕大小的常量
SCREEN_RECT = pygame.Rect(0,0,480,700)
#刷新的幀率
FRAME_PER_SEC = 60
class GameSprite(pygame.sprite.Sprite):
"""飛機大戰遊戲精靈"""
def __init__(self, image_name, speed=1):
#調用父類的初始化方法
super().__init__()
#定義對象屬性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speed = speed
def update(self):
#在屏幕垂直方向上移動
self.rect.y += self.speed
class Background(GameSprite):
"""遊戲背景精靈"""
def __init__(self, is_alt=False):
# 調用父類方法實現精靈的創建(image/rect/speed)
super().__init__("./images/background.png")
# 判斷是否是交替圖像,如果是,需要設置初始位置
if is_alt:
self.rect.y = -self.rect.height
def update(self):
#調用父類的方法實現:垂直移動
super().update()
#判斷是否移出屏幕,若移出屏幕,應該將圖像設置到圖像上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
plane_main.py
import pygame
from plane_sprites import *
class PlaneGame(object):
"""飛機大戰主遊戲"""
def __init__(self):
print("遊戲初始化")
#創建遊戲窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
#創建遊戲的時鐘
self.clock = pygame.time.Clock()
#調用私有方法,精靈和精靈組的創建
self.__create_sprites()
def __create_sprites(self):
#創建背景精靈和精靈組
bg1 = Background()
bg2 = Background(is_alt=True)
self.back_group = pygame.sprite.Group(bg1, bg2)
def start_game(self):
print("遊戲開始")
while True:
#設置刷新幀率
self.clock.tick(FRAME_PER_SEC)
#事件監聽
self.__event_handler()
#碰撞檢測
self.__check_collide()
#更新/繪製精靈組
self.__update_sprites()
#更新顯示
pygame.display.update()
def __event_handler(self):
for event in pygame.event.get():
#判斷是否退出遊戲
if event.type == pygame.QUIT:
PlaneGame.__game_over()
def __check_collide(self):
pass
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
#沒有使用對象屬性和類屬性,所以定義爲靜態方法
@staticmethod
def __game_over():
print("遊戲結束")
pygame.quit()
exit()
if __name__ == '__main__':
#創建遊戲對象
game = PlaneGame()
#啓動遊戲
game.start_game()