如何将箭头键分配给 C# 中的按钮?

How to assign an arrow key to a button in C#?

现在我正在制作游戏和其中的角色来移动玩家。我只是编程的初学者。

一共有8个按钮,每个按钮指向一个方向。例如,这是我的

程序
private void btnUp_Click(object sender, EventArgs e)
{
    //move up
    y = y - 1;
    MovePlayer();
    UpdateLabelLocation();
}
public void MovePlayer()
{
    picPlayer.Location = new Point(x, y);
}

public void UpdateLabelLocation()
{
    lblLocation.Text = "Location: (" + x + ", " + y + ")";
}

我想让它在按上下左右键时移动。另外,如果可能的话,我想这样做,当我同时按下右上和上时,它会触发这个:

private void btnRightUp_Click(object sender, EventArgs e)
{
    //move player
    y = y - 1;
    x = x + 1;
    MovePlayer();
    UpdateLabelLocation();
}

感谢您的帮助。

您实际上是在创建自己的简单游戏引擎。正如评论员所指出的,您最好使用现有的游戏引擎,例如 Unity。它比使用 WinForms 更容易、更自由。

就是说,如果您真的想继续这样做,我强烈建议您将 Click 处理程序中的代码移动到一个方法中。这减少了代码重复。即

private void DownButton_Click(...)
{
    MovePlayer(0, 1);
}

private void UpButton_Click(...)
{
    MovePlayer(0, -1);
}

public void MovePlayer(float xStep, float yStep)
{
    x += xStep;
    y += yStep;
    MovePlayer();
    UpdateLabelLocation();
}

要向下和向左移动,您需要调用 MovePlayer(-1, 1);

要向上和向右移动,您需要调用 MovePlayer(1, -1);

接下来您需要响应 KeyPress 事件。即

public void Form_KeyPress(object sender, KeyPressEventArgs args)
{
    switch (args.KeyChar) {
        case 'a': // Left
            args.Handled = true;
            MovePlayer(-1, 0);
            break;
        case 'd': // Right
            args.Handled = true;
            MovePlayer(1, 0);
            break;
        case 'w': // Up
            args.Handled = true;
            MovePlayer(0, -1);
            break;
        case 's': // Down
            args.Handled = true;
            MovePlayer(0, 1);
            break;
    }
}

请注意,如果您有另一个接受键盘输入的控件(例如 TextBox),它将拦截按键。要解决此问题,请使用 KeyPreview 强制 window 先预览输入。 args.Handled = true 防止事件在您的代码之后路由到子控件。

不幸的是,WinForms 不记录同时按下的多个键,因此单独使用 KeyPress 不足以处理角移动。您可以通过连接到 KeyDown and KeyUp 来解决这个问题,但这比它的价值更麻烦。

这是一个更强大的解决方案。请记住以下内容不是线程安全的,因此如果您计划引入其他线程,则需要使用适当的锁定。

HashSet<KeyCode> state = new HashSet<KeyCode>();
float speed = 120; // 120 pixels/second.

private void Form_KeyDown(object sender, KeyEventArgs args)
{
    var key = args.KeyCode;
    state.Add(key);

    // Fire pressed when a key was up.
    if (!state.Contains(key)) {
        state.Add(key);
        OnKeyPressed(key);
    }
}

private void Form_KeyUp(object sender, KeyEventArgs args)
{
    var key = args.KeyCode;
    state.Remove(key);

    // Fire release when a key was down.
    if (state.Contains(key)) {
        state.Remove(key);
        OnKeyReleased(key);
    }
}

// Runs when key was up, but pressed just now.
private void OnKeyPressed(KeyCode key)
{
    // Trigger key-based actions.
}

// Runs when key was down, but released just now.
private void OnReleased(KeyCode key)
{
    // Trigger key-based actions, but on release instead of press.
}

private bool IsDown(KeyCode key)
{
    return state.Contains(key);
}

// Trigger this periodically, at least 20 times a second(ideally 60).
// An option to get you started is to use a windows timer, but 
// eventually you'll want to use high precision timing instead.
private void Update()
{
    var deltaTime = // Calculate the seconds that have passed since the last update. 
    // Describing it is out of the scope of this answer, but see the links below.

    // Determine horizontal direction. Holding both 
    // A & D down cancels movement on the x-axis.
    var directionX = 0;
    if (IsDown(KeyCode.A)) {
        directionX--;
    }
    if (IsDown(KeyCode.D)) {
        directionX++;
    }

    // Determine vertical direction. Holding both 
    // W & S down cancels movement on the y-axis.
    var directionY = 0;
    if (IsDown(KeyCode.W)) {
        directionY--;
    }
    if (IsDown(KeyCode.S)) {
        directionY++;
    }

    // directionX & directionY should be normalized, but 
    // I leave that as an exercise for the reader.
    var movement = speed * deltaTime;
    var offsetX = directionX * movement;
    var offsetY = directionY * movement;
    MovePlayer(offsetX, offsetY);
}

如您所见,涉及的内容很多。如果您想要更精细的时间安排,请查看 this article. Eventually you'll want to transition to a game loop,但这是本答案范围之外的另一个主题。