SHO酱的Blog

SHO酱的Blog

pygame事件

354
2022-08-20

说明

对于输入事件主要有3类:键盘按键事件、鼠标事件(移动和按键)、手柄事件(按键、摇杆、方向)

键盘事件

键盘事件主要有两个类型,按键按下KEYDOWN与按键抬起KEYUP
键盘事件回调参数常用的有event.type/event.key/event.mod,还有event.unicode但该属性会在不同的操作系统中有不同的表现,所以不推荐使用。

  • event.type 事件类型,KEYDOWNKEYUP
  • event.key 按键的键值,在 pygame 中有以“K_”开头定义的常量来对应该key的值,如:pygame.K_a;
  • event.mod 在按键事件被触发是,功能键是否被按下,以位运算方式返回。
import pygame

pygame.init()
screen = pygame.display.set_mode((600, 400), pygame.SHOWN)
clock = pygame.time.Clock()
keepPlaying = True

def main():
    global keepPlaying
    while keepPlaying:
        clock.tick(120)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                keepPlaying = False
            if event.type == pygame.KEYDOWN:
                print('按下', event.key == pygame.K_a,
                      "alt" if event.mod & pygame.KMOD_ALT else "",
                      "ctrl" if event.mod & pygame.KMOD_CTRL else "",
                      "shift" if event.mod & pygame.KMOD_SHIFT else "")
                if event.key == pygame.K_ESCAPE:
                    keepPlaying = False
            elif event.type == pygame.KEYUP:
                print('抬起', event.key == pygame.K_a,
                      "alt" if event.mod & pygame.KMOD_ALT else "",
                      "ctrl" if event.mod & pygame.KMOD_CTRL else "",
                      "shift" if event.mod & pygame.KMOD_SHIFT else "")

if __name__ == '__main__':
    main()

鼠标事件

鼠标事件主要用的类型有3个:鼠标移动MOUSEMOTION/按键按下MOUSEBUTTONDOWN/按键抬起MOUSEBUTTONUP
事件说明:

  • MOUSEMOTION鼠标移动,主要用到三个参数
    • pos事件发生的位置(x, y)
    • rel事件发生相对上一次的位置偏移量(x, y)
    • buttons鼠标移动时按键情况(a, b, c),其中abc分别对应左键、中键、右键,值为1时说明对应位置按键按下,值为0则未按下。
  • MOUSEBUTTONDOWN/MOUSEBUTTONUP按键按下抬起类型参数类似,这里一起说明
    • pos事件发生的位置(x, y)
    • button按下或抬起按键的值,1左键 / 2中键 / 3右键。
import pygame

pygame.init()
screen = pygame.display.set_mode((600, 400), pygame.SHOWN)
clock = pygame.time.Clock()
keepPlaying = True

def main():
    global keepPlaying
    while keepPlaying:
        clock.tick(120)
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                keepPlaying = False
            elif event.type == pygame.MOUSEMOTION:
                print("移动",
                      event.pos,  # 鼠标相对游戏窗口左上角的位置
                      event.rel,  # 鼠标相对上一事件的位置偏移量
                      event.buttons)  # 元组中3个元素对应鼠标按键,位置0左,位置1中,位置2右,值为1时相对应的按键按下,0时未按下
            elif event.type == pygame.MOUSEBUTTONDOWN:
                print("按下",
                      event.pos,  # 鼠标相对游戏窗口左上角的位置
                      event.button)  # 按下的按键:1左 2中 3右
            elif event.type == pygame.MOUSEBUTTONUP:
                print("抬起",
                      event.pos,  # 鼠标相对游戏窗口左上角的位置
                      event.button)  # 按下的按键:1左 2中 3右

if __name__ == '__main__':
    main()

手柄事件

这里以 xbox 手柄为例。

2022-08-27更新:今天手柄除了事件以外还有很多其他的功能,比如在Sprite中检测按键状态、摇杆状态,以及使手柄震动等;之后单独开一篇记录。

手柄事件相较键盘和鼠标稍微复杂,事件类型有:JOYBUTTONDOWN按键按下 / JOYBUTTONUP按键抬起 / JOYAXISMOTION轴(摇杆或线性扳机)转动 / JOYHATMOTION方向键按下抬起变化 / JOYDEVICEADDED添加手柄 / JOYDEVICEREMOVED移除手柄。
对事件分别说明:

  • JOYDEVICEADDED 当游戏开始运行时识别手柄、游戏运行后手柄接入时触发,需要在事件触发时对手柄进行初始化和记录;
  • JOYDEVICEREMOVED 游戏运行时手柄拔出时触发,需要在事件触发时对手柄进行处理;
  • JOYBUTTONDOWN / JOYBUTTONUP 简介按下或抬起时触发,主要属性如下
    • button对应的按键值,按键值的说明:a = 0 b = 1 x = 2 y = 3 lb = 4 rb = 5 view/back = 6 menu/start = 7
    • instance_id对应的手柄ID。
  • JOYAXISMOTION轴转动的线性数值,这里需要特别说明,线性扳机也被归类在这里一同处理,主要属性如下
    • axis轴的ID,0 = 左摇杆X轴 1 = 左摇杆Y轴 2 = 右摇杆X轴 3 = 右摇杆Y轴 4 = 左扳机 5 = 右扳机
    • value 线性数值的偏移量,在-1到1之间取值,对与摇杆来说负值为左和上、正值为右和下,对与扳机键来说被分为两段,开始按下时为负值,随着逐渐按压值逐渐增大到0,再逐渐到1;
    • instance_id 对应的手柄ID。
import pygame

pygame.init()
joysticks = []
joystick_axis = [0, 1, 2, 3]
joystick_trigger = [4, 5]
joystick_buttons = ["a", "b", "x", "y", "lb", "rb", "view", "menu", "down", "left", "", "right", "up"]
clock = pygame.time.Clock()
keepPlaying = True


# 初始化手柄
def init_joystick(index):
    joystick = pygame.joystick.Joystick(index)
    joystick.init()
    return joystick

def main():
    global joysticks, keepPlaying
    while keepPlaying:
        clock.tick(120)
        for event in pygame.event.get():
            if event.type == pygame.JOYBUTTONDOWN:
                print("按下", joystick_buttons[event.button], event.instance_id, event.button)
                if event.button == 6:
                    keepPlaying = False
                # a 0
                # b 1
                # x 2
                # y 3
                # lb 4
                # rb 5
                # view/back 6
                # menu/start 7
            elif event.type == pygame.JOYBUTTONUP:
                print("抬起", joystick_buttons[event.button], event.instance_id, event.button)
            elif event.type == pygame.JOYAXISMOTION:
                if event.axis in joystick_axis and abs(event.value) > 0.28:
                    if event.axis == 0:  # 左摇杆X
                        print("左摇杆X", event.instance_id, event.value)
                    elif event.axis == 1:  # 左摇杆Y
                        print("左摇杆Y", event.instance_id, event.value)
                    elif event.axis == 2:  # 右摇杆X
                        print("右摇杆X", event.instance_id, event.value)
                    elif event.axis == 3:  # 右摇杆Y
                        print("右摇杆Y", event.instance_id, event.value)
                if event.axis in joystick_trigger:
                    event_value = event.value + 1
                    if event_value > 0.1:
                        if event.axis == 4:  # 左扳机
                            print("左扳机", event.instance_id, event_value)
                        elif event.axis == 5:  # 右扳机
                            print("右扳机", event.instance_id, event_value)
            elif event.type == pygame.JOYHATMOTION:
                # 方向键
                # 上 value(0,1)
                # 下 value(0,-1)
                # 左 value(-1,0)
                # 右 value(1,0)
                if event.value != (0, 0):
                    print(joystick_buttons[event.value[0]+event.value[1]*2+10],
                          event.instance_id, event.value[0], event.value[1])
            elif event.type == pygame.JOYDEVICEADDED:
                # 添加手柄
                joysticks = [init_joystick(i) for i in range(0, pygame.joystick.get_count())]
            elif event.type == pygame.JOYDEVICEREMOVED:
                # 移除手柄
                joysticks = [init_joystick(i) for i in range(0, pygame.joystick.get_count())]

if __name__ == '__main__':
    main()