|
上次我們?cè)囍鴮?xiě)了一個(gè)最簡(jiǎn)單的Pygame程序并且解釋了一個(gè)大概的框架,這次就Pygame中也是游戲中最關(guān)鍵(……好吧,也許并不是最關(guān)鍵,但絕對(duì)是至關(guān)重要的一項(xiàng))的事件來(lái)展開(kāi)。
 此圖為一個(gè)用Pygame開(kāi)發(fā)的游戲,或許有些簡(jiǎn)陋,但是只要你有愛(ài),什么都能出來(lái)!
理解事件
事件是什么,其實(shí)從名稱(chēng)來(lái)看我們就能想到些什么,而且你所想到的基本就是事件的真正意思了。我們上一個(gè)程序,會(huì)一直運(yùn)行下去,直到你關(guān)閉窗口而產(chǎn)生了一個(gè)QUIT事件,Pygame會(huì)接受用戶(hù)的各種操作(比如按鍵盤(pán),移動(dòng)鼠標(biāo)等)產(chǎn)生事件。事件隨時(shí)可能發(fā)生,而且量也可能會(huì)很大,Pygame的做法是把一系列的事件存放一個(gè)隊(duì)列里,逐個(gè)的處理。
事件檢索
上個(gè)程序中,使用了pygame.event.get()來(lái)處理所有的事件,這好像打開(kāi)大門(mén)讓所有的人進(jìn)入。如果我們使用pygame.event.wait(),Pygame就會(huì)等到發(fā)生一個(gè)事件才繼續(xù)下去,就好像你在門(mén)的貓眼上盯著外面一樣,來(lái)一個(gè)放一個(gè)……一般游戲中不太實(shí)用,因?yàn)橛螒蛲切枰獎(jiǎng)討B(tài)運(yùn)作的;而另外一個(gè)方法pygame.event.poll()就好一些,一旦調(diào)用,它會(huì)根據(jù)現(xiàn)在的情形返回一個(gè)真實(shí)的事件,或者一個(gè)“什么都沒(méi)有”。下表是一個(gè)常用事件集:
| 事件 |
產(chǎn)生途徑 |
參數(shù) |
| QUIT |
用戶(hù)按下關(guān)閉按鈕 |
none |
| ATIVEEVENT |
Pygame被激活或者隱藏 |
gain, state |
| KEYDOWN |
鍵盤(pán)被按下 |
unicode, key, mod |
| KEYUP |
鍵盤(pán)被放開(kāi) |
key, mod |
| MOUSEMOTION |
鼠標(biāo)移動(dòng) |
pos, rel, buttons |
| MOUSEBUTTONDOWN |
鼠標(biāo)按下 |
pos, button |
| MOUSEBUTTONUP |
鼠標(biāo)放開(kāi) |
pos, button |
| JOYAXISMOTION |
游戲手柄(Joystick or pad)移動(dòng) |
joy, axis, value |
| JOYBALLMOTION |
游戲球(Joy ball)?移動(dòng) |
joy, axis, value |
| JOYHATMOTION |
游戲手柄(Joystick)?移動(dòng) |
joy, axis, value |
| JOYBUTTONDOWN |
游戲手柄按下 |
joy, button |
| JOYBUTTONUP |
游戲手柄放開(kāi) |
joy, button |
| VIDEORESIZE |
Pygame窗口縮放 |
size, w, h |
| VIDEOEXPOSE |
Pygame窗口部分公開(kāi)(expose)? |
none |
| USEREVENT |
觸發(fā)了一個(gè)用戶(hù)事件 |
code |
如果你想把這個(gè)表現(xiàn)在就背下來(lái),當(dāng)然我不會(huì)阻止你,但實(shí)在不是個(gè)好主意,在實(shí)際的使用中,自然而然的就會(huì)記住。我們先來(lái)寫(xiě)一個(gè)可以把所有方法輸出的程序,它的結(jié)果是這樣的。

我們這里使用了wait(),因?yàn)檫@個(gè)程序在有事件發(fā)生的時(shí)候動(dòng)彈就可以了。還用了font模塊來(lái)顯示文字(后面會(huì)講的),下面是源代碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
import pygame from pygame.locals import * from sys import exit pygame.init() SCREEN_SIZE = (640, 480) screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32) font = pygame.font.SysFont("arial", 16); font_height = font.get_linesize() event_text = [] while True: event = pygame.event.wait() event_text.append(str(event)) #獲得時(shí)間的名稱(chēng) event_text = event_text[-SCREEN_SIZE[1]/font_height:] #這個(gè)切片操作保證了event_text里面只保留一個(gè)屏幕的文字 if event.type == QUIT: exit() screen.fill((255, 255, 255)) y = SCREEN_SIZE[1]-font_height #找一個(gè)合適的起筆位置,最下面開(kāi)始但是要留一行的空 for text in reversed(event_text): screen.blit( font.render(text, True, (0, 0, 0)), (0, y) ) #以后會(huì)講 y-=font_height #把筆提一行 pygame.display.update() |
小貼士:
書(shū)上說(shuō),如果你把填充色的(0, 0, 0)改為(0, 255, 0),效果會(huì)想黑客帝國(guó)的字幕雨一樣,我得說(shuō),實(shí)際試一下并不太像……不過(guò)以后你完全可以寫(xiě)一個(gè)以假亂真甚至更酷的!
這個(gè)程序在你移動(dòng)鼠標(biāo)的時(shí)候產(chǎn)生了海量的信息,讓我們知道了Pygame是多么的繁忙……我們第一個(gè)程序那樣是調(diào)用pygame.mouse.get_pos()來(lái)得到當(dāng)前鼠標(biāo)的位置,而現(xiàn)在利用事件可以直接獲得!
處理鼠標(biāo)事件
MOUSEMOTION事件會(huì)在鼠標(biāo)動(dòng)作的時(shí)候發(fā)生,它有三個(gè)參數(shù):
- buttons – 一個(gè)含有三個(gè)數(shù)字的元組,三個(gè)值分別代表左鍵、中鍵和右鍵,1就是按下了。
- pos – 就是位置了……
- rel – 代表了現(xiàn)在距離上次產(chǎn)生鼠標(biāo)事件時(shí)的距離
和MOUSEMOTION類(lèi)似的,我們還有MOUSEBUTTONDOWN和MOUSEBUTTONUP兩個(gè)事件,看名字就明白是什么意思了。很多時(shí)候,你只需要知道鼠標(biāo)點(diǎn)下就可以了,那就可以不用上面那個(gè)比較強(qiáng)大(也比較復(fù)雜)的事件了。它們的參數(shù)為:
- button – 看清楚少了個(gè)s,這個(gè)值代表了哪個(gè)按鍵被操作
- pos – 和上面一樣
處理鍵盤(pán)事件
鍵盤(pán)和游戲手柄的事件比較類(lèi)似,為KEYDOWN和KEYUP,下面有一個(gè)例子來(lái)演示使用方向鍵移動(dòng)一些東西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
background_image_filename = 'sushiplate.jpg' import pygame from pygame.locals import * from sys import exit pygame.init() screen = pygame.display.set_mode((640, 480), 0, 32) background = pygame.image.load(background_image_filename).convert() x, y = 0, 0 move_x, move_y = 0, 0 while True: for event in pygame.event.get(): if event.type == QUIT: exit() if event.type == KEYDOWN: #鍵盤(pán)有按下? if event.key == K_LEFT: #按下的是左方向鍵的話(huà),把x坐標(biāo)減一 move_x = -1 elif event.key == K_RIGHT: #右方向鍵則加一 move_x = 1 elif event.key == K_UP: #類(lèi)似了 move_y = -1 elif event.key == K_DOWN: move_y = 1 elif event.type == KEYUP: #如果用戶(hù)放開(kāi)了鍵盤(pán),圖就不要?jiǎng)恿?/div> move_x = 0 move_y = 0 #計(jì)算出新的坐標(biāo) x+= move_x y+= move_y screen.fill((0,0,0)) screen.blit(background, (x,y)) #在新的位置上畫(huà)圖 pygame.display.update() |
當(dāng)我們運(yùn)行這個(gè)程序的時(shí)候,按下方向鍵就可以把背景圖移動(dòng),但是等等!為什么我只能按一下動(dòng)一下啊……太不好試了吧?!用腳掌考慮下就應(yīng)該按著就一直動(dòng)下去才是?。??Pygame這么垃圾么……
哦,真是抱歉上面的代碼有點(diǎn)小bug,但是真的很小,你都不需要更改代碼本身,只要改一下縮進(jìn)就可以了,你可以發(fā)現(xiàn)么?Python本身是縮進(jìn)編排來(lái)表現(xiàn)層次,有些時(shí)候可能會(huì)出現(xiàn)一點(diǎn)小麻煩,要我們自己注意才可以。
KEYDOWN和KEYUP的參數(shù)描述如下:
- key – 按下或者放開(kāi)的鍵值,是一個(gè)數(shù)字,估計(jì)地球上很少有人可以記住,所以Pygame中你可以使用K_xxx來(lái)表示,比如字母a就是K_a,還有K_SPACE和K_RETURN等。
- mod – 包含了組合鍵信息,如果mod & KMOD_CTRL是真的話(huà),表示用戶(hù)同時(shí)按下了Ctrl鍵。類(lèi)似的還有KMOD_SHIFT,KMOD_ALT。
- unicode – 代表了按下鍵的Unicode值,這個(gè)有點(diǎn)不好理解,真正說(shuō)清楚又太麻煩,游戲中也不太常用,說(shuō)明暫時(shí)省略,什么時(shí)候需要再講吧。
事件過(guò)濾
并不是所有的事件都需要處理的,就好像不是所有登門(mén)造訪的人都是我們歡迎的一樣。比如,俄羅斯方塊就無(wú)視你的鼠標(biāo),而在游戲場(chǎng)景切換的時(shí)候,你按什么都是徒勞的。我們應(yīng)該有一個(gè)方法來(lái)過(guò)濾掉一些我們不感興趣的事件(當(dāng)然我們可以不處理這些沒(méi)興趣的事件,但最好的方法還是讓它們根本不進(jìn)入我們的事件隊(duì)列,就好像在門(mén)上貼著“XXX免進(jìn)”一樣),我們使用pygame.event.set_blocked(事件名)來(lái)完成。如果有好多事件需要過(guò)濾,可以傳遞一個(gè)列表,比如pygame.event.set_blocked([KEYDOWN, KEYUP]),如果你設(shè)置參數(shù)None,那么所有的事件有被打開(kāi)了。與之相對(duì)的,我們使用pygame.event.set_allowed()來(lái)設(shè)定允許的事件。
產(chǎn)生事件
通常玩家做什么,Pygame就產(chǎn)生對(duì)應(yīng)的事件就可以了,不過(guò)有的時(shí)候我們需要模擬出一些事件來(lái),比如錄像回放的時(shí)候,我們就要把用戶(hù)的操作再現(xiàn)一遍。
為了產(chǎn)生事件,必須先造一個(gè)出來(lái),然后再傳遞它:
|
|
my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=u' ') #你也可以像下面這樣寫(xiě),看起來(lái)比較清晰(但字變多了……) my_event = pygame.event.Event(KEYDOWN, {"key":K_SPACE, "mod":0, "unicode":u' '}) pygame.event.post(my_event) |
你甚至可以產(chǎn)生一個(gè)完全自定義的全新事件,有些高級(jí)的話(huà)題,暫時(shí)不詳細(xì)說(shuō),僅用代碼演示一下:
|
|
CATONKEYBOARD = USEREVENT+1 my_event = pygame.event.Event(CATONKEYBOARD, message="Bad cat!") pgame.event.post(my_event) #然后獲得它 for event in pygame.event.get(): if event.type == CATONKEYBOARD: print event.message |
這次的內(nèi)容很多,又很重要,一遍看下來(lái)云里霧里或者看的時(shí)候明白看完了全忘了什么的估計(jì)很多,慢慢學(xué)習(xí)吧~~多看看動(dòng)手寫(xiě)寫(xiě),其實(shí)都很簡(jiǎn)單。
下次講解顯示的部分。
>> 用Python和Pygame寫(xiě)游戲-從入門(mén)到精通(3)
|