Menu
CoddyTech

Не на змее

Урок 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, который проверяет голову и каждый сегмент.

challenge icon

Задание

Средне

Еда никогда не появляется на змее.

  1. В Snake напиши public bool Occupies(Vector3 cell): возвращает true, если ячейку занимает голова или любой сегмент хвоста.
  2. В 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);
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Игра на Unity: 3D-змейка

Потренируйтесь самостоятельно: Песочница Unity