摘要:和標志,用于表示飛船是否正在移動,用于實現飛船在不松開按鍵下連續移動。重寫了函數,用于繪制飛船模塊該模塊主要是集中處理游戲中發生的各種事件。函數用于監聽游戲的事件,比如,它表示游戲推出事件和分別表示鍵盤按下與松開事件。
《Python編程:從入門到實踐》筆記。1. 準備工作
本章主要學習如何使用pygame編寫一個簡單的小飛機打外星人的游戲,由于本人對用python寫游戲并不是特別感興趣,所以主要是看代碼的構建和一些編程規范,代碼會有所簡略。
Python標準庫中并沒有自帶pygame模塊,所以需要自行安裝,可以在控制臺(Windows下是cmd)上使用命令行安裝:pip install pygame。如果你是用的PyCharm,也可以在設置中安裝:
點擊右邊的加號,在彈出的窗口中輸入pygame,然后安裝即可。
該項目中需要使用一些書中的圖片,這些圖片都可以在 http://www.ituring.com.cn/boo... 中下載到。
2. 游戲基本內容首先需要新建一個項目,筆者取名為“alien_invasion”,并在該項目的根目錄下新建一個images文件夾,用于存放項目中用到的圖片。在本節中,我們將先創建4個文件:
alien_invasion.py:游戲主程序
settings.py:游戲的配置文件
game_functions.py:存放游戲的控制函數,比如響應鼠標、鍵盤等
ship.py:飛船類
2.1 alien_invasion.py模塊:該模塊經過重構后的代碼如下:
import pygame import game_functions as gf from settings import Settings from ship import Ship def run_game(): # 初始化游戲并創建一個屏幕對象 pygame.init() # 初始化背景設置,讓pygame能正常工作 ai_settings = Settings() # 實例化一個游戲配置類 # 返回一個游戲窗口 screen = pygame.display.set_mode( (ai_settings.screen_width, ai_settings.screen_height)) pygame.display.set_caption("Alien Invasion") # 給這個游戲窗口設置一個標題 ship = Ship(ai_settings, screen) # 實例化一個飛船類,傳入了參數ai_settings和屏幕對象screen # 開始游戲的主循環 while True: gf.check_events(ship) # 用于響應游戲事件 ship.update() # 更新飛船狀態 gf.update_screen(ai_settings, screen, ship) # 重繪screen run_game()
①代碼第1行導入pygame模塊,它包含開發游戲所需的基本功能;
②代碼3到5行導入的是自行編寫且經過重構的模塊;
③第9行代碼執行游戲的初始化工作,比如初始化游戲背景等;
④第10行實例化一個游戲配置類,用于配置游戲參數,該類的具體實現見本篇后面的內容;
⑤代碼第12-13行用于生成一個名為screen的顯示窗口,長寬從配置對象ai_settings中讀出;display.set_mode()返回的是一個surface,在pygame中,surface是屏幕的一部分,用于顯示游戲元素,這里的screen表示的是整個游戲窗口。我們激活游戲的循環后,每經過一次循環pygame都將重繪這個screen。
⑥代碼第20行的check_events()函數用于響應游戲中發生的時間,比如鼠標,鍵盤,關閉窗口等。
⑦代碼第21行用于更新飛船的信息,如飛船位置
⑧最后一行用于啟動游戲,即初始化游戲,并開始主循環。
2.2 settings.py模塊該文件主要是游戲的配置信息,存放游戲的各種參數。
class Settings: """存儲《外星人入侵》的所有設置的類""" def __init__(self): """初始化游戲的設置""" # 屏幕設置 self.screen_width = 1200 # 游戲窗口寬度 self.screen_height = 800 # 游戲窗口高度 self.bg_color = (230, 230, 230) # 游戲背景顏色 self.ship_speed_factor = 1.5 # 飛船的移動速度
這里故意將飛船的速度設置為浮點數,也可以是整數。在設置游戲元素的位置時,如果直接使用浮點數,則只會截取整數部分。
2.3 ship.py模塊該模塊描述了一個飛船類的基本內容:
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 # 自定義一個能存儲浮點數的臨時變量,x坐標 self.center = float(self.rect.centerx) # 標志,用于表示是否正在向某個方向移動 self.moving_right = False self.moving_left = False def update(self): """根據移動標志調整飛船的位置""" 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 # 用臨時變量更新rect的centerx,截取截取整數部分 self.rect.centerx = self.center def blitme(self): """在指定位置繪制飛船""" self.screen.blit(self.image, self.rect)
①__init__()中的self.center屬性,代碼將self.rect.centerx即飛船的中心x坐標轉換成浮點數,并將其存儲在self.center中。之所以轉換成浮點數,是因為在settings.py文件中,我們將飛船移動速度設置成了浮點數。
②self.moving_right和self.moving_left標志,用于表示飛船是否正在移動,用于實現飛船在不松開按鍵下連續移動。
③udpate()方法,用于增減飛船的中心位置x坐標(因為飛船只能在底部移動,所以不用改y坐標),并防止飛船移動出游戲窗口。
④重寫了blitme()函數,用于繪制飛船
2.4 game_functions.py模塊該模塊主要是集中處理游戲中發生的各種事件。
import sys import pygame def check_keydown_event(event, ship): """響應按下按鍵""" if event.key == pygame.K_RIGHT: ship.moving_right = True if event.key == pygame.K_LEFT: ship.moving_left = True def check_keyup_event(event, ship): """響應松開按鍵""" if event.key == pygame.K_RIGHT: ship.moving_right = False if 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_event(event, ship) elif event.type == pygame.KEYUP: check_keyup_event(event, ship) def update_screen(ai_settings, screen, ship): """更新屏幕上的圖像,并切換到新屏幕""" # 每次循環時都重繪屏幕 screen.fill(ai_settings.bg_color) ship.blitme() # 讓最近繪制的屏幕可見 pygame.display.flip()
①在pygame中,用K_RIGHT,K_LEFT表示方向按鍵,其實鍵盤上每個鍵在pygame中都有所對于,以K_開頭。check_keydown_event()函數和check_keyup_event()函數都是對下面的check_event()的進一步簡化,這兩個函數的代碼均可以放在check_event()中,但這樣代碼將會很臃腫,結構不清晰。
②check_event()函數用于監聽游戲的事件,比如pygame.QUIT,它表示游戲推出事件;pygame.KEYDOWN和pygame.KEYUP分別表示鍵盤按下與松開事件。本次大循環中(外層的while循環)發生的所有事件都存儲在pygame.event中,我們使用get()方法獲得這些事件。
③在update_screen()函數中,我們使用screen的fill()方法填充窗體的背景色,調用blitme()方法來在窗體中繪制飛船,最后,調用pygame.display.flip()方法讓最近的繪制在窗體中可見。
2.5 運行游戲現在我們運行alien_invasion.py文件,我們將得到如下窗體:
目前功能還比較簡單,只能實現飛船的左右移動。
3. 添加射擊功能為了添加射擊功能,需要先添加一個子彈類。
3.1 Bullet.pyimport pygame from pygame.sprite import Sprite class Bullet(Sprite): # 使用精靈 """一個對飛船發射的子彈進行管理的類""" def __init__(self, ai_settings, screen, ship): """在飛船所處的位置創建一個子彈對象""" super(Bullet, self).__init__() self.screen = screen # 在(0,0)處創建一個表示子彈的矩形,再設置正確的位置 self.rect = pygame.Rect(0, 0, ai_settings.bullet_width, ai_settings.bullet_height) self.rect.centerx = ship.rect.centerx # 從飛機的中央位置射出 self.rect.top = ship.rect.top # 從飛機的頂部射出 # 存儲用浮點數表示的子彈位置,因為子彈只在y軸上運動,所以不需要x坐標 self.y = float(self.rect.y) self.color = ai_settings.bullet_color # 子彈顏色 self.speed_factor = ai_settings.bullet_speed_factor # 子彈速度 def update(self): """向上移動子彈""" # 更新表示子彈位置的浮點數值 self.y -= self.speed_factor # 更新表示子彈的rect的位置 self.rect.y = self.y def draw_bullet(self): """在屏幕上繪制子彈""" pygame.draw.rect(self.screen, self.color, self.rect)
首先我們需要導入pygame模塊以及其中的Sprite類(直譯的話叫做“精靈類”,然而這名字叫的真的很尷尬),它可以讓我們在后面方便批量處理相同類型的同一操作,子彈類繼承自Sprite類。該子彈類并沒有使用圖片,而是直接在screen上繪制矩形用于表示子彈。update()方法用于更新子彈的位置。pygame.draw.rect()用于在screen上繪制子彈。
3.2 修改settings.py在該模塊中添加子彈類的參數:
class Settings: def __init__(self): -- snip -- # 子彈設置 self.bullet_speed_factor = 1 self.bullet_width = 3 self.bullet_height = 15 self.bullet_color = 60, 60, 60 # 表示窗口中最多允許存在的子彈數,當然你也可以將其去掉 self.bullets_allowed = 33.3 修改game_functions.py
游戲中我們按空格鍵發射子彈,并發射子彈的過程多帶帶寫在一個函數fire_bullet()中。為了響應空格鍵,需要修改check_event()函數和check_keydown_event()函數,前者只修改了參數,后者在判斷結構中添加了一個判斷。有了子彈類,那我們還需要在screen中繪制子彈,所以還需要修改update_screen()函數,而子彈自身信息(比如子彈的移動)的修改則放在了一個新的函數update_bullets()中。
import sys import pygame from Bullet import Bullet # 新增函數! def fire_bullet(ai_settings, screen, ship, bullets): """如果還沒有到達限制,就發射一顆子彈""" # 創建新子彈,并將其加入到編組bullets中 # 如果你想讓飛船能無限發射子彈,可以將判斷語句刪除 if len(bullets) < ai_settings.bullets_allowed: new_bullet = Bullet(ai_settings, screen, ship) bullets.add(new_bullet) # 修改了參數! def check_keydown_event(event, ship, ai_settings, screen, bullets): -- snip -- # 按空格鍵發射子彈 elif event.key == pygame.K_SPACE: fire_bullet(ai_settings, screen, ship, bullets) # 修改了參數! def check_events(ai_settings, screen, ship, bullets): """響應按鍵和鼠標事件""" for event in pygame.event.get(): -- snip -- elif event.type == pygame.KEYDOWN: # 增加了參數 check_keydown_event(event, ship, ai_settings, screen, bullets) -- snip -- # 修改了函數! def update_screen(ai_settings, screen, ship, bullets): -- snip -- # 繪制子彈 for bullet in bullets.sprites(): bullet.draw_bullet() -- snip -- # 新增函數 def update_bullets(bullets): """更新子彈的位置,并刪除已消失的子彈""" # 更新子彈的位置 # bullets是個Group對象,調用一次update()就會調用其中所有Sprite對象的update() # 相當于你不用自己寫for循環了 bullets.update() # 刪除已消失的子彈 for bullet in bullets.copy(): if bullet.rect.bottom <= 0: bullets.remove(bullet)
當子彈從窗口中消失時,它并沒有從內存中消失,如果對于已經從屏幕中消失的子彈不做處理的話,時間一長,子彈數一多,光子彈一項的內存占用就會越來越多(土豪請忽略),雖然只是線性增長,但作為一個合格的程序員,應該避免這種無謂的浪費。
3.4 修改alien_invation.py最后,我們修改主程序,在其中添加一個pygame.sprite中的Group對象用于表示子彈集合,以及對該對象的操作代碼。
import pygame from pygame.sprite import Group # 導入一個新類 import game_functions as gf from settings import Settings from ship import Ship def run_game(): -- snip -- bullets = Group() # 開始游戲的主循環 while True: gf.check_events(ai_settings, screen, ship, bullets) ship.update() gf.update_bullets(bullets) gf.update_screen(ai_settings, screen, ship, bullets)3.5運行新代碼
以下是運行截圖:
4. 小結自此,我們創建了一個能開火的小飛機,在下一篇文章中我們將向其中添加外星人。
本篇中的代碼都是經過了重構后的代碼,但是,當我們自己在編程時,如果對某一框架還是小白,搞不清楚該如何組織代碼,那就把所有代碼都寫在一個或幾個文件里(雖然這種習慣很不好),也暫時不用考慮代碼結構之類的問題,因為你的任務是造東西,而不是寫漂亮代碼,用精巧結構,用別人沒看過的語法。兩者能兼備當然更好,但每個人都有當小白的時期,有一定熟練度后,再來考慮代碼重構的問題。
迎大家關注我的微信公眾號"代碼港" & 個人網站 www.vpointer.net ~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/41790.html
摘要:現在開始創建多行外星人。小結本篇講述了如何在游戲中添加大量相同的元素如何用嵌套循環來創建元素網格如何控制對象在屏幕上移動的方向以及響應事件如何檢測和響應元素碰撞如何在游戲中跟蹤統計信息如何使用標志來判斷游戲是否結束。 《Python編程:從入門到實踐》筆記。本章主要是對上一篇的繼續,添加外星人,外星人與飛船的交互。 1. 回顧項目 開發較大的項目時,進入每個開發階段前回顧一下開發計劃,...
摘要:之所以這里要添加這四行代碼,其實是為了當你重新開始也就是第二次及以后點擊按鈕游戲時,計分板能正確顯示。當第一運行游戲時,沒有這四行也能正確顯示計分板。 《Python編程:從入門到實踐》筆記。本篇是Python小游戲《外星人入侵》的最后一篇。 1. 前言 本篇我們將結束Pygame小游戲《外星人入侵》的開發。在本篇中,我們將添加如下內容: 添加一個Play按鈕,用于根據需要啟動游戲以...
摘要:一些知識點有哪些方法方法前端從入門菜鳥到實踐老司機所需要的資料與指南合集前端掘金前端從入門菜鳥到實踐老司機所需要的資料與指南合集歸屬于筆者的前端入門與最佳實踐。 工欲善其事必先利其器-前端實習簡歷篇 - 掘金 有幸認識很多在大廠工作的學長,在春招正式開始前為我提供很多內部推薦的機會,非常感謝他們對我的幫助。現在就要去北京了,對第一份正式的實習工作也充滿期待,也希望把自己遇到的一些問題和...
摘要:年,阿里云在全球范圍內率先發起數據保護倡議。借助阿里云的網絡溯源,警方最終成功抓捕到名犯罪嫌疑人,將黑客組織一網打盡。過去兩年,阿里云已陸續協助警方破獲案件數十起攻擊相關案件,抓捕百余人次。9月28日,阿里云正式發布首個企業云安全架構和《2017阿里云安全白皮書》(以下簡稱白皮書),企業可參考架構指南和白皮書構建安全、穩固的信息化架構。白皮書將用戶隱私和數據安全列為第一原則,并于2015年全...
摘要:最近照著編程從入門到實踐這本書上的內容,開發了第一個完整的項目。之前都是用寫一些腳本什么的,這是第一次開發一個完整的項目,現將在開發過程中的一些心得總結如下。 最近照著《Python編程從入門到實踐》這本書上的內容,開發了第一個完整的Python項目。之前都是用Python寫一些腳本什么的,這是第一次開發一個完整的項目,現將在開發過程中的一些心得總結如下。 這個Python項目是一個小...
閱讀 2074·2021-11-15 17:57
閱讀 739·2021-11-11 16:54
閱讀 2589·2021-09-27 13:58
閱讀 4067·2021-09-06 15:00
閱讀 950·2021-09-04 16:45
閱讀 3505·2019-08-30 15:56
閱讀 1784·2019-08-30 15:53
閱讀 1604·2019-08-30 14:12