Console.KeyAvailable 为真,但 Console.In.Peek() 停止
Console.KeyAvailable is true, but Console.In.Peek() stalls
我正在制作贪吃蛇游戏。一切正常,但如果您按下按钮的速度太快,则会出现不幸的行为。在我开始解决这个问题之前,代码在每次循环迭代中处理一次按键,如果您连续多次按下一个键,则需要多次循环才能改变方向。
我最初的改变是读取自上次游戏循环以来按下的所有键,并且只应用最后一个。这行得通,但实际上,如果我按下两个键,我希望它们都被应用。我不希望因为我按了 3 次右键而卡在右键上。
所以我的下一个方法是查看下一个输入的字符,看看它是否与上一个相同。如果是,请从流中读取它,然后重试。
我的理解是Console.KeyAvailable
returnstrue
如果输入流中有未读数据,Console.In.Peek()
returns第一个字符输入流中的数据,否则挂起直到那里有数据。
这是我当前的代码:
private static void UpdateDirection()
{
ConsoleKey key = ConsoleKey.Escape; // dummy key
Dir curDir = s_snakeDir;
lock (s_consoleLock)
{
if (Console.KeyAvailable)
{
key = Console.ReadKey(true).Key;
// ignore multiple key presses of the same direction
while (Console.KeyAvailable)
{
int next = Console.In.Peek();
if (next != (int)key)
{
break;
}
// read and ignore next character
Console.ReadKey(true);
}
}
switch (key)
{
// do stuff...
}
}
}
如果我在同一个循环中按下两个键,游戏就会停止。发生了什么(据我所知)是到达 int next = Console.In.Peek();
并等待下一个字符。
我不明白的是为什么Console.In.Peek()
需要等待。如果 Console.KeyAvailable
为真,那么 Console.In
的流中应该有一个字符。
编辑
我相信我已经解决了这个问题。 Console.In.Peek()
正在寻找字符,而不是按键,并且箭头按钮没有与之关联的字符。所以我的下一个问题是如何做我想做的事。
不使用 Console.ReadKey() 没有任何意义。你只对控制蛇的按键位置感兴趣,而不是它们产生什么字母。例如,WASD 是 ZQSD in France。你可以使用光标键,你不能用 Console.Read()
我也做了一个贪吃蛇多人游戏(源代码here),我遇到了完全同样的问题:
如果有人按下一个键一段时间然后方向设置非常延迟...
我用 keyBuffer 和 keyCheck 线程解决了这个问题:
List<ConsoleKeyInfo> keyBuffer = new List<ConsoleKeyInfo>();
new Thread(() =>
{
while(true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (keyBuffer.Count > 0)
{
if (keyBuffer[keyBuffer.Count - 1] != key)
keyBuffer.Add(key);
}
else
keyBuffer.Add(key);
}
Thread.Sleep(1);
}
}).Start();
while(true)
{
if (keyBuffer.Count>0)
{
switch (keyBuffer[0].Key)
{
//SwitchSomeStuff
}
keyBuffer.RemoveAt(0);
}
//PlayGame
}
我正在制作贪吃蛇游戏。一切正常,但如果您按下按钮的速度太快,则会出现不幸的行为。在我开始解决这个问题之前,代码在每次循环迭代中处理一次按键,如果您连续多次按下一个键,则需要多次循环才能改变方向。
我最初的改变是读取自上次游戏循环以来按下的所有键,并且只应用最后一个。这行得通,但实际上,如果我按下两个键,我希望它们都被应用。我不希望因为我按了 3 次右键而卡在右键上。
所以我的下一个方法是查看下一个输入的字符,看看它是否与上一个相同。如果是,请从流中读取它,然后重试。
我的理解是Console.KeyAvailable
returnstrue
如果输入流中有未读数据,Console.In.Peek()
returns第一个字符输入流中的数据,否则挂起直到那里有数据。
这是我当前的代码:
private static void UpdateDirection()
{
ConsoleKey key = ConsoleKey.Escape; // dummy key
Dir curDir = s_snakeDir;
lock (s_consoleLock)
{
if (Console.KeyAvailable)
{
key = Console.ReadKey(true).Key;
// ignore multiple key presses of the same direction
while (Console.KeyAvailable)
{
int next = Console.In.Peek();
if (next != (int)key)
{
break;
}
// read and ignore next character
Console.ReadKey(true);
}
}
switch (key)
{
// do stuff...
}
}
}
如果我在同一个循环中按下两个键,游戏就会停止。发生了什么(据我所知)是到达 int next = Console.In.Peek();
并等待下一个字符。
我不明白的是为什么Console.In.Peek()
需要等待。如果 Console.KeyAvailable
为真,那么 Console.In
的流中应该有一个字符。
编辑
我相信我已经解决了这个问题。 Console.In.Peek()
正在寻找字符,而不是按键,并且箭头按钮没有与之关联的字符。所以我的下一个问题是如何做我想做的事。
不使用 Console.ReadKey() 没有任何意义。你只对控制蛇的按键位置感兴趣,而不是它们产生什么字母。例如,WASD 是 ZQSD in France。你可以使用光标键,你不能用 Console.Read()
我也做了一个贪吃蛇多人游戏(源代码here),我遇到了完全同样的问题: 如果有人按下一个键一段时间然后方向设置非常延迟...
我用 keyBuffer 和 keyCheck 线程解决了这个问题:
List<ConsoleKeyInfo> keyBuffer = new List<ConsoleKeyInfo>();
new Thread(() =>
{
while(true)
{
if (Console.KeyAvailable)
{
ConsoleKeyInfo key = Console.ReadKey(true);
if (keyBuffer.Count > 0)
{
if (keyBuffer[keyBuffer.Count - 1] != key)
keyBuffer.Add(key);
}
else
keyBuffer.Add(key);
}
Thread.Sleep(1);
}
}).Start();
while(true)
{
if (keyBuffer.Count>0)
{
switch (keyBuffer[0].Key)
{
//SwitchSomeStuff
}
keyBuffer.RemoveAt(0);
}
//PlayGame
}