理解事件
我们上一个程序,会一直运行下去,直到你关闭窗口而产生了一个QUIT事件,Pygame会接受用户的各种操作(比如按键盘,移动鼠标等)产生事件。事件随时可能发生,而且量也可能会很大,Pygame的做法是把一系列的事件存放一个队列里,逐个的处理。一句话就是使用者做的操作都叫产生事件,通过键盘或者鼠标。
事件检索
使用pygame.event.get()来处理所有的事件。如果我们使用pygame.event.wait(),Pygame就会等到发生一个事件才继续下去。一般游戏中不太实用,因为游戏往往是需要动态运作的;而另外一个方法pygame.event.poll()就好一些,一旦调用,它会根据现在的情形返回一个真实的事件,或者一个“什么都没有”。下表是一个常用事件集:
我们先来写一个可以把所有方法输出的程序
#-*- coding:utf-8 -*- #导入相关块 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_heigh = font.get_linesize() #定义事件列表 event_text = [] #页面循环 while True: #只有在发生事件时动,wait的作用 event = pygame.event.wait() #每产生一个事件就添加进列表 event_text.append(str(event)) # 这个切片操作保证了event_text里面只保留一个屏幕的文字 event_text = event_text[-SCREEN_SIZE[1]/font_heigh:] #点X退出 if event.type == QUIT: exit() #用白色填充背景 screen.fill((255, 255, 255)) # 找一个合适的起笔位置,最下面开始但是要留一行的空 y = SCREEN_SIZE[1]-font_heigh for text in reversed(event_text): screen.blit(font.render(text, True, (0, 0 ,0)), (0, y)) y -= font_heigh #刷新 pygame.display.update()
程序效果:
把填充色的(0, 0, 0)改为(0, 255, 0),效果会想黑客帝国的字幕雨一样;这里字体颜色变成了浅绿色,确实不太像。
或许把背景色用fill调成黑色会好一些,不是重点。。。
鼠标在这个程序上的时候会产生大量的信息,都是程序捕捉到的事件。
处理鼠标事件
MOUSEMOTION事件会在鼠标动作的时候发生,它有三个参数:
- buttons – 一个含有三个数字的元组,三个值分别代表左键、中键和右键,1就是按下了。
- pos – 就是位置了……
- rel – 代表了现在距离上次产生鼠标事件时的距离
和MOUSEMOTION类似的,我们还有MOUSEBUTTONDOWN和MOUSEBUTTONUP两个事件,看名字就明白是什么意思了。很多时候,你只需要知道鼠标点下就可以了,那就可以不用上面那个比较强大(也比较复杂)的事件了。它们的参数为:
- button – 看清楚少了个s,这个值代表了哪个按键被操作
- pos – 和上面一样
处理键盘事件
键盘和游戏手柄的事件比较类似,为KEYDOWN和KEYUP,下面有一个例子来演示使用方向键移动一些东西。
#-*- coding:utf-8 -*- background_image_filename = "./images/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循环捕捉每次出现的事件 for event in pygame.event.get(): if event.type == QUIT: exit() #如果键盘被按下 if event.type == KEYDOWN: #按下左键x左边减1,左移 if event.key == K_LEFT: 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,y坐标 x += move_x y += move_y screen.fill((0, 0, 0)) screen.blit(background, (x, y)) #刷新 pygame.display.update()
原代码的最后五行放在了for循环中,导致只能按一下键盘移动一次图片,将其改到while这个死循环中,就能很流畅的移动图片了。传递最终结果,而不是每次for循环的结果。
收入一个字典方法的移动图片:
x, y = 320, 240 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: move[event.key] = 1 elif event.type == KEYUP: if event.key in move: 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(picture, (x,y)) pygame.display.update()
事件过滤
我们使用pygame.event.set_blocked(事件名)来完成。如果有好多事件需要过滤,可以传递一个列表,比如pygame.event.set_blocked([KEYDOWN, KEYUP]),如果你设置参数None,那么所有的事件有被打开了。与之相对的,我们使用pygame.event.set_allowed()来设定允许的事件。
产生事件
通常玩家做什么,Pygame就产生对应的事件就可以了,不过有的时候我们需要模拟出一些事件来,比如录像回放的时候,我们就要把用户的操作再现一遍。
为了产生事件,必须先造一个出来,然后再传递它:
Python 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)
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