Pygame - 如何让用户更改输入按键?(自定义按键绑定)

3

我正在制作游戏,希望用户能够更改他们的输入按键,例如,他们按下A键,将MoveUp变量更改为A键,这样当他们在游戏中按下A键时,就会向上移动。非常感谢您提供任何帮助或建议。

global MoveUp   # MoveUp = pygame.K_UP
while not Fin:
    for event in pygame.event.get():
        pressed = pygame.key.pressed()
        if event.type == pygame.KEYDOWN:
            MoveUp = pressed
            KeysLoop()

这段代码目前的问题在于它返回了与按键相对应的列表,我需要一个按键标识符,以便稍后使用MoveUp移动我的精灵。

这个能用吗?如果不能,描述一下问题。我们无法运行它来查看。 - furas
也许在点击后,你应该退出这个循环,或者至少设置变量 key_selected = True 并使用它来停止再次选择键。 - furas
@furas 我修改了代码,使其更具体 - 目前这段代码的问题是它给我返回一个与按键对应的列表,我需要一个按键标识符,以便稍后使用MoveUp移动我的精灵。 - cdd
key.pressed() 总是返回一个包含所有按键的 True/False 值的列表。使用 event.key 来获取被按下的按键。 - furas
1
MoveUp = event.key BTW: you forgot : after pygame.KEYDOWN - furas
显示剩余2条评论
2个回答

4
您可以创建一个字典,将操作名称作为字典键,将pygame键(pygame.K_LEFT等)作为值。例如:
input_map = {'move right': pygame.K_d, 'move left': pygame.K_a}

这允许你将其他pygame按键分配给这些操作(在分配菜单的事件循环中):

if event.type == pygame.KEYDOWN:
    # Assign the pygame key to the action in the keys dict.
    input_map[selected_action] = event.key

接下来,在主while循环中,您可以使用动作名称来检查相应的键盘按键是否已按下:

pressed_keys = pygame.key.get_pressed()
if pressed_keys[input_map['move right']]:

在下面的例子中,你可以通过点击 ESCAPE 键来访问 assignment_menu。这是一个独立的函数,有自己的 while 循环,在其中我创建了一个动作和 pygame 键的表格,您可以通过鼠标选择。如果选择了一个动作并且用户按下一个键,我会更新 input_map 字典,并在用户再次按下 Esc 时将其返回给主游戏函数。

import sys
import pygame as pg


pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
FONT = pg.font.Font(None, 40)

BG_COLOR = pg.Color('gray12')
GREEN = pg.Color('lightseagreen')


def create_key_list(input_map):
    """A list of surfaces of the action names + assigned keys, rects and the actions."""
    key_list = []
    for y, (action, value) in enumerate(input_map.items()):
        surf = FONT.render('{}: {}'.format(action, pg.key.name(value)), True, GREEN)
        rect = surf.get_rect(topleft=(40, y*40+20))
        key_list.append([surf, rect, action])
    return key_list


def assignment_menu(input_map):
    """Allow the user to change the key assignments in this menu.

    The user can click on an action-key pair to select it and has to press
    a keyboard key to assign it to the action in the `input_map` dict.
    """
    selected_action = None
    key_list = create_key_list(input_map)
    while True:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
                sys.exit()
            elif event.type == pg.KEYDOWN:
                if selected_action is not None:
                    # Assign the pygame key to the action in the input_map dict.
                    input_map[selected_action] = event.key
                    selected_action = None
                    # Need to re-render the surfaces.
                    key_list = create_key_list(input_map)
                if event.key == pg.K_ESCAPE:  # Leave the menu.
                    # Return the updated input_map dict to the main function.
                    return input_map
            elif event.type == pg.MOUSEBUTTONDOWN:
                selected_action = None
                for surf, rect, action in key_list:
                    # See if the user clicked on one of the rects.
                    if rect.collidepoint(event.pos):
                        selected_action = action

        screen.fill(BG_COLOR)
        # Blit the action-key table. Draw a rect around the
        # selected action.
        for surf, rect, action in key_list:
            screen.blit(surf, rect)
            if selected_action == action:
                pg.draw.rect(screen, GREEN, rect, 2)

        pg.display.flip()
        clock.tick(30)


def main():
    player = pg.Rect(300, 220, 40, 40)
    # This dict maps actions to the corresponding key scancodes.
    input_map = {'move right': pg.K_d, 'move left': pg.K_a}

    done = False
    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:  # Enter the key assignment menu.
                    input_map = assignment_menu(input_map)

        pressed_keys = pg.key.get_pressed()
        if pressed_keys[input_map['move right']]:
            player.x += 3
        elif pressed_keys[input_map['move left']]:
            player.x -= 3

        screen.fill(BG_COLOR)
        pg.draw.rect(screen, GREEN, player)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    main()
    pg.quit()

一个普适的解决方案,供未来遇到此问题的人参考。 - skrx
实际上我会使用像 这个 这样的状态机来实现不同的场景和菜单,但为了简单起见,我只是编写了 assignment_menu 函数及其自己的 while 和事件循环。 - skrx

2

当你获取到事件 KEYDOWN 时,你已经按下了键盘上的键,该键的信息存储在 event.key 中。

while not Fin:
    for event in pygame.event.get():
        if event.type == pygame.KEYDOWN
            MoveUp = event.key

顺便提一句:每个事件都可能有不同的字段。您可以在文档中的黄色列表中查看所有内容:event


太好了,谢谢你,我在网上找了两个多小时。 - cdd

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接