本文介绍了消除 KeyDown 事件后的延迟?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在游戏中按住一个键来移动我的玩家时:

When I hold a key in my game to move my player:

public void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Up)
    {
        Player.MoveUp();
    }
}

我按下向下箭头后,玩家立即移动一步,然后暂停一小段时间,然后再次开始平滑移动.这是为什么?我该如何预防?

The player instantly moves one step as soon as I press the down arrow, and then pauses for a short duration before starting to smoothly move again. Why's this? How can I prevent it?

推荐答案

建议的重复 不正确.它不会忽略重复的 KeyDown 事件,因此会在每个关键案例处理的方向上逐渐增加delta"值.它也不会立即响应按键(即在第一个计时器滴答之前不会发生任何动作).

The answer in the proposed duplicate is incorrect, unfortunately. It doesn't ignore repeated KeyDown events, and so will gradually increase the "delta" value in the direction being handled by each key case. It also doesn't respond to the keypress immediately (i.e. no action happens until the first timer tick).

这个对按住箭头键进行字符移动 C# .Net 问题 的回答解释了如何忽略后续的 KeyDown 事件,但没有解释你的角色将如何移动.

This answer to Holding Arrow Keys Down For Character Movement C# .Net ISSUES explains how to ignore the subsequent KeyDown events, but doesn't explain how then your character would move.

换句话说,我找不到实际上正确回答您的问题的重复问题.所以…

In other words, I couldn't find a duplicate question that actually correctly answers your question. So…

你想做的基本技术是:

  1. 不要继续实际的按键输入.相反,生成您自己的计时逻辑来移动对象.
  2. 不是使用 KeyDown 事件来实际移动对象,而是使用它来设置移动方向,然后由您的计时逻辑处理.
  1. Don't move on the actual key input. Instead, generate your own timing logic that will move the object.
  2. Instead of using the KeyDown event to actually move the object, use it to set a movement direction, which is then processed by your timing logic.

有多种方法可以实现这一点.一个版本看起来像这样:

There are a variety of ways to accomplish this. One version would look like this:

private bool _moveUp;
private bool _moveDown;
private bool _moveLeft;
private bool _moveRight;

// You can add the Timer in the Winforms Designer instead if you like;
// The Interval property can be configured there at the same time, along
// with the Tick event handler, simplifying the non-Designer code here.
private System.Windows.Forms.Timer _movementTimer = new Timer { Interval = 100 };

public MainForm()
{
    InitializeComponent();

    _movementTimer.Tick += movementTimer_Tick;
}

private void movementTimer_Tick(object sender, EventArgs e)
{
    _DoMovement();
}

private void _DoMovement()
{
    if (_moveLeft) Player.MoveLeft();
    if (_moveRight) Player.MoveRight();
    if (_moveUp) Player.MoveUp();
    if (_moveDown) Player.MoveDown();
}

// You could of course override the OnKeyDown() method instead,
// assuming the handler is in the Form subclass generating the
// the event.
public void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    if (e.IsRepeat)
    {
        // Ignore key repeats...let the timer handle that
        return;
    }

    switch (e.KeyCode)
    {
    case Keys.Up:
        _moveUp = true;
        break;
    case Keys.Down:
        _moveDown = true;
        break;
    case Keys.Left:
        _moveLeft = true;
        break;
    case Keys.Right:
        _moveRight = true;
        break;
    }

    _DoMovement();
    _movementTimer.Start();
}

public void MainForm_KeyUp(object sender, KeyEventArgs e)
{
    switch (e.KeyCode)
    {
    case Keys.Up:
        _moveUp = false;
        break;
    case Keys.Down:
        _moveDown = false;
        break;
    case Keys.Left:
        _moveLeft = false;
        break;
    case Keys.Right:
        _moveRight = false;
        break;
    }

    if (!(_moveUp || _moveDown || _moveLeft || _moveRight))
    {
        _movementTimer.Stop();
    }
}

请注意,.NET 中的计时器对象具有有限的分辨率.我在上面显示了 100 毫秒(每秒 10 次)的间隔(与其他问题的答案相同),这与您可靠地获得的更新频率差不多.即便如此,计时器的 Tick 事件可能不会(也可能不会)以 恰好 100 毫秒的间隔引发.前后会有一些变化.但是对于基本游戏来说已经足够接近了.

Do note that the timer objects in .NET have limited resolution. I show an interval of 100 ms (10 times per second) above (same as in the other question's answer), and this is about as frequent an update as you're going to reliably get. Even then, the timer's Tick event may not (and probably won't) be raised on exactly 100 ms intervals. There will be some variation back and forth. But it will be close enough for a basic game.

如果您需要更高的精度,则必须在某处实现自己的状态轮询和动画循环.那是另外一种蜡球.:)

If you need more precision than that, you will have to implement your own state-polling-and-animation loop somewhere. That's a whole other ball o' wax. :)

这篇关于消除 KeyDown 事件后的延迟?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-31 10:17