【问题标题】:c# console snake gets stuck on long key pressc#控制台蛇卡在长按键上
【发布时间】:2013-06-03 20:17:20
【问题描述】:

几个月前我刚开始学习编程,并决定做一个控制台蛇游戏。一切都很好,期待一件事。

如果我的蛇向上移动并且我按下向下箭头并按住它,我的蛇会停止并在我停止按下按钮后保持停止状态。

如果我的蛇向右移动并且我按右箭头的时间过长,我会失去控制一段时间(但蛇不会停止),也会发生同样的事情。它发生在各个方面(左,右,上,下)。

我尝试将 cki 与另一个 ConsoleKeyInfo 进行比较,但它们之间存在轻微延迟,但这没关系。如果我按住这个键,我的程序就会停留在那个位置并更新一个键。 (至少我认为这就是问题所在)

这是 Console.ReadKey 的“功能”还是有什么方法可以解决这个问题?

请记住,我刚刚开始,所以我还不知道高级的东西。

只要我不按住按键超过 1 秒,一切都会完美无缺。

   public void LiikutaMato() //movesnake
    {

        if (Console.KeyAvailable)
        {
                ConsoleKeyInfo cki;
                cki = Console.ReadKey(true); // <-- I believe this is where it gets stuck 

    }

【问题讨论】:

  • 轮询率正在堆积 readkey 上的输入,您最终不得不等待它清除堆栈,然后才能接受任何新内容......只是猜测
  • 当您按下并保持按下状态时,系统将(我认为)开始向控制台发送许多按键事件。如果您最终因这些原因而阻塞(例如,您的计算或控制台重绘所花费的时间比每次发送按键之间的时间要长)或使蛇停止(例如,因为您没有在按键的那一刻移动蛇按下以正常改变方向),这可能会导致您的问题。
  • 提个建议……将这样的游戏编写为控制台应用程序有点矫枉过正,而且有点“变通办法”。您可能希望进一步磨练您的一般编码技能,并且由于您将使用 C#,因此请学习 XNA。
  • @Renan 我会说学习 MonoGame,因为 XNA 是 pretty much dead,除非您采取一些变通办法,否则 VS2012 甚至不可用。
  • 您可能想使用不同的方法来读取键盘状态。例如:stackoverflow.com/questions/4351258/…

标签: c# console console.readkey


【解决方案1】:

玩这个...它使用紧密循环来消耗按键,直到设置的延迟到期。您也不必按住键来保持蛇移动。它对我的系统非常敏感:

class Program
{

    public enum Direction
    {
        Up, 
        Down, 
        Right, 
        Left
    }

    static void Main(string[] args)
    {
        const int delay = 75;
        string snake = "O";
        char border = 'X';

        int x, y;
        int length;
        bool crashed = false;
        Direction curDirection = Direction.Up;
        Dictionary<string, bool> eaten = new Dictionary<string, bool>();
        Console.CursorVisible = false;

        ConsoleKeyInfo cki;
        bool quit = false;
        while (!quit)
        {
            Console.Clear();
            Console.Title = "Use 'a', 's', 'd' and 'w' to steer.  Hit 'q' to quit.";

            // draw border around the console:
            string row = new String(border, Console.WindowWidth);
            Console.SetCursorPosition(0, 0);
            Console.Write(row);
            Console.SetCursorPosition(0, Console.WindowHeight - 2);
            Console.Write(row);
            for (int borderY = 0; borderY < Console.WindowHeight - 2; borderY++)
            {
                Console.SetCursorPosition(0, borderY);
                Console.Write(border.ToString());
                Console.SetCursorPosition(Console.WindowWidth - 1, borderY);
                Console.Write(border.ToString());
            }

            // reset all game variables:
            length = 1;
            crashed = false;
            curDirection = Direction.Up;
            eaten.Clear();
            x = Console.WindowWidth / 2;
            y = Console.WindowHeight / 2;
            eaten.Add(x.ToString("00") + y.ToString("00"), true);

            // draw new snake:
            Console.SetCursorPosition(x, y);
            Console.Write(snake);

            // wait for initial keypress:
            while (!Console.KeyAvailable)
            {
                System.Threading.Thread.Sleep(10);
            }

            // see if intitial direction should be changed:
            cki = Console.ReadKey(true);
            switch (cki.KeyChar)
            {
                case 'w':
                    curDirection = Direction.Up;
                    break;

                case 's':
                    curDirection = Direction.Down;
                    break;

                case 'a':
                    curDirection = Direction.Left;
                    break;

                case 'd':
                    curDirection = Direction.Right;
                    break;

                case 'q':
                    quit = true;
                    break;
            }

            // main game loop:
            DateTime nextCheck = DateTime.Now.AddMilliseconds(delay);
            while (!quit && !crashed)
            {
                Console.Title = "Length: " + length.ToString();

                // consume keystrokes and change current direction until the delay has expired:
                // *The snake won't actually move until after the delay!
                while (nextCheck > DateTime.Now)
                {
                    if (Console.KeyAvailable)
                    {
                        cki = Console.ReadKey(true);
                        switch (cki.KeyChar)
                        {
                            case 'w':
                                curDirection = Direction.Up;
                                break;

                            case 's':
                                curDirection = Direction.Down;
                                break;

                            case 'a':
                                curDirection = Direction.Left;
                                break;

                            case 'd':
                                curDirection = Direction.Right;
                                break;

                            case 'q':
                                quit = true;
                                break;
                        }
                    }
                }

                // if the user didn't quit, attempt to move without hitting the border:
                if (!quit)
                {
                    string key = "";
                    switch (curDirection)
                    {
                        case Direction.Up:
                            if (y > 1)
                            {
                                y--;
                            }
                            else
                            {
                                crashed = true;
                            }
                            break;

                        case Direction.Down:
                            if (y < Console.WindowHeight - 3)
                            {
                                y++;
                            }
                            else
                            {
                                crashed = true;
                            }
                            break;

                        case Direction.Left:
                            if (x > 1)
                            {
                                x--;
                            }
                            else
                            {
                                crashed = true;
                            }

                            break;

                        case Direction.Right:
                            if (x < Console.WindowWidth - 2)
                            {
                                x++;
                            }
                            else
                            {
                                crashed = true;
                            }
                            break;
                    }

                    // if the user didn't hit the border, see if they hit the snake
                    if (!crashed)
                    {
                        key = x.ToString("00") + y.ToString("00");
                        if (!eaten.ContainsKey(key))
                        {
                            length++;
                            eaten.Add(key, true);
                            Console.SetCursorPosition(x, y);
                            Console.Write(snake);
                        }
                        else
                        {
                            crashed = true;
                        }
                    }

                    // set the next delay:
                    nextCheck = DateTime.Now.AddMilliseconds(delay);
                }
            } // end main game loop

            if (crashed)
            {
                Console.Title = "*** Crashed! *** Length: " + length.ToString() + "     Hit 'q' to quit, or 'r' to retry!";

                // wait for quit or retry:
                bool retry = false;
                while (!quit && !retry)
                {
                    if (Console.KeyAvailable)
                    {
                        cki = Console.ReadKey(true);
                        switch (cki.KeyChar)
                        {
                            case 'q':
                                quit = true;
                                break;

                            case 'r':
                                retry = true;
                                break;
                        }
                    }
                }
            } 

        } // end main program loop

    } // end Main()

}

【讨论】:

  • 谢谢 Idle_Mind。有效。我的问题是我同时更新了我的钥匙和我的蛇的长度。现在我首先检查 do while 循环中的键,并在计时器通过它之后,然后我修改我的蛇坐标。不再停下来,我的蛇一直以相同的速度移动。
  • 你怎么从来没有为一款很酷的小游戏获得过投票?
  • 不错的程序。只有两个cmets:我发现蛇总是从起点开始生长,这很奇怪,但我明白这是为了没有东西可抓而做出的权衡,这会使蛇变大。第二:如果你向后点击它不应该崩溃;它应该忽略该命令。如果我快速按两个键进行掉头,它会崩溃,因为它对第一个转弯没有反应。
  • 感谢@Andrew 的反馈。我会解决这些问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 2013-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多