在KeyDown事件后删除延迟?

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

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

当我按下向下箭头时,玩家立即移动一步,然后暂停一小段时间,然后再开始平稳移动。 这是为什么? 我该怎样预防呢?

不幸的是, 提议的副本中的答案是不正确的。 它不会忽略重复的KeyDown事件,因此将逐渐增加每个键案例处理方向上的“delta”值。 它也不会立即响应按键(即直到第一个计时器滴答时才会发生动作)。

对于角色运动持有箭头键的答案C#.Net ISSUES解释了如何忽略后续的KeyDown事件,但没有解释你的角色将如何移动。

换句话说,我找不到真正正确回答您问题的重复问题。 所以…

你想要做的基本技术是:

  1. 不要移动实际的键输入。 相反,生成您自己的移动对象的时序逻辑。
  2. 不使用KeyDown事件来实际移动对象,而是使用它来设置移动方向,然后由定时逻辑处理。

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

 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 ms的间隔引发。 来回会有一些变化。 但它足够接近基本游戏。

如果你需要更高的精度,你将不得不在某处实现自己的状态轮询和动画循环。 这是另一个球。 🙂

一种主观的优雅方法:

 public partial class Form1 : Form { private static Timer timer; private static bool[] keys_down; private static Keys[] key_props; private void Form1_Load(object sender, EventArgs e) { keys_down = new bool[4]; key_props = new []{Keys.A, Keys.D, Keys.W, Keys.S}; timer = new Timer(); timer.Interval = 15; // Roughly 67 FPS timer.Tick += tick; timer.Start(); KeyDown += key_down_event; KeyUp += key_up_event; ... // More things to do when the form loads. } private void tick(Object source, EventArgs e) { ... // Do this every timing interval. byte n = 0; foreach (var v in keys_down) { if (n == 3 && v) ... // If the "s" key is being held down, no key delay issues. :) n++; } ... } private void key_down_event(object sender, KeyEventArgs e) { byte n = 0; foreach (var v in keys_down) { if (e.KeyCode == key_props[n]) keys_down[n] = true; n++; } } private void key_up_event(object sender, KeyEventArgs e) { byte n = 0; foreach (var v in keys_down) { if (e.KeyCode == key_props[n]) keys_down[n] = false; n++; } } public Form1() { InitializeComponent(); } }