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, если cell — это клетка головы или клетка сегмента хвоста.
  2. В 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);
    }
}
quiz iconПроверьте себя

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

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