Не на змее
Урок 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, еслиcell— это клетка головы или клетка сегмента хвоста. - В
GameManagerдобавьusing System.Collections.Generic;и перепишиMoveFood(): перебирай x и z для каждой клетки игрового поля, добавляй вList<Vector3> freeкаждую клетку, которую не занимает змейка, и размещай еду в случайной клетке из этого списка.
Нажми Play, затем нажми Check. Проверки заполняют большую часть поля змейкой и убеждаются, что еда по-прежнему находит свободные клетки.
Попробуйте сами
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);
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.