【问题标题】:Snake Program stops running without exception蛇程序无异常停止运行
【发布时间】:2018-12-21 21:52:48
【问题描述】:

我正在尝试在控制台中对蛇进行编程。蛇随机走几步后,会生成一个新的游戏对象(例如,使蛇生长的苹果或使蛇更快的蘑菇)。

我创建了一个随机游戏对象(在随机(左,上)坐标上,然后我需要检查该游戏对象是在一个蛇形主体上还是另一个游戏对象上产生。如果是这样,我创建一个新游戏对象然后再试一次。只有当它不与另一个游戏对象或蛇碰撞时,它才会生成。

snakeElemnts = 一个列表,其中包含所有蛇的身体部位; gameObjects = 包含所有现有游戏对象的列表;

如果 noCollisionAmount ==snakeElements 和 GameObjects 的数量,则应该没有碰撞并且应该生成新的 GameObject。

不幸的是,在某一时刻(早期),蛇只是停止移动,什么都没有发生(没有例外或任何事情)。

我无法调试,因为我有一个 KeyboardWatcher 正在运行,它会检查某个键是否被按下。因此当我按下break时,我只能检查keyboardwatcher。

设置断点没有用,因为问题出现时我从不中断。

if (this.randomStepNumber == 0)                
{
    int noCollision = 0; // this variable counts the amount of times there was no collision

    GameObject validGameObject;

          while (true)
          {
             validGameObject = this.snakeGameObjectFactory.Generate();

             foreach (SnakeElements element in snakeElements)
             {
                   if (validGameObject.XPosition != element.XPosition || validGameObject.YPosition != element.YPosition)
                    {
                      noCollision++;
                    }
                    else
                    {
                       break;
                    }
               }

              foreach (GameObject gameObject in gameObjects)
              {
                  if (noCollision == snakeElements.Count) // if there was no collision of the new gameobject with an element of the snake, the gameobjects will get checked
                  {
                       if (validGameObject.XPosition != gameObject.XPosition || validGameObject.YPosition != gameObject.YPosition)
                       {
                           noCollision++;
                       }
                       else
                       {
                           break;
                        }
                  }
                  else
                  {
                      break;
                   }
               }

               if (noCollision == snakeElements.Count + gameObjects.Count) // if there was no collision at all, the check is ended
               {
                   break;
               }
               else
               {
                  noCollision = 0;
               }
           }

       this.gameObjects.Add(validGameObject);

       this.randomStepNumber = this.random.Next(10, 30);
}

【问题讨论】:

  • 你是在大学写的吗?我
  • 是的,先生,您是对的
  • 常春藤技术课?
  • 我在奥地利的第一学期计算机科学,C#基础
  • 什么是if (randomStepNumber == 0)else 部分因为如果你添加一个游戏对象,你会生成一个新的随机步数,它在 10 到 30 之间,我假设显示的代码正在运行在其他循环中或在循环或事件中被调用的函数中。

标签: c# element gameobject


【解决方案1】:

根据您的 cmets 删除此代码块会导致问题停止,我认为稍微清理一下代码并使用 continue 语句删除潜在的无限循环可能会很好。利用一点 LINQ Enumerable.Any 和一个 do-while 循环,我们可以简化上述代码的逻辑。实际上不需要计算碰撞次数,因为代码的目的是创建一个新对象iff检测到碰撞。这意味着如果我们检测到与蛇的碰撞,那么我们想要生成一个新对象,或者如果我们检测到与另一个现有对象的碰撞,那么我们想要生成一个新对象。因此,我们不使用计数,而是使用Any 语句来检查是否与蛇或现有对象发生任何碰撞。如果有,则生成一个新对象。如果没有,则使用该对象并继续。注意:要使用Enumerable.Any,您需要为命名空间System.Linq 添加using 语句。

if (randomStepNumber == 0)                
{    
    GameObject validGameObject;
    do
    {
        validGameObject = snakeGameObjectFactory.Generate();
    }
    while(snakeElements.Any(s => validGameObject.XPosition == s.XPosition && validGameObject.YPosition == s.YPosition) ||
         gameObjects.Any(o => validGameObject.XPosition == o.XPosition && validGameObject.YPosition == o.YPosition));

    gameObjects.Add(validGameObject);
    randomStepNumber = random.Next(10, 30);
}

作为旁注。我删除了 this 关键字,因为它看起来您并没有在代码中的所有情况下使用它,如果您不必使用它,它会使代码更具可读性,因为它不那么罗嗦。如果由于变量冲突而需要重新添加它,那么我建议将变量重命名为具有相同名称的成员变量和局部变量在尝试调试时也会造成混淆。

附注 - 这是一个不使用 LINQ 的代码版本,以防您的家庭作业不允许这样做。

if (randomStepNumber == 0)                
{    
    GameObject validGameObject = null;
    while(validGameObject == null)
    {
        validGameObject = snakeGameObjectFactory.Generate();
        foreach(var snake in snakeElements)
        {
            if (validGameObject.XPosition == snake.XPosition &&
                validGameObject.YPosition == snake.YPosition)
            {
                validGameObject = null;
                break;
            }
        }

        if (validGameObject != null)
        {
            foreach(var gameObject in gameObjects)
            {
                if (validGameObject.XPosition == gameObject.XPosition &&
                    validGameObject.YPosition == gameObject.YPosition)
                {
                    validGameObject = null;
                    break;
                }
            }
        }
    }

    gameObjects.Add(validGameObject);
    randomStepNumber = random.Next(10, 30);
}

【讨论】:

  • 如果没有检测到蛇或其他游戏对象的碰撞,我想创建一个新的游戏对象。这就是我检查 Snake 和所有游戏对象的原因
  • 看起来不错。确保他知道如何包含 linq。诚然,他是一名新学生
  • @pstrjds 抱歉,我误读了您的评论!非常感谢您的回答,我会试试的
  • @JohnLord - 这就是我在答案开头添加文档链接的原因。如果不允许,我还添加了一个非 LINQ。仍然不确定这是否会解决问题,但至少可以清理代码。虽然现在也添加了关于添加 using 语句的注释:)
  • @pstrjds 您的第二个代码似乎可以正常工作!你真是个天才,有什么办法感谢你吗?
【解决方案2】:

我想你可能不明白“继续”是如何工作的。

  if (noCollision > snakeElements.Count + gameObjects.Count)
            {
                continue;
            }

你在 while 循环的开始就有了。如果发现为真,您将陷入无限循环。

其次,你有一个 While(true) 在那里永远不会让你保存一个有效的结果,因为它在循环之外。您应该将 while 替换为 do while 并在其末尾检查有效结果,如果发生冲突则循环。

【讨论】:

  • 我删除了那部分,问题仍然存在
  • @d0neall - 它仍然应该去。它绝对会导致无限循环。当您在循环内说continue 时,它会跳回循环顶部并忽略剩余的循环代码。在您的情况下,如果 this 的计算结果为 true,那么您将陷入无限循环。
  • 可能是第二期?如果您的代码在上面是最新的,我会再看看它
  • 代码是最新的,蛇仍然停止移动。如果我从程序中删除上面的所有代码,没有问题,但我需要碰撞检测。一定有某种无限循环,但我无法调试它。
  • 我不确定 while(true) 循环的目的是什么。您应该只在需要生成新位置时循环。有关详细信息,请参阅我编辑的答案
猜你喜欢
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-14
  • 2021-06-20
  • 2022-11-21
相关资源
最近更新 更多