事件介绍

本片文章介绍如何获取输入设备(鼠标、键盘)的状态,有使用事件队列和使用相应模块两种方法可以达到目的

模块访问

所谓的模块访问指的是如果访问键盘就使用pygame.key模块的相应方法,如果访问鼠标就使用pygame.mouse模块的相应方法。这种方式的特点在于每次都会处理。代码如下:

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
import pygame
import sys

pygame.init()
screen=pygame.display.set_mode((800,400))
clock=pygame.time.Clock()

while True:
# 事件循环
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

# 打印鼠标按下的状态
mous_pos=pygame.mouse.get_pos()
print("鼠标左、中、右键按下状态:"+str(pygame.mouse.get_pressed()))
print("鼠标位置:"+str(mous_pos))

# 检测键盘输入
keys=pygame.key.get_pressed() # 获取输入对象
print("所有按键按下状态:"+str(keys))
print("空格键按下状态:"+str(keys[pygame.K_SPACE])) # 根据按键名查询按键状态
print("/*****************************************************************************************************************************/")
print()

# 绘制和更新所有内容
pygame.display.update()
clock.tick(1)

运行结果为:

事件队列

因为键盘按钮被按下和释放时会接收pygame.KEYDOWNpygame.KEYUP事件;鼠标按钮在按下和释放时会生成pygame.MOUSEBUTTONDOWNpygame.MOUSEBUTTONUP事件;滚动鼠标滚轮时会生成pygame.MOUSEBUTTONDOWNpygame.MOUSEBUTTONUP事件;鼠标移动时会生成一个pygame.MOUSEMOTION事件,所以可以通过遍历事件队列进行对指定事件进行处理。由于是对事件的处理,所以没有动作发生时不会执行处理逻辑。代码如下:

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
import pygame
import sys

pygame.init()
screen=pygame.display.set_mode((800,400))

while True:
# 事件循环
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

#使用循环事件检查获取鼠标位置,当鼠标移动时生效
if event.type==pygame.MOUSEMOTION:
print("鼠标位置:"+str(pygame.mouse.get_pos()))

# 鼠标按下的按键
if event.type==pygame.MOUSEBUTTONDOWN:
print("鼠标按键状态:"+str(pygame.mouse.get_pressed(num_buttons=5)))

# 循环事件检查键盘按键状态,
if event.type==pygame.KEYDOWN:
key_name=pygame.key.name(event.key)
print(key_name+"键按下")
if event.type==pygame.KEYUP:
key_name=pygame.key.name(event.key)
print(key_name+"键松开")

# 绘制和更新所有内容
pygame.display.update()
pygame.time.Clock().tick(24)

运行结果为:

自定义事件

除了使用外部设备行为触发事件外,也可以自定义事件和事件触发机制。自定义事件触发可以定时器触发,也可以通过自定义逻辑触发。
定时器触发事件代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import pygame
import sys

pygame.init()
screen=pygame.display.set_mode((800,400))

# 计时器
obstacle_time=pygame.USEREVENT+1
pygame.time.set_timer(obstacle_time,600) #代码触发事件(触发事件类选,触发间隔)

while True:
# 事件循环
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

# 当计时器触发时,执行事件
if event.type==obstacle_time:
print("自定义事件:{"+str(obstacle_time)+"}"+",计时器:"+str(pygame.time.get_ticks()))

# 绘制和更新所有内容
pygame.display.update()
pygame.time.Clock().tick(60)

运行结果为:

自定义逻辑触发事件代码如下

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
import pygame
import sys

pygame.init()
screen=pygame.display.set_mode((800,400))

# 计时器
custom_event_type=pygame.USEREVENT+1
custom_event =pygame.event.Event(custom_event_type)

while True:
# 事件循环
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()

# 当计时器触发时,执行事件
if event==custom_event:
print("自定义事件触发,时间为:"+event.message)
# 自定义逻辑触发
if pygame.time.get_ticks()%2000>1980:
custom_event.message=str(pygame.time.get_ticks())
pygame.event.post(custom_event) # 加入事件队列

# 绘制和更新所有内容
pygame.display.update()
pygame.time.Clock().tick(24)

运行结果为:

pygame.event

Pygame通过事件队列处理所有事件消息。该模块中的例程帮助您管理该事件队列。输入队列严重依赖于pygame.display模块来控制显示窗口和屏幕。如果显示没有被初始化并且视频模式没有设置,事件队列可能无法正常工作。

事件队列对其可以容纳的事件数量有一个上限。当队列变满时,新事件会被悄悄丢弃。为防止事件丢失,特别是那些表示退出命令的输入事件,您的程序必须每帧处理事件(使用pygame.event.get()pygame.event.pump()pygame.event.wait()pygame.event.peek()pygame.event.clear()),并对其进行处理。不处理事件可能导致系统认为您的程序已经死锁。为了加速队列处理,使用pygame.event.set_blocked()控制哪些事件允许进入队列以限制进入队列的事件。

要获取各种输入设备的状态,可以放弃事件队列,直接使用相应的模块访问输入设备:

  • pygame.mouse(用于处理鼠标的模块)
  • pygame.key(用于处理键盘的模块)
  • pygame.joystick(用于与游戏手柄、游戏板和跟踪球交互的模块)

如果使用这种方法,请记住pygame需要与系统窗口管理器和平台的其他部分进行某种形式的通信。为了保持pygame与系统同步,需要调用pygame.event.pump()来内部处理pygame事件处理程序以保持一切都是最新的。通常,这应该在每个游戏循环中调用一次。注意:在设备初始化之前,游戏手柄将不会发送任何事件。

事件队列包含pygame.event.Event(用于表示事件的事件对象)实例。有多种访问队列中事件的方法,从简单地检查事件的存在到直接从堆栈中获取它们。事件队列还提供了一些简单的过滤器,可以通过阻止队列中的某些事件类型来稍微提高性能。使用pygame.event.set_allowed()控制哪些事件允许进入队列,pygame.event.set_blocked()控制哪些事件禁止进入队列来更改此过滤。

所有pygame.event.Event实例都包含一个事件类型标识符和特定于该事件类型的属性。事件类型标识符可以通过pygame.event.Event.type属性访问。可以通过pygame.event.Event.__dict__事件属性字典属性或直接作为事件对象的属性(因为成员查找被传递到对象的字典值)来访问任何特定于事件的属性。事件对象没有方法函数。用户可以使用pygame.event.Event()函数创建自己的新事件。

事件类型标识符位于NOEVENTNUMEVENTS的值之间。用户定义的事件应该在USEREVENTNUMEVENTS - 1的包含范围内具有一个值。用户定义的事件可以使用pygame.event.custom_type()创建自定义用户事件类型,该函数为用户事件获取自定义事件编号。建议所有用户事件都遵循这个系统。

事件支持相等性和不等性比较。如果两个事件具有相同的类型和相同的属性值,它们就是相等的。在调试和实验中,可以打印事件对象以快速显示其类型和成员。函数pygame.event.event_name()可以用于获取表示事件类型名称的字符串。
本节全文引用来源:https://www.pygame.org/docs/ref/event.html

pygame.key

pygame.event模块的事件队列在键盘按钮被按下和释放时会接收pygame.KEYDOWNpygame.KEYUP事件。这两个事件都有keymod属性。

  • key: 代表键盘上每个按键的整数ID

  • mod: 在事件发生时处于按下状态的所有修改键的位掩码

    pygame.KEYDOWN事件还具有额外的属性unicodescancode

  • unicode: 一个单字符字符串,是完全翻译的输入字符,考虑了Shift和组合键

  • scancode: 平台特定的键码,可能因键盘而异,但对于选择奇怪的按键(如多媒体键)很有用。

本节全文引用来源:https://www.pygame.org/docs/ref/key.html

pygame.mouse

当显示模式设置后,事件队列将开始接收鼠标事件。鼠标按钮在按下和释放时会生成pygame.MOUSEBUTTONDOWNpygame.MOUSEBUTTONUP事件。这些事件包含一个button属性,表示按下了哪个按钮。当滚动鼠标滚轮时,会生成pygame.MOUSEBUTTONDOWNpygame.MOUSEBUTTONUP事件。当向上滚动滚轮时,button将被设置为4;当向下滚动滚轮时,button将被设置为5。每当鼠标移动时,都会生成一个pygame.MOUSEMOTION事件。鼠标的移动被分解为小而准确的运动事件。随着鼠标移动,许多运动事件将被放置在队列中。未正确清除事件队列中的鼠标运动事件是导致事件队列填满的主要原因。

如果鼠标光标被隐藏,并且输入被捕获到当前显示器,鼠标将进入虚拟输入模式,其中鼠标的相对移动不会受到屏幕边界的限制。参见函数pygame.mouse.set_visible()pygame.event.set_grab()以进行此配置。

在pygame 2中,对鼠标滚轮行为的支持是通过监听pygame.MOUSEWHEEL事件实现的。这些新的事件支持水平和垂直方向上的滚动,使用带符号的整数值表示滚动的量(x和y),以及翻转的方向(每个轴的正负值被翻转)。更多关于SDL2输入相关变化的信息可以在这里查看:SDL2 Migration Guide

在pygame 2中,可以通过监听pygame.MOUSEWHEEL事件来使用鼠标滚轮功能(请注意,它们仍然会发出pygame.MOUSEBUTTONDOWN事件)。当触发此事件时,开发者可以通过pygame.event.get()来获取相应的事件对象。该对象可用于访问有关鼠标滚动的数据,例如触发事件的确切鼠标设备。
本节全文引用来源:https://www.pygame.org/docs/ref/mouse.html