Не на змее
Урок 9 из 14 курса Игра на Unity: 3D-змейка на Coddy.
MoveFood() выбирает любую клетку, в том числе клетки, которые занимает змейка. Еду под змейкой нельзя съесть, пока змейка не отползёт с неё, и чем длиннее змейка, тем чаще это происходит.
Один способ исправить это — выбирать заново, пока не найдётся свободная клетка. На пустом поле это работает, но по мере заполнения поля требуется всё больше попыток, а когда свободных клеток не остаётся, цикл никогда не завершится. Надёжное решение — сначала составить список свободных клеток и выбрать одну из них: вероятность выбора каждой свободной клетки одинакова, и всегда достаточно одной попытки. В кинотеатре поступают так же, когда сажают опоздавшего зрителя:
List<int> free = new List<int>();
for (int seat = 1; seat <= 40; seat++)
{
if (!taken.Contains(seat)) free.Add(seat);
}
int pick = free[Random.Range(0, free.Count)];Random.Range(0, free.Count) возвращает индекс от 0 до последнего, поскольку верхняя граница не включается. Чтобы составить список, поле спрашивает у змейки, занимает ли она клетку: для этого нужен метод в Snake, который проверяет голову и каждый сегмент.
Задание
СреднеЕда никогда не появляется на змее.
- В
Snakeнапишиpublic bool Occupies(Vector3 cell): возвращает true, если ячейку занимает голова или любой сегмент хвоста. - В
MoveFood()классаGameManagerперебирай значения x и z от-snake.edgeдоsnake.edge, добавляй каждую ячейку, для которой выполняется условие!snake.Occupies(cell), вList<Vector3> free, а затем размещай еду в ячейкеfree[Random.Range(0, free.Count)].
Нажми «Играть» и вырасти: еда всегда появляется на пустой ячейке. Затем нажми «Проверить».
Попробуйте сами
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager Instance;
public Snake snake;
public GameObject foodPrefab;
private Transform food;
private int score;
void Awake()
{
Instance = this;
}
void Start()
{
food = Instantiate(foodPrefab).transform;
MoveFood();
}
public bool IsFood(Vector3 cell)
{
return cell == food.position;
}
public void Eat()
{
score++;
MoveFood();
}
void MoveFood()
{
int x = Random.Range(-snake.edge, snake.edge + 1);
int z = Random.Range(-snake.edge, snake.edge + 1);
food.position = new Vector3(x, 0f, z);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Игра на Unity: 3D-змейка
Потренируйтесь самостоятельно: Песочница Unity