前言
??上篇文章我們給大家詳細介紹了飛船相關素材的下載以及創建了一個ship類,并且在螢屏上出現了飛船,最后,又向大家介紹了模塊的重構,讓我們的代碼更加具有可用性和可擴展性,進一步使得我們的代碼更具有魯棒性,本文繼續給大家介紹武裝飛船的相關內容,首先給大家介紹駕駛飛船,
一、駕駛飛船
??下面來讓玩家能夠左右移動飛船,為此,我們將撰寫代碼,在用戶按左或右箭頭鍵時作出回應,我們將首先專注于向右移動,再使用同樣的原理來控制向左移動,通過這樣做,你將學會如何控制螢屏影像的移動,
1、回應按鍵
??每當用戶按鍵時,都將在Python中注冊一個事件,事件都是通過方法pygame.event.get()獲取的,因此在函式check_events()中,我們需要指定要檢查哪些型別的事件,每次按鍵都被注冊為一個KEYDOWN事件,
??檢測到KEYDOWN事件時,我們需要檢查按下的是否是特定的鍵,例如,如果按下的是右箭頭鍵,我們就增大飛船的rect.centerx值,將飛船向右移動:
import sys
import pygame
def check_events(ship):
"""回應按鍵和滑鼠事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
# 向右移動飛機
ship.rect.centerx += 1
def update_screen(ai_settings, screen, ship):
"""更新螢屏上的影像,并切換到新螢屏"""
# 每次回圈時都重繪螢屏
screen.fill(ai_settings.bg_color)
ship.blitme()
# 讓最近繪制的螢屏可見
pygame.display.flip()
??我們在函式check_events()中包含形參ship,因為玩家按右箭頭時,需要將飛機向右移動,在函式check_events()內部,我們在事件回圈中添加了elif代碼塊,以便在Pygame檢測到KEYDOWN事件時作出相應,我們讀取屬性event.key,以檢查按下的是否是右箭頭鍵(pygame.K_PIGHT),如果按下的是右箭頭鍵,就將ship.rect.centerx的值加1,從而將飛船向右移動,
??在alien_invasion.py中,我們需要更新呼叫的check_events()代碼,將ship作為實參傳遞給它:
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化游戲并創建一個螢屏物件
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alian Invasion")
# 創建一艘飛船
ship = Ship(screen)
# 開始游戲的主回圈
while True:
# 監視鍵盤和滑鼠事件
gf.check_events(ship)
# 每次回圈時都重繪螢屏
gf.update_screen(ai_settings, screen, ship)
run_game()
??如果我們現在運行alien_invasion.py,則每次按右箭頭一次,飛船都將向右移動一個像素,這里實在不方便演示,表示抱歉,這是一個開端,但并非控制飛船的高效方式,下面我們來改進控制方式,允許持續移動,
2、允許不斷移動
??玩家按住右鍵頭不放時,我們希望飛船不斷地向右移動,直到玩家松開為止,我們將讓游戲檢測pygame.KEYUP事件,以便玩家松開右箭頭鍵時我們能夠知道一點;然后,我們將結合使用KEYDOWN和KEYUP事件,以及一個名為moving_right的標志來實作持續移動,
??飛船不棟時,標志moving_right將為FALSE,玩家按下右箭頭鍵時,我們將這個標志設定為True;而玩家松開時,我們將這個標志重新設定為False,
??飛船的屬性都由ship類控制,因此,我們將給這個類添加了一個名為moving_right的屬性和一個名為update()的方法,方法update()檢查標志著moving_right的狀態,如果這個標志為True,就調整飛船的裝置,每當需要調整飛船的位置時,我們都呼叫這個方法,我們接下來對對Ship類所做的修改:
import pygame
class Ship():
def __init__(self, screen):
"""初始化飛船并設定其初始化位置"""
self.screen = screen
# 加載飛船影像并獲取其外接矩陣
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# 將每艘新飛船放在螢屏底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 移動標志
self.moving_right = False
def update(self):
"""根據移動標志調整飛船的位置"""
if self.moving_right:
self.rect.centerx += 1
def blitme(self):
"""在指定位置繪制飛船"""
self.screen.blit(self.image, self.rect)
??在方法__init__()中,我們添加了屬性self.moving_right,并將其初始值設定為False,接下來,我們添加了方法update(),它在前述標志為True時向右移動飛船,
??下面修改check_events(),使其再玩家按下右箭頭鍵時將moving_right設定為True,并在玩家松開時將moving_right設定為False,
import sys
import pygame
def check_events(ship):
"""回應按鍵和滑鼠事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
def update_screen(ai_settings, screen, ship):
"""更新螢屏上的影像,并切換到新螢屏"""
# 每次回圈時都重繪螢屏
screen.fill(ai_settings.bg_color)
ship.blitme()
# 讓最近繪制的螢屏可見
pygame.display.flip()
??我們首先修改了游戲在玩家按下右箭頭鍵時回應的方式:不直接調整飛船的位置,而只是將moving_right設定為True,接著我們添加一個新的elif代碼塊,用于回應KEYUP事件;玩家松開右箭頭鍵(K_RIGHT)時,我么將moving_right設定為False,
??最后,我們需要修改alien_invasion.py中的while回圈,以便每次執行回圈時都會呼叫飛船的方法update():
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化游戲并創建一個螢屏物件
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alian Invasion")
# 創建一艘飛船
ship = Ship(screen)
# 開始游戲的主回圈
while True:
# 監視鍵盤和滑鼠事件
gf.check_events(ship)
ship.update()
# 每次回圈時都重繪螢屏
gf.update_screen(ai_settings, screen, ship)
run_game()
??飛船的位置將在檢測到鍵盤事件后(但在更新螢屏前)更新,這樣玩家輸入時,飛船的位置將更新,從而確保使用更新后的位置將更新,從而確保使用更新后的位置將飛船繪制到螢屏上,
?&emsp如果我們現在運行alien_invasion.py并按住右箭頭鍵,飛船將不斷地向右移動,直到松開為止,不過,無法錄屏,大家感興趣的可以敲代碼實作一下,自己可以看看效果,
3、左右移動
??飛船能夠不斷地向右移動后,添加向左移動的邏輯很容易,我們將再次修改ship類和函式check_events(),下面顯示了對Ship類的方法__init__()和update()所做的相關修改:
import pygame
class Ship():
def __init__(self, screen):
"""初始化飛船并設定其初始化位置"""
self.screen = screen
# 加載飛船影像并獲取其外接矩陣
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# 將每艘新飛船放在螢屏底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 移動標志
self.moving_right = False
self.moving_left = False
def update(self):
"""根據移動標志調整飛船的位置"""
if self.moving_right:
self.rect.centerx += 1
if self.moving_left:
self.rect.centerx -= 1
def blitme(self):
"""在指定位置繪制飛船"""
self.screen.blit(self.image, self.rect)
??在方法__init__()中,我們添加了屬性self.moving_left,在方法update()中,我們添加了一個if代碼塊而不是elif代碼塊,這樣如果玩家同時按下左右鍵箭頭,將先增大飛船的rect_centrix值,再降低這個值,即飛船的位置保持不變,如果使用一個elif代碼塊來處理向右左移動的情況,右箭頭鍵將始終處于優先地位,從向左移動切換到向右移動時,玩家可能同時按住左右箭頭鍵,在這種情況下,前面介紹的方法讓移動更加準確,
??我們還需要對check_events()作兩方面的調整:
import sys
import pygame
def check_events(ship):
"""回應按鍵和滑鼠事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def update_screen(ai_settings, screen, ship):
"""更新螢屏上的影像,并切換到新螢屏"""
# 每次回圈時都重繪螢屏
screen.fill(ai_settings.bg_color)
ship.blitme()
# 讓最近繪制的螢屏可見
pygame.display.flip()
??如果因玩家按下K_LEFT鍵而觸發了KEYDOWN事件,我們就將moving_left設定為True;如果因玩家K_LEFT而觸發了KEYUP事件,我們就將moving_left設定為False,這里之所以可以使用elif代碼塊,是因為每個事件都只與一個鍵相關聯;如果玩家同時按下了左右箭頭鍵,將會檢測到兩個不同的事件,
??如果此時運行alien_invasion.py,就能夠不斷地左右移動飛船;如果我們同時按左右箭頭鍵,飛船將紋絲不動,
??下面來進一步優化飛船的移動方式,調整飛船的速度;限制飛船的移動距離,以免它移動到螢屏外面去,
4、調整飛船的速度
??當前,每次執行while回圈時,飛船最多移動一個像素,但我們可以在Settings類中添加屬性ship_speed_factor,用于控制飛船的速度,我們將根據這個屬性決定飛船在每次回圈時最多移動多少距離,下面演示了如何在settings.py中添加這個新屬性:
class Settings():
"""存盤《外星人入侵》的所有設定類"""
def __init__(self):
"""初始化游戲的設定"""
# 螢屏的設定
self.screen_width = 900
self.screen_height = 600
self.bg_color = (230, 230, 230)
# 飛船的設定
self.ship_speed_factor = 1.5
??我們將ship_speed_factor的初始值設定成了1.5.需要移動飛船時,我們將移動1.5像素而不是1像素,通過將速度設為指定的小數值,可在后面加快游戲的節奏時更細致地控制飛船的速度,然而,rect的centerx等屬性只能存盤數值,因此,我們需要對視頻類做些修改:
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""初始化飛船并設定其初始化位置"""
self.screen = screen
self.ai_settings = ai_settings
# 加載飛船影像并獲取其外接矩陣
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# 將每艘新飛船放在螢屏底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 在飛船的屬性center中存盤小數值
self.center = float(self.rect.centerx)
# 移動標志
self.moving_right = False
self.moving_left = False
def update(self):
"""根據移動標志調整飛船的位置"""
# 更新飛船的center值,而不是rect
if self.moving_right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left:
self.center -= self.ai_settings.ship_speed_factor
# 根據self.center更新rect物件
self.rect.centerx = self.center
def blitme(self):
"""在指定位置繪制飛船"""
self.screen.blit(self.image, self.rect)
??我們首先在__init__()的形參串列中添加了ai_settings,讓飛船能夠獲取其速度設定,接下來,我們將形參ai_settings的值存盤在一個屬性中,以便能夠在updates()中使用它,鑒于現在調整飛船的位置時,將增加或減去一個單位的像素的小數值,因此,需要將位置存盤在一個能夠存盤小數值的變數中,可以使用小數來設定rect的屬性,但rect將只存盤這個值的整數部分,為準確地存盤飛船的位置,我們定義了一個可存盤小數值的新屬性self.center,我們使用函式float()將self.rect.centerx的值轉換為小數,并將結果存盤到self.center中,
??現在在update()中調整了飛船的位置時,將self.center的值增加或減去ai_settings.ship_speed_factor的值,更新self.center后,我們再根據它來更新控制飛船的位置的self.rect.centerx,self.rect.centerx將存盤self.center的整數部分,但對于顯示飛船而言,則問題不是很大,
self.center在alien_invasion.py中創建Ship實體時,需要傳入實參ai_settings:
import sys
import pygame
from settings import Settings
from ship import Ship
import game_functions as gf
def run_game():
# 初始化游戲并創建一個螢屏物件
pygame.init()
ai_settings = Settings()
screen = pygame.display.set_mode((ai_settings.screen_width, ai_settings.screen_height))
pygame.display.set_caption("Alian Invasion")
# 創建一艘飛船
ship = Ship(ai_settings, screen)
# 開始游戲的主回圈
while True:
# 監視鍵盤和滑鼠事件
gf.check_events(ship)
ship.update()
# 每次回圈時都重繪螢屏
gf.update_screen(ai_settings, screen, ship)
run_game()
??現在,只要ship_speed_factor的值大于1,飛船的速度就會比以往更快,這有助于讓飛船的反應速度足夠快,能夠將外星人射下來,還讓我們能夠隨著游戲的進行加快游戲的節奏,
5、限制飛船的活動范圍
??當前,如果玩家按住箭頭鍵的時間足夠長,飛船將移到螢屏外面,消失得無影無蹤,下面來修復這種問題,讓飛船到達螢屏邊緣后停止移動,為此,我們將修改Ship類的方法update():
import pygame
class Ship():
def __init__(self, ai_settings, screen):
"""初始化飛船并設定其初始化位置"""
self.screen = screen
self.ai_settings = ai_settings
# 加載飛船影像并獲取其外接矩陣
self.image = pygame.image.load('images/ship.bmp')
self.rect = self.image.get_rect()
self.screen_rect = screen.get_rect()
# 將每艘新飛船放在螢屏底部中央
self.rect.centerx = self.screen_rect.centerx
self.rect.bottom = self.screen_rect.bottom
# 在飛船的屬性center中存盤小數值
self.center = float(self.rect.centerx)
# 移動標志
self.moving_right = False
self.moving_left = False
def update(self):
"""根據移動標志調整飛船的位置"""
# 更新飛船的center值,而不是rect
if self.moving_right and self.rect.right < self.screen_rect.right:
self.center += self.ai_settings.ship_speed_factor
if self.moving_left and self.rect.left > 0:
self.center -= self.ai_settings.ship_speed_factor
# 根據self.center更新rect物件
self.rect.centerx = self.center
def blitme(self):
"""在指定位置繪制飛船"""
self.screen.blit(self.image, self.rect)
??上述代碼在修改self.center的值之前先檢查飛船的位置,self.rect.right回傳飛船外接矩陣的右邊緣的x坐標,如果這個值小于self.screen_rect.right的值,就說明飛船未觸及螢屏右邊緣,左邊緣的情況與此類似;如果rect的左邊緣的x坐標大于零,就說明飛船未觸及螢屏左邊緣,這確保僅當飛船在螢屏內時,才調整self.center的值,
??如果此時運行alien_invasion.py,飛船將在觸及螢屏左邊緣或右邊緣后停止移動,
6、重構check_envents()
??隨著游戲開發的進行,函式check_events()將越來越長,我們將其部分代碼放在兩個函式中;一個處理KEYDOWN事件,另一個處理KEYUP事件:
import sys
import pygame
def check_keydown_events(event, ship):
"""回應按鍵"""
if event.key == pygame.K_RIGHT:
ship.moving_right = True
elif event.key == pygame.K_LEFT:
ship.moving_left = True
def check_keyup_events(event, ship):
"""回應松開"""
if event.key == pygame.K_RIGHT:
ship.moving_right = False
elif event.key == pygame.K_LEFT:
ship.moving_left = False
def check_events(ship):
"""回應按鍵和滑鼠事件"""
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
check_keydown_events(event, ship)
elif event.type == pygame.KEYUP:
check_keyup_events(event, ship)
def update_screen(ai_settings, screen, ship):
"""更新螢屏上的影像,并切換到新螢屏"""
# 每次回圈時都重繪螢屏
screen.fill(ai_settings.bg_color)
ship.blitme()
# 讓最近繪制的螢屏可見
pygame.display.flip()
??我們創建了兩個新函式:check_keydown_events()和check_keyup_events(),它們都包含形參event和ship,這兩個函式的代碼是從check_events()中復制而來的,因此我們將函式check_events中相應的代碼替換成了對這兩個函式的呼叫,現在,函式check_events()更簡單,代碼的結構更加的清晰,這樣,在其中回應其他玩家輸入時將更容易,也讓我們的代碼更有邏輯性,擴展性更強,魯棒性更好,
二、簡單回顧
??我們飛船的所有代碼已經結束,下篇文章就是給大家介紹飛船設計子彈的功能,在這之前,我們在本文即將結束之際給大家簡單回顧一下之前我們飛船中所有檔案的主要功能,目前我們有四個檔案,其中包含很多類、函式和方法,添加其他功能之后,為了讓大家清楚這個專案的組織結構,我們一起回顧一下這寫檔案:
1、alien_inversion.py
??主檔案alien_inversion.py創建了一系列整個游戲都要用到的物件;存盤在ai_settings中的設定、存盤在screen中的主要顯示surface以及一個飛船的實體,檔案alien_inversion.py還包含游戲中的主回圈,這是一個要呼叫check_events()、ship.update()和update_screen()的while回圈,
??要玩游戲《外星人入侵》,我們只需要運行檔案alien_inversion.py,其他檔案(settings.py、game_funcation.py、ship.py)包含的代碼被直接或間接地匯入這個檔案中,
2、setting.py
??檔案settings.py包含settings類,這個類只包含方法__init__(),它初始化控制游戲外觀和飛船速度的屬性,
3、game_funcation.py
??檔案game_funcation.py包含一系列函式,游戲的大部分作業都是由它們完成的,函式check_events()檢測相關的事件,如按鍵和松開,并使用輔助函式check_keydown_events()和check_keyup_events()來處理這些事情,就目前而言,這些函式管理飛船的移動,模塊game_funcations還包含函式update_screen(),它用于在每次執行主回圈時都重繪螢屏,
4、ship.py
??檔案ship.py包含Ship類,這個類包含方法__init__()、管理飛船位置的方法update()以及在螢屏上繪制飛船的方法blitme(),表示飛船的影像存盤在images下的檔案ship.bmp中,
總結
??上篇文章我們給大家詳細介紹了飛船相關素材的下載以及創建了一個ship類,并且在螢屏上出現了飛船,最后,又向大家介紹了模塊的重構,讓我們的代碼更加具有可用性和可擴展性,進一步使得我們的代碼更具有魯棒性,本文給大家介紹飛船駕駛功能的實作;即通過左右箭頭鍵來控制我們的飛船,并且提高了飛船的運行速度,最后限制飛船只能在本螢屏之內,由于本文的效果均是動態的,本人受條件所限,無法錄視頻,因此,本文只有代碼,沒有視頻,大家感興趣的可以自己動手將代碼敲一遍,感受一下該游戲的效果,為了讓大家更好的吸收專案所用到的知識點,我們每一篇文章只給大家實作《外星人入侵》的一個功能,所以,希望大家能夠仔細閱讀,認真跟著寫代碼,理解其中的深入含義,吧這個專案的價值發揮到最大,其實這個專案已經很典型,代碼到處都是,但是,如果你只是簡單的粘貼復制,對你知識的學習沒有任何的價值,你還是得跟著過一遍,然后要知道每行代碼的含義或者是用到了前面我們介紹的哪一塊知識點,只有這樣,這個專案才會發揮不一樣的價值,希望大家認真學習,把基礎知識打扎實一點,Python是一門注重實際操作的語言,它是眾多編程語言中最簡單,也是最好入門的,當你把這門語言學會了,再去學習java、go以及C語言就比較簡單了,當然,Python也是一門熱門語言,對于人工智能的實作有著很大的幫助,因此,值得大家花時間去學習,生命不息,奮斗不止,我們每天努力,好好學習,不斷提高自己的能力,相信自己一定會學有所獲,加油!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297656.html
標籤:其他
