一、理解事件
我们上一个程序,一直运行直到关闭窗口而产生了一个QUIT事件,Pygame会接受用户的各种操作(比如按键盘,移动鼠标等)产生事件。事件随时可能发生,而且量也可能会很大,Pygame的做法是把一系列的事件存放一个队列里,逐个的处理。
二、事件检索
上个程序中,使用了pygame.event.get()来处理所有的事件;也可以使用pygame.event.wait(),pygame会等到发生一个时间才继续下去;另外一个方法pygame.event.poll(),一旦调用,它会根据现在的情形返回一个真实的事件,或者一个“什么都没有”。下表是一个常用事件集:
事件 | 产生途径 | 参数 |
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 | 游戏球(Joy 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 |
接下来我们写一个把所有发生的事件输出的程序
# -*- coding: utf-8 -*-
# Time : 2019/1/29 21:39
# Author : ***
import pygame
from pygame.locals import *
from sys import exit
if __name__ == "__main__":
pygame.init()
SCREEN_SIZE = (640, 480)
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
# font = pygame.font.SysFont("my_font.ttf", 16)
font = pygame.font.SysFont("arial", 16)
font_height = font.get_linesize()
event_text = []
while True:
event = pygame.event.wait()
event_text.append(str(event))
#获得时间的名称
event_text = event_text[int(-SCREEN_SIZE[1]/font_height):]
#这个切片操作保证了event_text里面只保留一个屏幕的文字
if event.type == QUIT:
exit()
screen.fill((255, 255, 255))
y = SCREEN_SIZE[1]-font_height
#找一个合适的起笔位置,最下面开始但是要留一行的空
for text in reversed(event_text):
screen.blit(font.render(text, True, (0, 0, 0)), (0, y))
#以后会讲
y-=font_height
#把笔提一行
pygame.display.update()
结果如下,会将发生的事件列出。在程序中使用wait(),因为这个程序只要在有动作时执行就好了。
三、处理鼠标事件
MOUSEMOTION事件会在鼠标动作的时候发生,它有三个参数:
buttons | 一个含有三个数字的元组,三个值分别代表左键、中键和右键,1就是按下了。 |
pos | 位置 |
rel | 代表了现在距离上次产生鼠标事件时的距离 |
和MOUSEMOTION类似的,我们还有MOUSEBUTTONDOWN和MOUSEBUTTONUP两个事件。它们的参数为:
button | 这个值代表了哪个按键被操作 |
pos | 位置 |
四、处理键盘事件
键盘的事件为KEYDOWN和KEYUP 。
下面这个例子演示的是使用方向键来移动图片。
# -*- coding: utf-8 -*-
# Time : 2019/1/29 22:03
# Author : hubozhi
import pygame
from pygame.locals import *
from sys import exit
import time
background_image_filename = './image/sushiplate.jpg'
if __name__ == "__main__":
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()
# 休眠,减缓持续移动时的速度
time.sleep(0.035)
KEYDOWN和KEYUP的参数描述如下:具体描述请点击这里
key | 按下或者放开的键值,是一个数字,Pygame中可以使用K_xxx来表示,比如字母a就是K_a,还有K_SPACE和K_RETURN等。 |
mo | 包含了组合键信息,如果mod & KMOD_CTRL是真的话,表示用户同时按下了Ctrl键。类似的还有KMOD_SHIFT,KMOD_ALT。 |
unicode | 代表了按下键的Unicode值 |
五、事件过滤
并不是所有的事件都需要处理。我们使用pygame.event.set_blocked(type)来完成。如果有好多事件需要过滤,可以传递一个列表,比如pygame.event.set_blocked([KEYDOWN, KEYUP]),如果你设置参数None,那么所有的事件有被打开了。与之相对的,我们使用pygame.event.set_allowed()**来设定允许的事件。
六、产生事件
通常玩家做什么,Pygame就产生对应的事件就可以了,不过有的时候我们需要模拟出一些事件来,比如录像回放的时候,我们就要把用户的操作再现一遍。
为了产生事件,必须先造一个出来,然后再传递它:
my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=' ')
# 你也可以像下面这样写
my_event = pygame.event.Event(KEYDOWN, {"key":K_SPACE, "mod":0, "unicode":' '})
pygame.event.post(my_event)
Event():Event(type, dict) 或者 Event(type, **attributes),
post(): 把新的事件放在事件队列的最后。
下面的代码会显示效果:
# -*- coding: utf-8 -*-
# Time : 2019/1/30 21:15
# Author : ***
import pygame
from pygame.locals import *
from sys import exit
if __name__ == "__main__":
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))# 获得事件的名称
event_text = event_text[int(-SCREEN_SIZE[1] / font_height):]
# 这个切片操作保证了event_text里面只保留一个屏幕的文字
# 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' '})
if event.type == QUIT:
exit()
# 将模拟的操作加入到队列的最后
# event_text.append('my====='+str(my_event))
pygame.event.post(my_event)#注意:该种写法需要在退出判断的后面,否则退出操作会被覆盖
screen.fill((255, 255, 255))
y = SCREEN_SIZE[1] - font_height
# 找一个合适的起笔位置,最下面开始但是要留一行的空
for text in reversed(event_text):
screen.blit(font.render(text, True, (0, 0, 0)), (0, y))
y -= font_height
# 把笔提一行
pygame.display.update()
也可以产生一个完全自定义的全新事件。
import pygame
from pygame.locals import *
pygame.init()
my_event = pygame.event.Event(KEYDOWN, key=K_SPACE, mod=0, unicode=' ')
# my_event = pygame.event.Event(KEYDOWN,{"key":K_SPACE, "mod":0, "unicode":' '})
pygame.event.post(my_event)
###############
# 产生一个自定义的全新事件
CATONKEYBOARD = USEREVENT + 1
my_event = pygame.event.Event(CATONKEYBOARD, message="bad act!")
pygame.event.post(my_event)
# 获得这个事件
for event in pygame.event.get():
if event.type == CATONKEYBOARD:
print( event.message)
五、显示
全屏显示
在第一个例子“hello world”中,使用了如下语句
screen = pygame.display.set_mode((640, 480), 0, 32)
如果把第二个参数设置成FULLSCREEN,就会得到一个全屏显示的窗口。
screen = pygame.display.set_mode((640, 480), FULLSCREEN | RESIZEABLE, 32)
#两个及以上用‘|’分隔开
在全屏模式下,显卡可能就切换了一种模式,你可以用如下代码获得您的机器支持的显示模式
>>> import pygame
>>> pygame.init()
>>> pygame.display.list_modes()