电竞比分网-中国电竞赛事及体育赛事平台

分享

Pygame寫(xiě)游戲-2:理解事件

 zcxuexi 2014-07-30

上次我們?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ì)講的),下面是源代碼:

Python
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)似的,我們還有MOUSEBUTTONDOWNMOUSEBUTTONUP兩個(gè)事件,看名字就明白是什么意思了。很多時(shí)候,你只需要知道鼠標(biāo)點(diǎn)下就可以了,那就可以不用上面那個(gè)比較強(qiáng)大(也比較復(fù)雜)的事件了。它們的參數(shù)為:

  • button – 看清楚少了個(gè)s,這個(gè)值代表了哪個(gè)按鍵被操作
  • pos – 和上面一樣

處理鍵盤(pán)事件

鍵盤(pán)和游戲手柄的事件比較類(lèi)似,為KEYDOWNKEYUP,下面有一個(gè)例子來(lái)演示使用方向鍵移動(dòng)一些東西。

Python
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_SPACEK_RETURN等。
  • mod – 包含了組合鍵信息,如果mod & KMOD_CTRL是真的話(huà),表示用戶(hù)同時(shí)按下了Ctrl鍵。類(lèi)似的還有KMOD_SHIFTKMOD_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),然后再傳遞它:

Python
1
2
3
4
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ō),僅用代碼演示一下:

Python
1
2
3
4
5
6
7
8
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)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多