Создание 2D змейки в Unity.

Создание 2D змейки в Unity.

Пример создания простой 2D игры змейка (так же известной как snake, slither) в среде Unity.

Дл начала создадим проект 2D. На сцене разместим три спрайта и подпишем Head, BodyPart, FoodItem.

Head - это наша голова, которой мы и будем управлять.
BodyPart - часть тела, которая будет добавляться по мере съедания Food. Так же с добавлением длинны тела, будем менять и скорость.

Если вышли за пределы экрана, респавним в начальной точке и отсекаем часть туловища.

Управление змейкой.

Создадим скрипт SnakeController. Добавим свойство

    List<GameObject> parts = new List<GameObject>();
    float currentRotation = 0.0f;

    public GameObject bodyPart;

    public float speed = .8f;
    public float speedRotation = 100.0f;

Массив parts будет содержать наше тело, включая голову. Текущий угол поворота будет в переменной currentRotation. В bodyPart будет префаб с частью туловища. speed и speedRotation будет отвечать за скорость перемещения и поворота соответственно.

В функции Start добавим себя (голову) в массив частей тела.

В функции Update напишем

        currentRotation -= Input.GetAxis("Horizontal") * speedRotation * Time.deltaTime;
        transform.rotation = Quaternion.Euler(0, 0, currentRotation);
        transform.Translate(Vector3.up * speed * Time.deltaTime);

То есть мы получаем от -1 до +1 значение поворота и умножаем его на время, прошедшее с прошлого обновления и на коэффициент скорости вращения. Для инверсии отнимаем от текущего угла.

Далее используем вспомогательную функцию Quaternion.Euler которая возвращает поворот на заданный угол вокруг каждой из осей. Так как нас интересует только вращения вокруг оси Z, X и Y можно передать 0.

И вызываем Translate для перемещения головы вперед с заданной скоростью с учетом угла поворота указанного выше.

Для управления головой этого уже достаточно.

Создадим еще один скрипт BodyPart.

    public GameObject parentObject;
    public SnakeController snakeController;

    void Update()
    {
        parentObject.transform.LookAt(parentObject.transform);
        transform.position = Vector3.Lerp(transform.position, parentObject.transform.position, Time.deltaTime * 3.0f * snakeController.speed);
    }

В свойстве parentObject будет объект за которым будет следовать данная часть тела змейки.

В функции Update с помощью функции LookAt задаем поворот в сторону объекта слежения, то есть предыдущего объекта. И перемещаем наш объект с помощью функции Lerp. Это линейная интерполяция между двумя точками, позицией текущего объекта и объекта за которым движется текущий объект.

То есть движется голова, за ней первый объект BodyPart. Он поворачивается в сторону головы и сдвигается. Если третий параметр 1.0f будет возвращен второй параметр функции Lerp, то есть наш объект переместится в точку где находится голова. Если же передать 0.0f, будет возвращена позиция текущего объекта и он останется на месте.

snake body parts

Таким коэффициент 3.0f немного сожмет части тела змейки чтобы они не были слишком далеко. Умножение на скорость, даст еще большее прижатие с увеличением скорости. То есть чем больше частей, тем больше скорость, тем компактнее они будут.

snake body parts speed

Еда для змейки

Добавим одноименный тег на объект FoodItem для определения еды. Добавим на объекты Head и BodyPart по Circle Collider 2D. Это нужно для определения пересечения головы и еды. При пересечении коллайдеров будет вызвана функция OnTriggerEnter2D. Но для этого необходимо еще повесить на объект Head компонент Rigidbody 2D. Без него триггер не сработает.

Rigidbody по умолчанию имеет массу и гравитацию, и будет падать вниз экрана, поэтому уберем гравитацию (Gravity Scale) в 0.

private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.tag.Equals("FoodItem"))
        {
            Destroy(collision.gameObject);
            GameObject parent = parts[parts.Count - 1];
            GameObject bodyPartObj = GameObject.Instantiate(bodyPart, parent.transform.position, Quaternion.identity) as GameObject;
            BodyPart bodyPartScript = bodyPartObj.GetComponent<BodyPart>();
            bodyPartScript.parentObject = parent;
            bodyPartScript.snakeController = GetComponent<SnakeController>();

            this.parts.Add(bodyPartObj);
            speed += 0.1f;
        }
    }

При столкновении проверяем ранее заданный тег для еды, если это еда, удаляем объект еды.

Достаем из нашего массива частей тела предыдущую часть, за которой будет следовать новая. И спавним BodyPart в месте где сейчас голова. Задаем нашей новой части тела объект за которым следовать. Так же передадим контроллер головы, для доступа к скорости (цель использования скорости описаны выше). Помещаем наш объект в массив частей тела змеи. И увеличиваем скорость движения змеи для большей сложности.

Добавим скрипт SnakeController на объект Head, а скрипт BodyPart на одноименный объект. Перетянем BodyPart в папку Assets тем самым создав префаб.

На объекте Head в скрипте в свойстве Body Part выберем созданный только что префаб.

Генератор еды для змейки

Создадим префаб FoodItem. В нем можно прописать вес еды и присвоение картинки. В репозитории вы найдете скрипт с заданием случайного спрайта нашему FoodItem.

Создадим скрипт FoodManager

    public GameObject foodItem;
    private float width = 8.0f;
    private float height = 4.0f;

    void Start()
    {
        for (int i = 0; i < 7; ++i)
        {
            Add();
        }
    }

    public void Add()
    {
        Vector3 pos = new Vector3(Random.Range(width * -1, width), Random.Range(height * -1, height), 0);
        GameObject.Instantiate(foodItem, pos, Quaternion.identity);
    }
}

Свойство foodItem ссылается на префаб FoodItem.

Функция Add добавляет на экран в случайных координатах один объект еды. При старте создаем 7 объектов еды.

Добавим в SnakeController при съедании одного объекта, создание нового в случайном месте.

Объявим новое свойство

FoodManager foodManager;

В методе Start присвоим ему наш скрипт. Можно повесить сразу на Head скрипт FoodManager. Но я создал пустой объект на сцене, повесил на него скрипт, и задал имя FooManager. Если змеек будет не одна, то два менеджера еды не нужны :)

В функцию Start добавим

foodManager = GameObject.Find("FoodManager").GetComponent();

В функцию OnTriggerEnter2D после изменения скорости

speed += 0.1f;

Добавим

foodManager.Add();

На этом пожалуй я закончу.

Полный код проекта можно посмотреть по ссылке под видео на канале. 

В нем есть проверка выхода за пределы экрана и сброс половины веса а так же спрайты.

При копировании материалов ссылка на https://terraideas.ru/ обязательна

Комментарии к статье: Создание 2D змейки в Unity.

Нет ни одного комментария. Будьте первым!