(六)通過pygame讓遊戲背景圖像實現交替滾動


python飛機大戰系列文章(按順序)
(一)通過pygame 將自己的圖像添加到遊戲中
(二)通過pygame讓遊戲人物 動起來
(三)通過pygame處理用戶的鼠標鍵盤操作(事件和監聽
(四)詳解pygame中的精靈和精靈組
(五)通過pygame搭建遊戲框架
(六)通過pygame讓遊戲背景圖像實現交替滾動
(七)通過pygame來設置飛機大戰中 敵機 的速度、位置等
(八)通過pygame來操控遊戲人物的移動
(九)通過pygame使遊戲人物發射子彈
(十)通過pygame來進行碰撞檢測



原理

在遊戲中,需要如何將遊戲的背景實現交替滾動?

  • 利用運動是相對的

遊戲啓動後,背景圖像會連續不斷地向下方移動,在視覺上就會產生英雄的飛機不斷向上方飛行的錯覺,這在很多跑酷類遊戲中是常見的

如果只是單單一張背景圖向下移動,如下圖所示,可以看到,如果只是一張背景圖向下移動的話,那麼遊戲主界面上方就會出現沒有背景圖的情況(紅色區域)

在這裏插入圖片描述
那麼要怎麼解決這個問題呢??

  • 用兩張一樣的背景圖,另一張疊放在屏幕的正上方(如下圖)

在這裏插入圖片描述

讓兩張背景圖像同時向下移動,那麼上文所說的“紅色區域”就會被“暫時”遮住,但是在第1張背景圖完全移出背景圖像之後,第2張背景就又會產生沒有背景圖的情況
在這裏插入圖片描述
那麼怎麼解決這個問題呢?
當第一張圖像完全移出屏幕後,立馬又移到第二張圖像的正上方,這樣循環,週而復始,就可以實現背景圖的循環滾動了
在這裏插入圖片描述

解決辦法

  1. 創建兩張背景圖像精靈,第一張完全和圖像屏幕重合,第二張在屏幕的正上方
  2. 兩張圖一起向下方運動:self.rect.y += self.speed
  3. 當任意背景精靈的 rect.y >= 屏幕高度 說明已經完全移出了屏幕
  4. 將移動到屏幕下方的這張圖像設置到屏幕的正上方 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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章