来自键盘C#WPF的多输入

来自键盘C#WPF的多输入,c#,.net,wpf,keyboard-events,C#,.net,Wpf,Keyboard Events,我正在用WPF写一个俄罗斯方块克隆。如果我按住向右箭头键,当前工件将向右移动。对于可玩性,我希望允许用户按下另一个键(即F键)并旋转移动部件,而无需先松开右箭头键。目前,当我这样做时,工件停止移动 我的第一次基本尝试是与 Window_PreviewKeyDown(object sender, KeyEventArgs e) 然后向控制器层发送消息 我如何构造我的输入侦听代码以允许这样做 “我的当前代码”Windows将仅为您最后按下的一个键重复事件。此外,先重复按键之前的延迟以及重复按键的速

我正在用WPF写一个俄罗斯方块克隆。如果我按住向右箭头键,当前工件将向右移动。对于可玩性,我希望允许用户按下另一个键(即F键)并旋转移动部件,而无需先松开右箭头键。目前,当我这样做时,工件停止移动

我的第一次基本尝试是与

Window_PreviewKeyDown(object sender, KeyEventArgs e)
然后向控制器层发送消息

我如何构造我的输入侦听代码以允许这样做


“我的当前代码”

Windows将仅为您最后按下的一个键重复事件。此外,先重复按键之前的延迟以及重复按键的速率取决于通常针对打字而非游戏进行优化的设置。因此,对于游戏,最好完全忽略它们,并用自己的方式实现“重复”键

基本上,您必须保持感兴趣的键的状态(按下或释放),并在收到KeyDown或KeyUp事件时更改它们。然后,在某种计时器中,您必须检查在该时刻关闭的每个键的状态和触发事件。如果计时器发生在控制器层或UI中,则取决于您的体系结构
:-)


您可以添加额外的检查,例如当左键和右键同时按下时,忽略这两个键,否则工件将重复左键和右键跳转。

也应该存在一个KeyUp事件,通过同时使用KeyDown和KeyUp,您可以达到您想要的效果。有几种方法可以做到这一点

一种是让KeyDown事件启动一个重复操作,然后让keydup取消它

另一种方法是存储是否按下了某些键。保留一个键列表,并在“向下键”和“向上键”上分别打开和关闭键。在游戏主循环中,您将触发与当前按下的所有键对应的事件

例如:

bool[] heldDown = new bool[256]; // One index for the keycode of each key

void Window_PreviewKeyDown(object sender, KeyEventArgs e) {
    heldDown[e.KeyCode] = true;
}    
void Window_PreviewKeyUp(object sender, KeyEventArgs e) {
    heldDown[e.KeyCode] = false;
}    
然后在主循环中执行“heldDown”,并对按下的每个有意义的键触发事件:

if (heldDown[Key.F])
    MainController.TriggerPieceEvent(Constants.PieceEvents.RotateClockwise);
if (heldDown[Key.Left])
    MainController.TriggerPieceEvent(Constants.PieceEvents.ShiftLeft);
// etc...

你需要国家。创建一些变量,如“RightArrowPressed”和“RotateButtonPressed”

在按键向下检查键是否按下,如果按下,则将相应变量设置为true

在key_up中,执行相同的操作,但将其设置为false


现在,您可以随时查看这两个变量,并查看按下了哪个键。

您依靠自动重复键来保持工件移动。这是不合适的,用户的键盘重复延迟是可变的,会影响游戏的可玩性。正如您所发现的,当按下另一个键时,它会停止自动重复

通过将每个游戏对象指定为运动状态来修复此问题。使用KeyDown事件对其进行更改。如果运动状态值仍然与关键点匹配,则使用KeyUp事件将其重置。在游戏循环中,根据游戏对象的运动状态更新游戏对象的位置。你会以固定的速率这样做,由计时器触发

运动状态也应指示“下降”。你现在可以简单地通过降低计时器的速度使游戏变得更加困难。碎片落得更快。而且键盘的响应能力更强,用户仍有机会赢得一个关卡