和事件關聯的動詞,是「發生」,因此當咱們在關注事件的時候,咱們其實就是在關注當前正在發生什麼……
舉一個很是扯淡的例子,在咱們口語表達中,有這樣一種嫌棄:「你事情怎麼這麼多的?」。這是一種南方的口語表達,可能還不是很是明顯,換成北方的表達方式,就很直接了:「你怎麼這麼事兒?」
這個「事兒」咱們就能夠理解爲,操做。咱們的程序是會一直一直運行下去的,直到我關閉窗口的操做產生了一個QUIT事件。事件隨時可能發生,並且量也可能會很大,pygame的作法是把一系列的事情存放在一個隊列裏,逐個處理。python
一般,在我目前寫到的程序中,我都使用pygame.event.get()
來處理全部的事件。若是咱們使用pygame.event.wait()
,pygame就會等到發生下一個事件才繼續下去。
在一些動態遊戲中,遊戲每每是要動態運做的,而另一個方法pygame.event.poll()
就好一些,一旦調用,他會根據如今的情形返回一個真實的事件,或者一個「什麼都沒有」。app
下表爲一個經常使用事件集:post
事件 | 產生途徑 | 參數 |
---|---|---|
QUIT | 用戶按下關閉按鈕 | none |
ATIVEEVENT | pygame被激活或者隱藏 | gain,state |
KEYDOWN | 鍵盤被按下 | unicode,key,mod |
KEYUP | 鍵盤被放開 | key,mod |
MOUSEMOTION | 鼠標移動 | pos,rel,buttons |
MOUSEBUTTONDOWN | 鼠標按下 | pos,button |
MOUSEBUTTONUP | 鼠標放開 | pos,button |
JOYAXISMOTION | 遊戲手柄(joystick or pad)移動 | joy,axis,value |
JOYBALLMOTION | 遊戲手柄(joystick ball)移動 | joy,axis,value |
JOYHATMOTION | 遊戲手柄(joystick)移動 | joy,axis,value |
JOYBUTTONDOWN | 遊戲手柄按下 | joy,button |
JOYBUTTONUP | 遊戲手柄放開 | joy,button |
VIDEORESIZE | pygame窗口縮放 | size,w,h |
VIDEOEXPOSE | pygame窗口部分公開(expose) | none |
USEREVENT | 觸發用戶事件 | code |
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", 17) font_height = font.get_linesize() event_text = [] while 1: event = pygame.event.wait() event_text.append(str(event)) event_text = event_text[(-screen_size[1]//font_height):] # 這個切片操做保證了event_text裏面只保留一個屏幕的文字 if event.type == QUIT: exit() screen.fill((0, 0, 0)) # screen.blit() y = screen_size[1]-font_height # 找一個合適的起筆位置,最下面開始可是要留一行空 for text in reversed(event_text): screen.blit(font.render(text,True,(0,255,0)),(0,y)) y -= font_height pygame.display.update()
這個程序很是適合分步去了解各個操做在pygame內的響應效果,可是有一個小小的弊端就是,他和通常的pygame.event.get()
不一樣,它只有在新的事件發生的時候纔會有反饋到屏幕上,這就讓咱們形成某種錯覺,就是pygame只能知道咱們某瞬間的狀態,若是這個狀態不改變,pygame就沒法察覺。
顯然這是不對的,例如咱們按下某個鍵的時候,咱們能夠用for語句搭配pygame.event.get去進行一個輪詢,這個輪詢會不斷的檢測事件,pygame始終能覺察到咱們的操做和狀態。
下面的程序就是一個典型的例子。在長按方向鍵的時候,pygame並不會移動一次就結束,而是會一直移動,直到咱們鬆開按鍵返回原始狀態。測試
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: #鍵盤有按下? if event.key == K_LEFT: #按下的是左方向鍵的話,把x座標減一 move_x = -1 elif event.key == K_RIGHT: #右方向鍵則加一 move_x = 1 elif event.key == K_UP: #相似了 move_y = -1 elif event.key == K_DOWN: move_y = 1 elif event.type == KEYUP: #若是用戶放開了鍵盤,圖就不要動了 move_x = 0 move_y = 0 #計算出新的座標 x+= move_x y+= move_y screen.fill((0,0,0)) screen.blit(background, (x,y)) #在新的位置上畫圖 pygame.display.update()
經過上面的動做檢測腳本咱們能夠發現,出現頻率最高的,就是鼠標事件和鍵盤事件。因此在這裏咱們特別地來討論一下這兩個事件的典型用法。code
MOUSEMOTION事件會在鼠標動做的時候發生,他有三個參數:隊列
MOUSEBUTTONDOWN和MOUSEBUTTONUP遊戲
KEYDOWN和KEYUP的參數描述:事件
K_xxx
來表示,好比字母a就是K_a,還有K_SPACE和K_RETURN等。案例在上面已經放了,就是經過方向鍵移動圖片的小腳本。可是這個腳本有一個小小的bug:「在快速切換方向時,有時候會出現沒法持續移動的狀況」,這種bug的緣由其實跟pygame.event.get()機制有關。event.get只能監聽接收一個事件,在咱們快速操做的時候,好比咱們按下左鍵,忽然按下上鍵而且鬆開左鍵,這種時候bug就會出現。
咱們把上述動做分解一下:圖片
顯而易見,最後的終結操做並非KEYDOWN,而是KEYUP,在咱們的代碼中KEYUP會把移動位給歸零。這時候即使K_UP仍是在一個KEYDOWN的狀態,可是他再也不被event.get到了,因此天然,這個圖像就停下來了。ip
改良版:
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 move={K_LEFT:0,K_RIGHT:0,K_UP:0,K_DOWN:0} while True: for event in pygame.event.get(): if event.type == QUIT: exit() if event.type == KEYDOWN: #鍵盤有按下? if event.key in move.keys(): #按下的是左方向鍵的話,把x座標減一 move[event.key]=1 elif event.type == KEYUP: if event.key in move.keys(): move[event.key]=0 #計算出新的座標 x-= move[K_LEFT] x+= move[K_RIGHT] y-= move[K_UP] y+= move[K_DOWN] screen.fill((0,0,0)) screen.blit(background, (x,y)) #在新的位置上畫圖 pygame.display.update()
並非全部的事件都是須要處理的,好比在遊戲場景切換的時候,你按什麼都沒有用。咱們應該有一個方法來過濾掉一些咱們不感興趣的事件(固然咱們能夠不處理,不給他們設置響應的事件,可是最好的方法仍是讓他們根本不進入咱們的事件隊列)。
咱們使用pygame.event.set_blocked(事件名)
來完成。若是有好多事件須要過濾,能夠傳遞一個列表pygame.event.set_blocked([list])
,若是是設置參數爲None,那麼全部的事件就被打開了。
與之相對的,咱們使用pygame.event.set_allowed()
來設定容許的事件
一般玩家作什麼,pygame產生對應的事件就能夠了,不過有的時候咱們須要模擬出一些事件來,好比錄像回放的時候,咱們就要把用戶的操做再現一遍。或者說咱們在作外掛的時候,咱們就要把一些用戶的操做自動完成。
my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=u' ') #你也能夠像下面這樣寫,看起來比較清晰(但字變多了……) my_event = pygame.event.Event(KEYDOWN, {"key":K_SPACE, "mod":0, "unicode":u' '}) pygame.event.post(my_event)
有時候咱們甚至能夠產生一個徹底自定義的全新事件。範例代碼以下,可是我本身並無敲成功,由於我不知道它的這個USEREVENT
在哪裏何時如何定義的
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