2

我正在 WPF 中编写俄罗斯方块克隆。如果我按住右箭头键,则当前片段向右移动。为了可玩性,我想让用户按下另一个键(即 F 键)并旋转移动块,而不必先松开右箭头键。目前,当我这样做时,这件作品停止移动。

我在这方面的第一个基本尝试是挂钩

Window_PreviewKeyDown(object sender, KeyEventArgs e)

然后向控制器层发送消息。

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

我当前的代码在这里

4

4 回答 4

3

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

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

运动状态还应指示“跌倒”。您现在可以通过降低计时器速率来简单地使游戏随着关卡的进展而变得更加困难。碎片落得更快。键盘变得更加灵敏,让用户仍有机会赢得关卡。

于 2010-04-06T15:39:11.183 回答
2

还应该存在一个 KeyUp 事件,并且通过同时使用 KeyDown 和 KeyUp 您可以实现您正在寻找的效果。可以通过几种方式完成。

一种方法是让您的 KeyDown 事件启动重复操作并让 KeyUp 取消它。

另一个是存储某些键是否被按住。保留一个键列表,并在 KeyDown 时打开它们,在 KeyUp 时关闭它们。在游戏主循环中,您将触发与当前按下的所有键对应的事件。

一个例子:

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...
于 2010-04-06T15:24:33.673 回答
1

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

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

您可以添加额外的检查,例如当左右键都按下时忽略两者,否则该片段将反复左右跳跃。

于 2010-04-06T15:21:58.507 回答
1

你需要状态。创建一些变量,例如“RightArrowPressed”和“RotateButtonPressed”

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

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

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

于 2010-04-06T15:24:43.927 回答