和事件关联的动词,是“发生”,因此当咱们在关注事件的时候,咱们其实就是在关注当前正在发生什么……
举一个很是扯淡的例子,在咱们口语表达中,有这样一种嫌弃:“你事情怎么这么多的?”。这是一种南方的口语表达,可能还不是很是明显,换成北方的表达方式,就很直接了:“你怎么这么事儿?”
这个“事儿”咱们就能够理解为,操做。咱们的程序是会一直一直运行下去的,直到我关闭窗口的操做产生了一个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