Pygame Event事件模块(示例)
原文链接
参考文章
事件(Event)是 Pygame 的重要模块之一,它是构建整个游戏程序的核心,比如鼠标点击、键盘敲击、游戏窗口移动、调整窗口大小、触发特定的情节、退出游戏等等,这些都可以看做是“事件”,Pygame 会接受用户产生的各种操作(或事件),这些操作随时产生,并且操作量可大可小,那么 Pygame 是如何处理这些事件的呢?
事件类型
Pygame 定义了一个专门用来处理事件的结构,即事件队列,该结构遵循队列“先到先处理”的基本原则,通过事件队列,我们可以有序的、逐一的处理用户的操作(触发事件)。下述表格列出了 Pygame 中常用的游戏事件:
事件类型 | 描述 | 成员属性 |
---|---|---|
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 | 触发一个用户事件 | 事件代码 |
注意,当使用 Pygame 做游戏开发时,上述事件并非都会应用的到,因此在学习的过程中,我们要懂得触类旁通、举一反三。
事件处理方法
Pygame.event 模块提供了处理事件队列的常用方法,如下表所示:
方法 | 说明 |
---|---|
pygame.event.get() | 从事件队列中获取一个事件,并从队列中删除该事件 |
pygame.event.wait() | 阻塞直至事件发生才会继续执行,若没有事件发生将一直处于阻塞状态 |
pygame.event.set_blocked() | 控制哪些事件禁止进入队列,如果参数值为None,则表示禁止所有事件进入 |
pygame.event.set_allowed() | 控制哪些事件允许进入队列 |
pygame.event.pump() | 调用该方法后,Pygame 会自动处理事件队列 |
pygame.event.poll() | 会根据实际情形返回一个真实的事件,或者一个None |
pygame.event.peek() | 检测某类型事件是否在队列中 |
pygame.event.clear() | 从队列中清除所有的事件 |
pygame.event.get_blocked() | 检测某一类型的事件是否被禁止进入队列 |
pygame.event.post() | 放置一个新的事件到队列中 |
pygame.event.Event() | 创建一个用户自定义的新事件 |
当我们使用 Pygame 处理事件时,逻辑一般都是相似的。首先是判断事件的类型,然后根据不同的事件操作,执行不同的游戏操作。因此这种情况非常适合使用 if … else 语句。如下所示:
while True:
#等待事件发生
event = pygame.event.wait()
if event.type == pygame.QUIT:
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
print('鼠标按下',event.pos)
if event.type == pygame.MOUSEBUTTONUP:
print('鼠标弹起')
if event.type == pygame.MOUSEMOTION:
print('鼠标移动')
# 键盘事件
if event.type ==pygame.KEYDOWN:
# 打印按键的英文字符
print('键盘按下',chr(event.key))
if event.type == pygame.KEYUP:
print('键盘弹起')
下面应用上述方法对鼠标事件和键盘事件分别做简单的介绍。
处理键盘事件
键盘事件会涉及到大量的按键操作,比如游戏中的上下左右,或者人物的前进、后退等操作,这些都需要键盘来配合实现。
键盘事件提供了一个 key 属性,通过该属性可以获取键盘的按键。Pygame 将键盘上的字母键、数字键、组合键等按键以常量的方式进行了定义,下表列出了按键的常量:
KeyASCII | ASCII | 描述 |
---|---|---|
K_BACKSPACE | \ b | 退格键(Backspace) |
K_TAB | \ t | 制表键(Tab) |
K_CLEAR | 清楚键(Clear) | |
K_RETURN | \ r | 回车键(Enter) |
K_PAUSE | 暂停键(Pause) | |
K_ESCAPE | ^[ | 退出键(Escape) |
K_SPACE | 空格键(Space) | |
K_EXCLAIM | ! | 感叹号(exclaim) |
K_QUOTEDBL | " | 双引号(quotedbl) |
K_HASH | # | 井号(hash) |
K_DOLLAR | $ | 美元符号(dollar) |
K_AMPERSAND | & | and 符号(ampersand) |
K_QUOTE | ' | 单引号(quote) |
K_LEFTPAREN | ( | 左小括号(left parenthesis) |
K_RIGHTPAREN | ) | 右小括号(right parenthesis) |
K_ASTERISK | * | 星号(asterisk) |
K_PLUS | + | 加号(plus sign) |
K_COMMA | , | 逗号(comma) |
K_MINUS | - | 减号(minus sign) |
K_PERIOD | . | 句号(period) |
K_SLASH | / | 正斜杠(forward slash) |
K_0 | 0 | 0 |
K_1 | 1 | 1 |
K_2 | 2 | 2 |
K_3 | 3 | 3 |
K_4 | 4 | 4 |
K_5 | 5 | 5 |
K_6 | 6 | 6 |
K_7 | 7 | 7 |
K_8 | 8 | 8 |
K_9 | 9 | 9 |
K_COLON | : | 冒号(colon) |
K_SEMICOLON | ; | 分号(semicolon) |
K_LESS | < | 小于号(less-than sign) |
K_EQUALS | = | 等于号(equals sign) |
K_GREATER | > | 大于号(greater-than sign) |
K_QUESTION | ? | 问号(question mark) |
K_AT | @ | at 符号(at) |
K_LEFTBRACKET | [ | 左中括号(left bracket) |
K_BACKSLASH | \ | 反斜杠(backslash) |
K_RIGHTBRACKET | ] | 右中括号(right bracket) |
K_CARET | ^ | 脱字符(caret) |
K_UNDERSCORE | _ | 下划线(underscore) |
K_BACKQUOTE | ` | 重音符(grave) |
K_a | a | a |
K_b | b | b |
K_c | c | c |
K_d | d | d |
K_e | e | e |
K_f | f | f |
K_g | g | g |
K_h | h | h |
K_i | i | i |
K_j | j | j |
K_k | k | k |
K_l | l | l |
K_m | m | m |
K_n | n | n |
K_o | o | o |
K_p | p | p |
K_q | q | q |
K_r | r | r |
K_s | s | s |
K_t | t | t |
K_u | u | u |
K_v | v | v |
K_w | w | w |
K_x | x | x |
K_y | y | y |
K_z | z | z |
K_DELETE | 删除键(delete) | |
K_KP0 | 0(小键盘) | |
K_KP1 | 1(小键盘) | |
K_KP2 | 2(小键盘) | |
K_KP3 | 3(小键盘) | |
K_KP4 | 4(小键盘) | |
K_KP5 | 5(小键盘) | |
K_KP6 | 6(小键盘) | |
K_KP7 | 7(小键盘) | |
K_KP8 | 8(小键盘) | |
K_KP9 | 9(小键盘) | |
K_KP_PERIOD | . | 句号(小键盘) |
K_KP_DIVIDE | / | 除号(小键盘) |
K_KP_MULTIPLY | * | 乘号(小键盘) |
K_KP_MINUS | - | 减号(小键盘) |
K_KP_PLUS | + | 加号(小键盘) |
K_KP_ENTER | \r | 回车键(小键盘) |
K_KP_EQUALS | = | 等于号(小键盘) |
K_UP | 向上箭头(up arrow) | |
K_DOWN | 向下箭头(down arrow) | |
K_RIGHT | 向右箭头(right arrow) | |
K_LEFT | 向左箭头(left arrow) | |
K_INSERT | 插入符(insert) | |
K_HOME | Home 键(home) | |
K_END | End 键(end) | |
K_PAGEUP | 上一页(page up) | |
K_PAGEDOWN | 下一页(page down) | |
K_F1 | F1 | |
K_F2 | F2 | |
K_F3 | F3 | |
K_F4 | F4 | |
K_F5 | F5 | |
K_F6 | F6 | |
K_F7 | F7 | |
K_F8 | F8 | |
K_F9 | F9 | |
K_F10 | F10 | |
K_F11 | F11 | |
K_F12 | F12 | |
K_F13 | F13 | |
K_F14 | F14 | |
K_F15 | F15 | |
K_NUMLOCK | 数字键盘锁定键(numlock) | |
K_CAPSLOCK | 大写字母锁定键(capslock) | |
K_SCROLLOCK | 滚动锁定键(scrollock) | |
K_RSHIFT | 右边的 shift 键(right shift) | |
K_LSHIFT | 左边的 shift 键(left shift) | |
K_RCTRL | 右边的 ctrl 键(right ctrl) | |
K_LCTRL | 左边的 ctrl 键(left ctrl) | |
K_RALT | 右边的 alt 键(right alt) | |
K_LALT | 左边的 alt 键(left alt) | |
K_RMETA | 右边的元键(right meta) | |
K_LMETA | 左边的元键(left meta) | |
K_LSUPER | 左边的 Window 键(left windows key) | |
K_RSUPER | 右边的 Window 键(right windows key) | |
K_MODE | 模式转换键(mode shift) | |
K_HELP | 帮助键(help) | |
K_PRINT | 打印屏幕键(print screen) | |
K_SYSREQ | 魔术键(sysrq) | |
K_BREAK | 中断键(break) | |
K_MENU | 菜单键(menu) | |
K_POWER | 电源键(power) | |
K_EURO | 欧元符号(euro) |
下面通过“图片移动”示例来了解键盘事件的处理过程,如下所示:
import pygame
import sys
# 初始化pygame
pygame.init()
# 定义变量
size = width, height = 600, 400
bg = (255, 255, 255)
# 加载logo图
img = pygame.image.load("C:/Users/Administrator/Desktop/logo.jpg")
# 获取图像的位置
position = img.get_rect()
# 创建一个主窗口
screen = pygame.display.set_mode(size)
# 标题
pygame.display.set_caption("C语言中文网")
# 创建游戏主循环
while True:
# 设置初始值
site = [0, 0]
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# 图像移动 KEYDOWN 键盘按下事件
# 通过 key 属性对应按键
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
site[1] -= 8
if event.key == pygame.K_DOWN:
site[1] += 8
if event.key == pygame.K_LEFT:
site[0] -= 8
if event.key == pygame.K_RIGHT:
site[0] += 8
# 移动图像
position = position.move(site)
# 填充背景
screen.fill(bg)
# 放置图片
screen.blit(img, position)
# 更新显示界面
pygame.display.flip()
对键盘的连续监听
大家请看下面这一段代码:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
print("右")
if event.key == pygame.K_UP:
print("上")
if event.key == pygame.K_DOWN:
print("下")
if event.key == pygame.K_LEFT:
print("左")
大家首次监控键盘事件一般都会写出这样的代码我们着重来看一下对键盘上下左右键的监控。我们运行代码块我们会发现这几行代码和我们的想法是不一样的,我们在开发游戏的时候,我们大部分时候希望是可以连续控制,这样可以大大减少我们的手部疲劳,对玩家们也会非常的友好,但是我们现在的代码块,是敲一下键盘响应一次事件。所以我们要对代码进行改进,改进的方法有以下两种,大家可以根据自己的理解进行选择。
方法一:设置中间变量
moving_r = False
moving_l = False
moving_u = False
moving_d = False
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
moving_r = True
if event.key == pygame.K_UP:
moving_u = True
if event.key == pygame.K_DOWN:
moving_d = True
if event.key == pygame.K_LEFT:
moving_l = True
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
moving_r = False
if event.key == pygame.K_UP:
moving_u = False
if event.key == pygame.K_DOWN:
moving_d = False
if event.key == pygame.K_LEFT:
moving_l = False
if moving_r:
print("右")
elif moving_u:
print("上")
elif moving_d:
print("下")
elif moving_l:
print("左")
引入四个moving变量将四个变量的初值均设为Flase,用pygame的KEYDOWN和KEYUP方法来改变四个变量的值,以此来实现对键盘的连续监控,这种方法虽然很好理解,但是如果是小白对代码的重构不是很熟悉会显得非常缀余。
方法二:运用pygame中get_pressed()
Key_pressed = pygame.key.get_pressed()
if Key_pressed[K_UP]:
print("上")
if Key_pressed[K_DOWN]:
print("下")
if Key_pressed[K_LEFT]:
print("左")
if Key_pressed[K_RIGHT]:
print("右")
这样也是能连续监听键盘事件,但是这里需要注意一下if半段语句后面是中括号并非是小括号,第二个要注意的地方便是键盘名称,如果直接输入K_UP等是会报错的,有两种解决办法一种是导入pygame的方法:
from pygame import *
这样就不会报错了,另一种是在K_UP 前面加上pygame如:
if Key_pressed[pygame.K_UP]:
print("上")
处理鼠标事件
鼠标是计算机最重要外接设备之一,同时它也是游戏玩家必不可少的工具之一。
Pygame 提供了三个鼠标事件,分别是鼠标移动
(MOUSEMOTION
)、鼠标按下(MOUSEBUTTONDOWN
)、鼠标释放(MOUSEBUTTONUP
),不同事件类型对应着不同的成员属性。如下所示:
pygame.event.MOUSEMOTION
鼠标移动事件
event.pos
相对于窗口左上角,鼠标的当前坐标值(x,y)event.rel
鼠标相对运动距离(X,Y),相对于上次事件event.buttons
鼠标按钮初始状态(0,0,0),分别对应(左键,滑轮,右键),移动过程中点击那个键,相应位置变会为1
pygame.event.MOUSEBUTTONUP
鼠标键释放事件
event.pos
相对于窗口左上角,鼠标的当前坐标值(x,y)event.button
鼠标释放键编号(整数)左键为1,按下滚动轮2、右键为3
pygame.event.MOUSEBUTTONDOWN
鼠标键按下事件
event.pos
相对于窗口左上角,鼠标的当前坐标值(x,y)event.button
鼠标按下键编号(整数),左键为1,按下滚动轮2、右键为3,向前滚动滑轮4、向后滚动滑轮5
通过一组简单的示例对鼠标事件进行演示,示例代码如下:
import pygame
from random import randint
# 初始化程序
pygame.init()
screen = pygame.display.set_mode((450,400))
pygame.display.set_caption("c语言中文网")
# 更新显示
pygame.display.flip()
while True:
#等待事件发生
event = pygame.event.wait()
if event.type == pygame.QUIT:
exit("成功退出")
if event.type == pygame.MOUSEBUTTONDOWN:
# pos 获取鼠标当前位置
print('鼠标按下',event.pos)
mx,my = event.pos
# 调用 pygame.draw 模块画圆
pygame.draw.circle(screen,(255,255,0),(mx,my),50)
if event.type == pygame.MOUSEBUTTONUP:
print('鼠标弹起')
pass
if event.type == pygame.MOUSEMOTION:
print('鼠标移动')
mx, my = event.pos
# 随机生成 RGB 颜色值
r = randint(0,255)
g = randint(0,255)
b = randint(0,255)
pygame.draw.circle(screen, (r,g,b,),(mx, my), 50)
# 处理完,更新显示
pygame.display.update()