Программа Snake перестает работать без исключения - PullRequest
0 голосов
/ 22 декабря 2018

Я пытаюсь запрограммировать змею в консоли.После случайного количества шагов, которые делает змея, появляется новый GameObject (например, яблоко, которое заставляет змею расти, или гриб, который ускоряет змею).

Я создаю случайный gameObject (случайно (слева,top) координаты, а затем мне нужно проверить, появляется ли этот gameObject поверх snakeBodyPart или поверх другого gameObject. Если это так, я создаю новый gameObject и пробую то же самое снова. Только если он не сталкивается сдругой gameObject или Snake, он будет появляться.

snakeElemnts = список, содержащий все части тела змеи; gameObjects = список со всеми существующими объектами gameObjects;

If noCollisionAmount == количество snakeElements и GameObjects, не должно быть столкновений, и новый GameObject должен появиться.

К сожалению, в какой-то момент (в начале) змея просто перестает двигаться и ничего не происходит (без исключений или чего-либо).

Я не могу отладить, потому что у меня работает 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);
}

Ответы [ 2 ]

0 голосов
/ 22 декабря 2018

Исходя из ваших комментариев о том, что удаление этого блока кода приводит к прекращению проблемы, я подумал, что, возможно, было бы неплохо немного очистить код и удалить этот потенциальный бесконечный цикл с помощью оператора continue.Используя маленький LINQ Enumerable.Any и цикл do-while, мы можем упростить логику приведенного выше кода.Нет необходимости в подсчете коллизий, поскольку целью кода является создание нового объекта , если , обнаружение коллизии.Это означает, что если мы обнаружим столкновение со змеей, то мы хотим создать новый объект или если мы обнаружим столкновение с другим существующим объектом, то мы хотим создать новый объект.Поэтому вместо подсчета мы используем оператор Any, чтобы проверить, нет ли столкновения со змеей или существующим объектом.Если есть, то сгенерируйте новый объект.Если нет, то используйте этот объект и продолжайте.Примечание. Чтобы использовать Enumerable.Any, вам необходимо добавить оператор using для пространства имен System.Linq.

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);
}
0 голосов
/ 22 декабря 2018

Я думаю, вы не понимаете, как работает «продолжить».

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

у вас это есть в начале цикла while.Если он найден верным, вы застрянете в бесконечном цикле.

во-вторых, у вас есть while (true), которое никогда не позволит вам сохранить действительный результат, поскольку он находится вне цикла.Вам следует заменить while на do while и проверить действительный результат в конце, а затем зациклить, если произошло столкновение.

...