用pygame回顧飛機(jī)大戰(zhàn)
回復(fù)“書籍”即可獲贈(zèng)Python從入門到進(jìn)階共10本電子書
本文主要內(nèi)容
通過(guò)例子示范窗口繪制及其所需函數(shù)簡(jiǎn)要說(shuō)明
圖片移動(dòng)、通過(guò)用戶事件移動(dòng)圖片及所需函數(shù)簡(jiǎn)要說(shuō)明
碰撞檢測(cè)及所需函數(shù)簡(jiǎn)要說(shuō)明
音頻加載及所需函數(shù)簡(jiǎn)要說(shuō)明
成果展示
環(huán)境
python3.6+
windows/linux
模塊安裝
pip?install?pygame
游戲窗口建立及所需函數(shù)簡(jiǎn)要說(shuō)明
import?os
import?time
import?pygame
#?屏幕寬度
SCREEN_WIDTH?=?500
#?屏幕高度
SCREEN_HEIGHT?=?250
#?圖片絕對(duì)路徑
IMG_PATH?=?os.path.join(os.getcwd(),?"img")
def?main():
???#?初始化顯示模塊
???pygame.display.init()
???#?創(chuàng)建窗口
???screen?=?pygame.display.set_mode((SCREEN_WIDTH,?SCREEN_HEIGHT))
???#?設(shè)置窗口標(biāo)題
???pygame.display.set_caption("python小demo?飛機(jī)大戰(zhàn)")
???#?設(shè)置窗口icon
???pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH,?"icon.jpg")))
???#?加載背景圖片
???background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
???while?True:
???????#?將背景圖片繪制到窗口上
???????screen.blit(background,?(0,?0))
???????#?更新屏幕上內(nèi)容
???????pygame.display.update()
???????time.sleep(0.02)
if?__name__?==?"__main__":
???main()
查看下效果:

x、y是我手動(dòng)繪制的,讓大家可以更加直觀的看到窗口坐標(biāo)軸情況
所需函數(shù)簡(jiǎn)要說(shuō)明
pygame.display pygame用來(lái)控制屏幕和窗口
https://www.pygame.org/docs/ref/display.html
display.init()?->?None
#?該函數(shù)只做初始化顯示模塊,且不返回任何東西
#?如果在使用display其他方法未初始化,會(huì)自動(dòng)調(diào)用
display.set_mode(size=(0,?0),?flags=0,?depth=0,?display=0,?vsync=0)?->?Surface
#?該函數(shù)會(huì)創(chuàng)建并返回一個(gè)Surface的窗口對(duì)象
#?參數(shù):
#???size=(0,?0)?設(shè)置窗口大小,第一個(gè)是屏幕寬度,第二個(gè)是窗口高度
#?? flags 控制您想要的顯示類型,例如是否全屏,可選參數(shù):
#?????? pygame.FULLSCREEN:創(chuàng)建一個(gè)全屏
#?????? pygame.DOUBLEBUF:雙緩沖模式,推薦和HWSURFACE或OPENGL一起使用
#?????? pygame.HWSURFACE:硬件加速,只有在 FULLSCREEN 下可以使用
#?????? pygame.OPENGL:創(chuàng)建一個(gè) OPENGL 渲染的顯示
#?????? pygame.RESIZABLE:創(chuàng)建一個(gè)可調(diào)整尺寸的窗口
#?????? pygame.NOFRAME:創(chuàng)建一個(gè)沒有邊框和控制按鈕的窗口
#???????可以使用按位或選擇多個(gè)參數(shù),如:
#???????????flags?=?pygame.OPENGL?|?pygame.FULLSCREEN
#???depth?參數(shù)表示顏色位數(shù),不建議傳遞,默認(rèn)會(huì)選擇最佳的顏色深度
#???display?窗口索引,默認(rèn)0
#???vsync?傳入1時(shí),可以獲得垂直同步顯示,只有同時(shí)設(shè)置了pygame.OPENGL、
#???pygame.FULLSCREEN才能傳值
display.set_caption(title,?icontitle=None)?->?None
#?設(shè)置窗口標(biāo)題
#?參數(shù):
#???title?窗口的標(biāo)題
#???icontitle?部分系統(tǒng)支持最小窗口時(shí)切換標(biāo)題欄
display.set_icon(Surface)?->?None
#?設(shè)置窗口LOGO
#?參數(shù):
#???Surface?可以傳入任何Surface對(duì)象作為圖標(biāo),但大多數(shù)系統(tǒng)要求大小是32*32
display.update(rectangle=None)?->?None
display.update(rectangle_list)?->?None
#?更新屏幕內(nèi)容顯示,如果設(shè)置了pygame.OPENGL情況下調(diào)用,會(huì)觸發(fā)異常
#?參數(shù):
#???rectangle?一個(gè)矩形區(qū)域
#???rectangle_list?多個(gè)矩形區(qū)域
#?如果傳入None或者空列表,就會(huì)更新整個(gè)窗口
pygame.image pygame用于傳輸圖像模塊
https://www.pygame.org/docs/ref/image.html
image.load(filename)?->?Surface
#?加載圖像,返回一個(gè)Surface對(duì)象,pygame支持常見PNG、JPG、GIF等格式圖片
#參數(shù):
#???filename?圖片路徑,兼容運(yùn)行環(huán)境,路徑建議通過(guò)os.path.join()獲取
pygame.Surface pygame用于表示圖片的模塊
https://www.pygame.org/docs/ref/surface.html
Surface.blit(source,?dest,?area=None,?special_flags=0)?->?Rect
#?將圖像繪制到另外一個(gè)圖像上,返回值是一個(gè)Rect對(duì)象,表示在screen上繪制的矩形區(qū)域
#?參數(shù):
#???source?矩形圖像的Surface實(shí)例對(duì)象
#???dest?是坐標(biāo)對(duì)象,繪制在屏幕的坐標(biāo)
#???area?表示從scorce的area區(qū)域取出繪制的到Surface對(duì)象上
#?結(jié)合上面例子
#?background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
#?screen.blit(background,?(0,?0))
#?就是將background圖片繪制到screen屏幕的0,?0坐標(biāo)處
Surface.get_rect(**kwargs)?->?Rect
#?獲取Surface的矩形區(qū)域,該矩形區(qū)域始終從坐標(biāo)0,?0開始,寬度和高度與圖片大小相同
#?返回一個(gè)rect對(duì)象,rect對(duì)象記錄著Surface的屬性信息,如:
#???rect.x?Surface對(duì)象x軸坐標(biāo)
#???rect.y?Surface對(duì)象y軸坐標(biāo)
#???rect.width?Surface對(duì)象的寬度
#???rect.height?Surface對(duì)象的高度
圖片移動(dòng)、通過(guò)用戶事件移動(dòng)圖片
上面代碼已經(jīng)能夠建立游戲窗口和加載背景圖,現(xiàn)在創(chuàng)建英雄,通過(guò)改變坐標(biāo)實(shí)現(xiàn)移動(dòng)
import?os
import?time
import?pygame
#?屏幕寬度
SCREEN_WIDTH?=?500
#?屏幕高度
SCREEN_HEIGHT?=?250
#?圖片絕對(duì)路徑
IMG_PATH?=?os.path.join(os.getcwd(),?"img")
class?HeroPlane(object):
???def?__init__(self):
???????super(HeroPlane,?self).__init__()
???????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"hero_show_1.png"))
???????self.rect?=?self.image.get_rect()
???????self.rect.x?=?0??#?飛機(jī)x軸位置
???????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
???????self.is_running?=?True
???????self.bullet_list?=?pygame.sprite.Group()
???????self.last_time?=?time.time()
???def?move_level(self,?level):
???????#?防止飛機(jī)移出屏幕外,?增加判斷
???????add_level?=?self.rect.x?+?level
???????if?0?<=?add_level?<=?SCREEN_WIDTH?-?self.rect.width:
???????????self.rect.x?=?add_level
???????elif?add_level?0:
???????????self.rect.x?=?0
???????elif?add_level?>?SCREEN_WIDTH?-?self.rect.width:
???????????self.rect.x?=?SCREEN_WIDTH?-?self.rect.width
???def?move_vertical(self,?vertical):
???????add_vertical?=?self.rect.y?+?vertical
???????if?0?<=?add_vertical?<=?SCREEN_HEIGHT?-?self.rect.height:
???????????self.rect.y?=?add_vertical
???????elif?add_vertical?0:
???????????self.rect.y?=?0
???????elif?add_vertical?>?SCREEN_HEIGHT?-?self.rect.height:
???????????self.rect.y?=?SCREEN_HEIGHT?-?self.rect.height
def?main():
???pygame.display.init()
???#?初始化顯示模塊
???#?pygame.display.init()
???#?創(chuàng)建窗口
???screen?=?pygame.display.set_mode((SCREEN_WIDTH,?SCREEN_HEIGHT))
???#?設(shè)置窗口標(biāo)題
???pygame.display.set_caption("python小demo?飛機(jī)大戰(zhàn)")
???#?設(shè)置窗口icon
???pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH,?"icon.jpg")))
???#?加載背景圖片
???background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
???#?初始化英雄類
???hero?=?HeroPlane()
???def?update_hero():
???????hero.move_level(2)
???????screen.blit(hero.image,?(hero.rect.x,?hero.rect.y))
???while?True:
???????#?將背景圖片繪制到窗口上
???????screen.blit(background,?(0,?0))
???????#?更新英雄在屏幕上的位置
???????update_hero()
???????#?更新屏幕上內(nèi)容
???????pygame.display.update()
???????time.sleep(0.02)
if?__name__?==?"__main__":
???main()
執(zhí)行效果如下:

上面加載英雄并且實(shí)現(xiàn)英雄移動(dòng),其實(shí)就是不斷改變圖片在屏幕中的繪制位置。主函數(shù)的time.sleep也可以替換成pygame.time.Clock.tick方法,但本例子中,效果偏差不遠(yuǎn),就沒有使用pygame.time(https://www.pygame.org/docs/ref/time.html)提供的時(shí)間模塊
上面代碼雖然能夠?qū)崿F(xiàn)英雄的移動(dòng),但是無(wú)法根據(jù)玩家操作控制英雄的移動(dòng),這時(shí)候我們就需要提供特定的鍵盤或者鼠標(biāo)事件控制英雄移動(dòng),下面示例按住鼠標(biāo)實(shí)現(xiàn)飛機(jī)移動(dòng)
import?os
import?sys
import?time
import?pygame
#?屏幕寬度
SCREEN_WIDTH?=?500
#?屏幕高度
SCREEN_HEIGHT?=?250
#?圖片絕對(duì)路徑
IMG_PATH?=?os.path.join(os.getcwd(),?"img")
#?鼠標(biāo)按鍵標(biāo)識(shí)
MOUSE_MOVE?=?False
class?HeroPlane(object):
???def?__init__(self):
???????super(HeroPlane,?self).__init__()
???????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"hero_show_1.png"))
???????self.rect?=?self.image.get_rect()
???????self.rect.x?=?0??#?飛機(jī)x軸位置
???????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
???????self.is_running?=?True
???????self.bullet_list?=?pygame.sprite.Group()
???????self.last_time?=?time.time()
???def?move_level(self,?level):
???????#?防止飛機(jī)移出屏幕外,?增加判斷
???????if?0?<=?level?<=?SCREEN_WIDTH?-?self.rect.width:
???????????self.rect.x?=?level
???????elif?level?0:
???????????self.rect.x?=?0
???????elif?level?>?SCREEN_WIDTH?-?self.rect.width:
???????????self.rect.x?=?SCREEN_WIDTH?-?self.rect.width
???def?move_vertical(self,?vertical):
???????if?0?<=?vertical?<=?SCREEN_HEIGHT?-?self.rect.height:
???????????self.rect.y?=?vertical
???????elif?vertical?0:
???????????self.rect.y?=?0
???????elif?vertical?>?SCREEN_HEIGHT?-?self.rect.height:
???????????self.rect.y?=?SCREEN_HEIGHT?-?self.rect.height
def?main():
???pygame.init()
???#?初始化顯示模塊
???pygame.display.init()
???#?創(chuàng)建窗口
???screen?=?pygame.display.set_mode((SCREEN_WIDTH,?SCREEN_HEIGHT))
???#?設(shè)置窗口標(biāo)題
???pygame.display.set_caption("python小demo?飛機(jī)大戰(zhàn)")
???#?設(shè)置窗口icon
???pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH,?"icon.jpg")))
???#?加載背景圖片
???background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
???#?初始化英雄類
???hero?=?HeroPlane()
???def?event_check():
???????"""
???????事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
???????return:
???????"""
???????global?MOUSE_MOVE
???????for?event?in?pygame.event.get():
???????????if?event.type?==?pygame.QUIT:
???????????????#?接收到退出事件后退出程序
???????????????pygame.quit()
???????????????sys.exit()
???????????elif?event.type?==?pygame.MOUSEBUTTONDOWN:
???????????????MOUSE_MOVE?=?True
???????????elif?event.type?==?pygame.MOUSEBUTTONUP:
???????????????MOUSE_MOVE?=?False
???????if?MOUSE_MOVE:
???????????x,?y?=?pygame.mouse.get_pos()
???????????hero.move_level(x)
???????????hero.move_vertical(y)
???def?update_hero():
???????screen.blit(hero.image,?(hero.rect.x,?hero.rect.y))
???while?True:
???????#?事件檢測(cè)
???????event_check()
???????#?將背景圖片繪制到窗口上
???????screen.blit(background,?(0,?0))
???????#?更新英雄在屏幕上的位置
???????update_hero()
???????#?更新屏幕上內(nèi)容
???????pygame.display.update()
???????time.sleep(0.02)
if?__name__?==?"__main__":
???main()
執(zhí)行效果如下:

所需函數(shù)簡(jiǎn)要說(shuō)明
pygame.event用于監(jiān)聽玩家事件,如按下鍵盤、點(diǎn)擊鼠標(biāo)等
https://www.pygame.org/docs/ref/event.html
event.get(eventtype=None)?->?Eventlist
event.get(eventtype=None,?pump=True)?->?Eventlist
#?獲取事件隊(duì)列
#?參數(shù):
#???eventtype?可以傳入你想要監(jiān)聽到的事件列表,如果不傳,會(huì)把所有用戶觸發(fā)的事件返回
#???如上面示例中只監(jiān)聽了三個(gè)事件,也可以:
#???????pygame.event.get([pygame.QUIT,?pygame.MOUSEBUTTONDOWN,?pygame.MOUSEBUTTONUP])
#???但如果設(shè)置了指定類型事件,其他事件將不會(huì)被獲取,存在了事件隊(duì)列中中,有可能導(dǎo)致事件隊(duì)列被堆滿
#???pump?默認(rèn)為False,如果設(shè)置為True,event.pump()將會(huì)被調(diào)用
#?返回事件列表
#?常見事件類型:
#???事件??????????????????產(chǎn)生途徑????????????參數(shù)
#???QUIT?????????????????用戶按下關(guān)閉按鈕???????none
#???KEYDOWN??????????????鍵盤被按下????????????unicode,?key,?mod
#???KEYUP????????????????鍵盤被放開????????????key,?mod
#???MOUSEMOTION??????????鼠標(biāo)移動(dòng)?????????????pos,?rel,?buttons
#???MOUSEBUTTONDOWN??????鼠標(biāo)按下?????????????pos,?button
#???MOUSEBUTTONUP????????鼠標(biāo)放開?????????????pos,?button
#???USEREVENT????????????用戶自定義事件????????code
#?上面列舉了常見的事件,更多事件和方法可以點(diǎn)擊上面文檔鏈接查閱文檔
pygame.key用于處理鍵盤的模塊,當(dāng)鍵盤按下或者釋放時(shí),pygame.event.get()就能獲取pygame.KEYDOWN或pygame.KEYUP事件,這兩個(gè)事件都有key和mod屬性:key代表鍵盤上每個(gè)整數(shù)ID;mod代表事件發(fā)生時(shí)修飾建位掩碼。
https://www.pygame.org/docs/ref/key.html
上述例子中,如果想通過(guò)長(zhǎng)按鍵盤?、?、?、?控制英雄,可將事件處理函數(shù)修改為:
def?event_check():
???"""
???事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
???return:
???"""
???#?設(shè)置KEYDOWN標(biāo)志位,0代表鍵盤已釋放,1、2、3、4分別代表?、?、?、?
???global?KEYDOWN
???for?event?in?pygame.event.get():
???????if?event.type?==?pygame.QUIT:
???????????#?接收到退出事件后退出程序
???????????pygame.quit()
???????????sys.exit()
???????elif?event.type?==?pygame.KEYDOWN:
???????????if?event.key?==?pygame.K_LEFT:
???????????????KEYDOWN?=?1
???????????elif?event.key?==?pygame.K_UP:
???????????????KEYDOWN?=?2
???????????elif?event.key?==?pygame.K_DOWN:
???????????????KEYDOWN?=?3
???????????elif?event.key?==?pygame.K_RIGHT:
???????????????KEYDOWN?=?4
???????elif?event.type?==?pygame.KEYUP:
???????????KEYDOWN?=?0
???if?KEYDOWN:
???????if?KEYDOWN?==?1:
???????????hero.move_level(hero.rect.x?-?5)
???????elif?KEYDOWN?==?2:
???????????hero.move_vertical(hero.rect.y?-?5)
???????elif?KEYDOWN?==?3:
???????????hero.move_vertical(hero.rect.y?+?5)
???????else:
???????????hero.move_level(hero.rect.x?+?5)
下面列舉常見的鍵盤常量(更多鍵盤常量可點(diǎn)擊上方連接查閱文檔):
| KeyASCII | 描述 |
|---|---|
| K_BACKSPACE | 退格鍵(Backspace) |
| K_TAB | 制表鍵(Tab) |
| K_CLEAR | 清除鍵(Clear) |
| K_RETURN | 回車鍵(Enter) |
| K_ESCAPE | 退出鍵(Escape) |
| K_DELETE | 刪除鍵(delete) |
| K_0 - K_9 | 0 - 9 |
| K_a - K_z | a - z |
| K_KP0 - K_KP9 | 0 - 9(小鍵盤) |
| K_UP | 向上箭頭(up arrow) |
| K_DOWN | 向下箭頭(down arrow) |
| K_RIGHT | 向右箭頭(right arrow) |
| K_LEFT | 向左箭頭(left arrow) |
碰撞檢測(cè)及所需函數(shù)簡(jiǎn)要說(shuō)明
上面代碼中,已經(jīng)實(shí)現(xiàn)創(chuàng)建英雄,并且能通過(guò)事件去控制英雄的移動(dòng),下面我們可以按照創(chuàng)建英雄的方法,創(chuàng)建一個(gè)敵機(jī),并通過(guò)讓英雄與敵機(jī)碰撞發(fā)生爆炸
import?os
import?sys
import?time
import?pygame
#?屏幕寬度
SCREEN_WIDTH?=?500
#?屏幕高度
SCREEN_HEIGHT?=?250
#?圖片絕對(duì)路徑
IMG_PATH?=?os.path.join(os.getcwd(),?"img")
#?鼠標(biāo)按鍵標(biāo)識(shí)
MOUSE_MOVE?=?False
#?鍵盤長(zhǎng)按標(biāo)識(shí)位
KEYDOWN?=?0
class?HeroPlane(object):
????def?__init__(self):
????????super(HeroPlane,?self).__init__()
????????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"hero_show_1.png"))
????????self.rect?=?self.image.get_rect()
????????self.rect.x?=?0??#?飛機(jī)x軸位置
????????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
????????self.is_running?=?True
????def?move_level(self,?level):
????????#?防止飛機(jī)移出屏幕外,?增加判斷
????????if?0?<=?level?<=?SCREEN_WIDTH?-?self.rect.width:
????????????self.rect.x?=?level
????????elif?level?0:
????????????self.rect.x?=?0
????????elif?level?>?SCREEN_WIDTH?-?self.rect.width:
????????????self.rect.x?=?SCREEN_WIDTH?-?self.rect.width
????def?move_vertical(self,?vertical):
????????if?0?<=?vertical?<=?SCREEN_HEIGHT?-?self.rect.height:
????????????self.rect.y?=?vertical
????????elif?vertical?0:
????????????self.rect.y?=?0
????????elif?vertical?>?SCREEN_HEIGHT?-?self.rect.height:
????????????self.rect.y?=?SCREEN_HEIGHT?-?self.rect.height
class?EnemyPlane(pygame.sprite.Sprite):
????def?__init__(self):
????????super(EnemyPlane,?self).__init__()
????????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"mp_show_3.png"))
????????self.rect?=?self.image.get_rect()
????????self.rect?=?self.image.get_rect()
????????self.rect.x?=?int(SCREEN_WIDTH?-?self.rect.width)??#?飛機(jī)x軸位置
????????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
????????self.is_running?=?True
def?main():
????pygame.init()
????#?初始化顯示模塊
????pygame.display.init()
????#?創(chuàng)建窗口
????screen?=?pygame.display.set_mode((SCREEN_WIDTH,?SCREEN_HEIGHT))
????#?設(shè)置窗口標(biāo)題
????pygame.display.set_caption("python小demo?飛機(jī)大戰(zhàn)")
????#?設(shè)置窗口icon
????pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH,?"icon.jpg")))
????#?加載背景圖片
????background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
????#?初始化英雄
????hero?=?HeroPlane()
????#?初始化敵機(jī)
????enemy?=?EnemyPlane()
????def?event_check():
????????"""
????????事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
????????return:
????????"""
????????global?MOUSE_MOVE
????????for?event?in?pygame.event.get():
????????????if?event.type?==?pygame.QUIT:
????????????????#?接收到退出事件后退出程序
????????????????pygame.quit()
????????????????sys.exit()
????????????elif?event.type?==?pygame.MOUSEBUTTONDOWN:
????????????????MOUSE_MOVE?=?True
????????????elif?event.type?==?pygame.MOUSEBUTTONUP:
????????????????MOUSE_MOVE?=?False
????????if?MOUSE_MOVE:
????????????x,?y?=?pygame.mouse.get_pos()
????????????hero.move_level(x)
????????????hero.move_vertical(y)
????#?def?event_check():
????#?????"""
????#?????事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
????#?????return:
????#?????"""
????#?????#?設(shè)置KEYDOWN標(biāo)志位,0代表鍵盤已釋放,1、2、3、4分別代表?、?、?、?
????#?????global?KEYDOWN
????#
????#?????for?event?in?pygame.event.get():
????#?????????if?event.type?==?pygame.QUIT:
????#?????????????#?接收到退出事件后退出程序
????#?????????????pygame.quit()
????#?????????????sys.exit()
????#?????????elif?event.type?==?pygame.KEYDOWN:
????#?????????????if?event.key?==?pygame.K_LEFT:
????#?????????????????KEYDOWN?=?1
????#?????????????elif?event.key?==?pygame.K_UP:
????#?????????????????KEYDOWN?=?2
????#?????????????elif?event.key?==?pygame.K_DOWN:
????#?????????????????KEYDOWN?=?3
????#?????????????elif?event.key?==?pygame.K_RIGHT:
????#?????????????????KEYDOWN?=?4
????#?????????elif?event.type?==?pygame.KEYUP:
????#?????????????KEYDOWN?=?0
????#
????#?????if?KEYDOWN:
????#?????????if?KEYDOWN?==?1:
????#?????????????hero.move_level(hero.rect.x?-?5)
????#?????????elif?KEYDOWN?==?2:
????#?????????????hero.move_vertical(hero.rect.y?-?5)
????#?????????elif?KEYDOWN?==?3:
????#?????????????hero.move_vertical(hero.rect.y?+?5)
????#?????????else:
????#?????????????hero.move_level(hero.rect.x?+?5)
????def?update_hero():
????????screen.blit(hero.image,?(hero.rect.x,?hero.rect.y))
????def?update_enemy():
????????screen.blit(enemy.image,?(enemy.rect.x,?enemy.rect.y))
????def?check_crash():
????????is_crash?=?pygame.sprite.collide_rect(hero,?enemy)
????????if?is_crash:
????????????#?先展示飛機(jī)爆炸,然后在屏幕中間寫下game?over提示
????????????screen.blit(pygame.image.load(os.path.join(IMG_PATH,?"ex_2.png")),?(hero.rect.x,?hero.rect.y))
????????????screen.blit(pygame.image.load(os.path.join(IMG_PATH,?"ex_2.png")),?(enemy.rect.x,?enemy.rect.y))
????????????game_over?=?pygame.font.Font(None,?100)
????????????game_over?=?game_over.render("game?over",?True,?(220,?20,?60))
????????????screen.blit(game_over,?[int(SCREEN_WIDTH?/?2?-?game_over.get_width()?/?2),?int(SCREEN_HEIGHT?/?2)])
????while?True:
????????#?事件檢測(cè)
????????event_check()
????????#?將背景圖片繪制到窗口上
????????screen.blit(background,?(0,?0))
????????#?更新英雄在屏幕上的位置
????????update_hero()
????????#?更新敵機(jī)在屏幕上位置
????????update_enemy()
????????#?碰撞檢測(cè)
????????check_crash()
????????#?更新屏幕上內(nèi)容
????????pygame.display.update()
????????time.sleep(0.02)
if?__name__?==?"__main__":
????main()
執(zhí)行效果如下:

所需函數(shù)簡(jiǎn)要說(shuō)明
pygame.sprite 基本游戲?qū)ο箢悾厦胬又校覀冇⑿鄹鷶硻C(jī)都繼承了pygame.sprite.Sprite,這是方便我們省略了造輪子的步驟,比如碰撞檢測(cè)。
https://www.pygame.org/docs/ref/sprite.html
sprite.collide_rect(left,?right)?->?bool
#?檢測(cè)兩個(gè)繼承了pygame.sprite.Sprite且具有矩形區(qū)域?qū)傩缘膶?duì)象是否發(fā)生了碰撞
#?該方法會(huì)根據(jù)對(duì)象的rect屬性判斷是否發(fā)生了碰撞
#?參數(shù):
#???left?第一個(gè)對(duì)象,如hero
#???right?第二個(gè)對(duì)象,如hero
#?返回bool值,?真為發(fā)生碰撞,假為沒有碰撞
#?該示例中,只有一架敵機(jī)和一架英雄,但如果需要英雄與多架敵機(jī)發(fā)生碰撞
#?或者英雄發(fā)出的子彈是否擊中了敵機(jī),這就產(chǎn)生了一對(duì)多、多對(duì)多的檢測(cè)
#?這種情況可以使用sprite.Group來(lái)完成該方法
sprite.Group()?->?Group
#?用于保存和管理多個(gè)?Sprite?對(duì)象的容器類
#?返回一個(gè)組對(duì)象
sprite.Group.add(*sprites)?->?None
#?增加一個(gè)sprites到該組中
sprite.spritecollide(sprite,?group,?dokill,?collided?=?None)?->?Sprite_list
#?查找一個(gè)sprite是否與sprite.Group()中的sprite發(fā)生碰撞
#?用于一對(duì)多的碰撞檢測(cè)
#?參數(shù):
#???sprite?單個(gè)sprite對(duì)象
#???group?一個(gè)包含多個(gè)sprite對(duì)象的組對(duì)象
#???dokill?bool值,如果為真,發(fā)生碰撞時(shí),將碰撞的sprite對(duì)象從組中移除
#???collided?是一個(gè)判斷碰撞的函數(shù),參數(shù)為兩個(gè)sprite對(duì)象,并且需要返回bool值,如果你的
#???sprite對(duì)象也有像例子中設(shè)置了rect屬性,可以不傳
#?返回所有和sprite發(fā)生碰撞的對(duì)象,如果沒有,返回空Sprite_list
sprite.groupcollide(group1,?group2,?dokill1,?dokill2,?collided?=?None)?->?Sprite_dict
#?查找兩組中所有碰撞的Sprite對(duì)象
#?用于實(shí)現(xiàn)多對(duì)多碰撞檢測(cè)
#?參數(shù):
#???group1?第一個(gè)sprite對(duì)象的組對(duì)象
#???group2?第二個(gè)sprite對(duì)象的組對(duì)象
#???dokill1?bool值,如果為真,發(fā)生碰撞時(shí),將碰撞的sprite對(duì)象從第一個(gè)組中移除
#???dokill2?bool值,如果為真,發(fā)生碰撞時(shí),將碰撞的sprite對(duì)象從第二個(gè)組中移除
#???collided?是一個(gè)判斷碰撞的函數(shù),參數(shù)為兩個(gè)sprite對(duì)象,并且需要返回bool值,如果你的
#???sprite對(duì)象也有像例子中設(shè)置了rect屬性,可以不傳
#?返回一個(gè)Sprite_dict對(duì)象,類似于:
#???{:?[]}
#???key?是group1?碰撞列表,?value是group2碰撞列表
#?上面列舉了本例需要的函數(shù),更多使用方法可以點(diǎn)擊上面文檔鏈接查閱文檔
pygame.font 用于加載和渲染字體
https://www.pygame.org/docs/ref/font.html
font.Font(filename,?size)?->?Font
font.Font(object,?size)?->?Font
#?從給定的文件名或者python的文件對(duì)象加載新字體
#?參數(shù):
#???filename?文件路徑字符串,如os.path.join('fonts',?'ziti.ttf')
#???object?python文件對(duì)象
#???如果第一個(gè)參數(shù)傳None,會(huì)使用默認(rèn)字體
#???size?整數(shù)類型,字體大小
#?返回一個(gè)Font對(duì)象
font.Font.render(text,?antialias,?color,?background=None)?->?Surface
#?創(chuàng)建一個(gè)新的?Surface,其上呈現(xiàn)了指定的文本,該方法只能寫一行文字,不呈現(xiàn)換行,空字符串會(huì)引發(fā)異常
#?參數(shù):
#???text?要展示的文本
#???antialias?bool值,如果為真,字符將有平滑的邊緣
#???color?字體顏色?RGB值
#???background?用于文本背景顏色,如果沒有傳遞,背景色是透明色
#?上面列舉了本例需要的函數(shù),更多使用方法可以點(diǎn)擊上面文檔鏈接查閱文檔
音頻加載及所需函數(shù)簡(jiǎn)要說(shuō)明
import?os
import?sys
import?time
import?pygame
#?屏幕寬度
SCREEN_WIDTH?=?500
#?屏幕高度
SCREEN_HEIGHT?=?250
#?圖片絕對(duì)路徑
IMG_PATH?=?os.path.join(os.getcwd(),?"img")
#?鼠標(biāo)按鍵標(biāo)識(shí)
MOUSE_MOVE?=?False
#?鍵盤長(zhǎng)按標(biāo)識(shí)位
KEYDOWN?=?0
#?背景音樂(lè)路徑
MUSIC_PATH?=?os.path.join(os.getcwd(),?"sound")
class?HeroPlane(pygame.sprite.Sprite):
????def?__init__(self):
????????super(HeroPlane,?self).__init__()
????????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"hero_show_1.png"))
????????self.rect?=?self.image.get_rect()
????????self.rect.x?=?0??#?飛機(jī)x軸位置
????????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
????????self.is_running?=?True
????def?move_level(self,?level):
????????#?防止飛機(jī)移出屏幕外,?增加判斷
????????if?0?<=?level?<=?SCREEN_WIDTH?-?self.rect.width:
????????????self.rect.x?=?level
????????elif?level?0:
????????????self.rect.x?=?0
????????elif?level?>?SCREEN_WIDTH?-?self.rect.width:
????????????self.rect.x?=?SCREEN_WIDTH?-?self.rect.width
????def?move_vertical(self,?vertical):
????????if?0?<=?vertical?<=?SCREEN_HEIGHT?-?self.rect.height:
????????????self.rect.y?=?vertical
????????elif?vertical?0:
????????????self.rect.y?=?0
????????elif?vertical?>?SCREEN_HEIGHT?-?self.rect.height:
????????????self.rect.y?=?SCREEN_HEIGHT?-?self.rect.height
class?EnemyPlane(pygame.sprite.Sprite):
????def?__init__(self):
????????super(EnemyPlane,?self).__init__()
????????self.image?=?pygame.image.load(os.path.join(IMG_PATH,?"mp_show_3.png"))
????????self.rect?=?self.image.get_rect()
????????self.rect?=?self.image.get_rect()
????????self.rect.x?=?int(SCREEN_WIDTH?-?self.rect.width)??#?飛機(jī)x軸位置
????????self.rect.y?=?int(SCREEN_HEIGHT?-?self.rect.height)?/?2??#?飛機(jī)y軸位置
????????self.is_running?=?True
def?main():
????pygame.init()
????#?初始化顯示模塊
????pygame.display.init()
????#?創(chuàng)建窗口
????screen?=?pygame.display.set_mode((SCREEN_WIDTH,?SCREEN_HEIGHT))
????#?設(shè)置窗口標(biāo)題
????pygame.display.set_caption("python小demo?飛機(jī)大戰(zhàn)")
????#?設(shè)置窗口icon
????pygame.display.set_icon(pygame.image.load(os.path.join(IMG_PATH,?"icon.jpg")))
????#?加載背景圖片
????background?=?pygame.image.load(os.path.join(IMG_PATH,?"test_bj.png"))
????#?初始化英雄
????hero?=?HeroPlane()
????#?初始化敵機(jī)
????enemy?=?EnemyPlane()
????#?加載背景音樂(lè)并播放
????pygame.mixer.init()
????pygame.mixer.music.load(os.path.join(MUSIC_PATH,?"game_music.ogg"))
????pygame.mixer.music.play(loops=-1)
????def?event_check():
????????"""
????????事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
????????return:
????????"""
????????global?MOUSE_MOVE
????????for?event?in?pygame.event.get():
????????????if?event.type?==?pygame.QUIT:
????????????????#?接收到退出事件后退出程序
????????????????pygame.quit()
????????????????sys.exit()
????????????elif?event.type?==?pygame.MOUSEBUTTONDOWN:
????????????????MOUSE_MOVE?=?True
????????????elif?event.type?==?pygame.MOUSEBUTTONUP:
????????????????MOUSE_MOVE?=?False
????????if?MOUSE_MOVE:
????????????x,?y?=?pygame.mouse.get_pos()
????????????hero.move_level(x)
????????????hero.move_vertical(y)
????#?def?event_check():
????#?????"""
????#?????事件檢測(cè),這邊做了一個(gè)簡(jiǎn)單的示例
????#?????return:
????#?????"""
????#?????#?設(shè)置KEYDOWN標(biāo)志位,0代表鍵盤已釋放,1、2、3、4分別代表?、?、?、?
????#?????global?KEYDOWN
????#
????#?????for?event?in?pygame.event.get():
????#?????????if?event.type?==?pygame.QUIT:
????#?????????????#?接收到退出事件后退出程序
????#?????????????pygame.quit()
????#?????????????sys.exit()
????#?????????elif?event.type?==?pygame.KEYDOWN:
????#?????????????if?event.key?==?pygame.K_LEFT:
????#?????????????????KEYDOWN?=?1
????#?????????????elif?event.key?==?pygame.K_UP:
????#?????????????????KEYDOWN?=?2
????#?????????????elif?event.key?==?pygame.K_DOWN:
????#?????????????????KEYDOWN?=?3
????#?????????????elif?event.key?==?pygame.K_RIGHT:
????#?????????????????KEYDOWN?=?4
????#?????????elif?event.type?==?pygame.KEYUP:
????#?????????????KEYDOWN?=?0
????#
????#?????if?KEYDOWN:
????#?????????if?KEYDOWN?==?1:
????#?????????????hero.move_level(hero.rect.x?-?5)
????#?????????elif?KEYDOWN?==?2:
????#?????????????hero.move_vertical(hero.rect.y?-?5)
????#?????????elif?KEYDOWN?==?3:
????#?????????????hero.move_vertical(hero.rect.y?+?5)
????#?????????else:
????#?????????????hero.move_level(hero.rect.x?+?5)
????def?update_hero():
????????screen.blit(hero.image,?(hero.rect.x,?hero.rect.y))
????def?update_enemy():
????????screen.blit(enemy.image,?(enemy.rect.x,?enemy.rect.y))
????def?check_crash():
????????is_crash?=?pygame.sprite.collide_rect(hero,?enemy)
????????if?is_crash:
????????????#?先展示飛機(jī)爆炸,然后在屏幕中間寫下game?over提示
????????????screen.blit(pygame.image.load(os.path.join(IMG_PATH,?"ex_2.png")),?(hero.rect.x,?hero.rect.y))
????????????screen.blit(pygame.image.load(os.path.join(IMG_PATH,?"ex_2.png")),?(enemy.rect.x,?enemy.rect.y))
????????????pygame.mixer.Sound(os.path.join(MUSIC_PATH,?"enemy1_down.wav")).play()
????????????game_over?=?pygame.font.Font(None,?100)
????????????game_over?=?game_over.render("game?over",?True,?(220,?20,?60))
????????????screen.blit(game_over,?[int(SCREEN_WIDTH?/?2?-?game_over.get_width()?/?2),?int(SCREEN_HEIGHT?/?2)])
????while?True:
????????#?事件檢測(cè)
????????event_check()
????????#?將背景圖片繪制到窗口上
????????screen.blit(background,?(0,?0))
????????#?更新英雄在屏幕上的位置
????????update_hero()
????????#?更新敵機(jī)在屏幕上位置
????????update_enemy()
????????#?碰撞檢測(cè)
????????check_crash()
????????#?更新屏幕上內(nèi)容
????????pygame.display.update()
????????time.sleep(0.02)
if?__name__?==?"__main__":
????main()
執(zhí)行效果:
所需函數(shù)簡(jiǎn)要說(shuō)明
pygame.mixer 用于加載和播放音頻
https://www.pygame.org/docs/ref/mixer.html
mixer.init(
????frequency=44100,
????size=-16,
????channels=2,
????buffer=512,
????devicename=None,
????allowedchanges=AUDIO_ALLOW_FREQUENCY_CHANGE?|?AUDIO_ALLOW_CHANNELS_CHANGE
)?->?None
#?初始化mixer模塊以進(jìn)行聲音加載和播放。可以重寫默認(rèn)參數(shù)以提供特定的音頻混合
#?參數(shù):
#???frequency??pygame?2.0.0+時(shí),范圍44100-22050
#?? size 表示每個(gè)音頻樣本使用了多少位。如果是負(fù)值,則使用帶符號(hào)的樣本值,無(wú)效值會(huì)觸發(fā)異常,2.0.0后可以是32
#???channels?指定使用單聲道還是立體音,1為單聲道,2為立體音,?2.0.0后可以是4或者6
#???buffer?控制聲音混合器mixer中使用的內(nèi)部樣本數(shù),默認(rèn)值應(yīng)適用于大多數(shù)情況
#?? allowedchanges 當(dāng)allowedchanges=0,將在運(yùn)行時(shí)轉(zhuǎn)換示例以匹配硬件支持的內(nèi)容,allowedchanges也支持:
#???????AUDIO_ALLOW_FREQUENCY_CHANGE
#???????AUDIO_ALLOW_FORMAT_CHANGE
#???????AUDIO_ALLOW_CHANNELS_CHANGE
#???????AUDIO_ALLOW_ANY_CHANGE
mixer.music.load(filename)?->?None
mixer.music.load(object)?->?None
#?將加載音樂(lè)文件/或者音樂(lè)文件對(duì)象并準(zhǔn)備播放,如果音樂(lè)已經(jīng)播放,調(diào)用則會(huì)停止
mixer.music.play(loops=0,?start=0.0,?fade_ms?=?0)?->?None
#?播放已經(jīng)加載的音樂(lè)流,如果已經(jīng)在播放時(shí)調(diào)用,則會(huì)重新播放
#?參數(shù):
#???loops?可選整數(shù)參數(shù),表示重復(fù)播放次數(shù),設(shè)置為-1表示無(wú)限重復(fù)
#???start?可選浮點(diǎn)數(shù),表示開始播放音樂(lè)時(shí)間的位置,起始位置決定于音樂(lè)格式
#???fade_ms?可選整數(shù)參數(shù),大于0時(shí),在給定的fade_ms內(nèi)逐漸加大音量
pygame.mixer.Sound(filename)?->?Sound
pygame.mixer.Sound(buffer)?->?Sound
#?從文件或者緩沖區(qū)創(chuàng)建一個(gè)新的文件對(duì)象
pygame.mixer.Sound.play(loops=0,?maxtime=0,?fade_ms=0)?->?Channel
#?開始在可用的頻道上播放聲音,播放時(shí)可能在必要時(shí)切斷正在播放的聲音
#?在本例中,調(diào)用該方法產(chǎn)生爆炸音效并不會(huì)影響背景音樂(lè)的播放
#?參數(shù):
#???loops?可選整數(shù)參數(shù),表示重復(fù)播放次數(shù),設(shè)置為-1表示無(wú)限重復(fù)
#???maxtime?大于零時(shí),在給定的maxtime停止播放(毫秒)
#???fade_ms?可選整數(shù)參數(shù),大于0時(shí),在給定的fade_ms內(nèi)逐漸加大音量
#?返回所選的通道對(duì)象
#?上面列舉了本例需要的函數(shù),更多使用方法可以點(diǎn)擊上面文檔鏈接查閱文檔
python小demo 飛機(jī)大戰(zhàn)完整例子
在上面,大致示范了使用pygame寫一個(gè)飛機(jī)大戰(zhàn)所需模塊及函數(shù),本人也寫了一個(gè)示例,包括本推文中所使用的代碼都提交至github,在本公眾號(hào)中回復(fù)“飛機(jī)大戰(zhàn)”即可獲取源碼地址,及圖片素材、音頻素材,下面看下我例子效果:
?小伙伴們,快快用實(shí)踐一下吧!如果在學(xué)習(xí)過(guò)程中,有遇到任何問(wèn)題,歡迎加我好友,我拉你進(jìn)Python學(xué)習(xí)交流群共同探討學(xué)習(xí)。
-------------------?End?-------------------
往期精彩文章推薦:

歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持
想加入Python學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群】
萬(wàn)水千山總是情,點(diǎn)個(gè)【在看】行不行
/今日留言主題/
隨便說(shuō)一兩句吧~~
