Как сделать поворот врага в unity 2d

Обновлено: 06.07.2024

В этом уроке мы напишем код, который заставляет gameObject перемещаться вверх, вниз, влево и вправо в зависимости от ввода пользователя. Это должно помочь нам легче понять процесс написания сценариев Unity.

Помните, что у каждого GameObject есть по крайней мере один компонент — Transform . Что особенного, так это то, что Transform для gameObject также отображается как переменная в сценариях Unity, поэтому мы можем изменить его с помощью кода. Это не ограничивается преобразованием; все компоненты в Unity имеют свойства, которые доступны через переменные в сценариях.

Теперь откройте сценарий, и вы увидите то же, что вы видели на последнем уроке.

Давайте создадим общедоступную переменную типа float с именем speed . Обнародование переменной в Unity имеет большое преимущество —

Переменная отображается как редактируемое поле внутри редактора, поэтому вам не нужно вручную корректировать значения в коде.

Переменная отображается как редактируемое поле внутри редактора, поэтому вам не нужно вручную корректировать значения в коде.

Если мы сохраним этот скрипт, не затрагивая другие методы, он должен скомпилироваться в Unity.

буфер

(Вы можете увидеть, когда он компилируется значок в правом нижнем углу.)

Затем перетащите сценарий из активов в GameObject. Если вы делаете это правильно, это то, что вы должны увидеть в свойствах GameObject —

Перетащить

Поскольку значение скорости является регулируемым и не требует постоянного изменения кода, мы можем использовать метод update () вместо start ().

Проверьте пользовательский ввод.

Если есть пользовательский ввод, прочитайте инструкции по вводу.

Измените значения положения преобразования объекта в зависимости от его скорости и направления. Для этого мы добавим следующий код —

Проверьте пользовательский ввод.

Если есть пользовательский ввод, прочитайте инструкции по вводу.

Измените значения положения преобразования объекта в зависимости от его скорости и направления. Для этого мы добавим следующий код —

Давайте теперь обсудим код в кратком изложении.

Прежде всего, мы создаем переменную с плавающей запятой с именем h (для горизонтали), и ее значение задается методом Input.GetAxisRaw . Этот метод возвращает -1, 0 или 1 в зависимости от того, какую клавишу игрок нажал на стрелки вверх / вниз / влево / вправо.

Класс Input отвечает за получение ввода от пользователя в виде нажатия клавиш, ввода мышью, ввода с контроллера и так далее. Метод GetAxisRaw немного сложнее для понимания, поэтому мы вернемся к этому позже.

Затем мы обновляем позицию нашего gameObject на новую позицию, определенную созданием нового Vector2 . Vector2 принимает 2 параметра, которые являются его значениями x и y соответственно. Для значения x мы предоставляем сумму текущей позиции объекта и его скорости , эффективно добавляя некоторую величину в каждом кадре, когда клавиша нажимается на его позицию.

Сохраните этот скрипт и возвращайтесь в Unity. Unity автоматически обновит все сценарии после успешной компиляции, поэтому вам не придется повторно подключать сценарий снова и снова.

Теперь, когда вы закончите, измените значение скорости в свойствах GameObject на 0,8. Это важно, потому что более высокое значение заставит игрока двигаться слишком быстро.

Значение скорости

Теперь нажмите Play и увидите свою первую маленькую игру в действии!

Играть

Попробуйте нажать клавиши со стрелками и перемещаться. Чтобы остановить игру, просто нажмите Play еще раз. Вы даже можете регулировать скорость в режиме реального времени, чтобы вам не приходилось останавливаться и запускать ее постоянно.



Для игр, где требуется создавать множество врагов или просто случайно генерировать объекты на сцене очень важна реализация спавна объектов - их создания из скрипта. Давайте рассмотрим, как это сделать.

Первым делом обозначим переменные, которые будем использовать. Это переменная игрового объекта, который надо создать и переменная позиции в 3D или 2D пространстве. В моем примере игра трехмерная.

Vector3 spawn_pos = Vector3.zero;

Теперь создадим объект на сцене с помощью встроенной в Unity функции Instantiate():

Instantiate(prefab, spawn_pos, Quaternion.identity);

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

В прошлой статье было небольшое введение в принцип работы Bolt и основы визуального программирования. В этой же попробуем небольшой платформер сделать и затронем основные аспекты.

​Поработаем с силами, рейкастами и затронем тему модульности и переиспользования компонентов.


Цикл статей

​Туториалы можно скачать бесплатно с Гитхаба. Каждый туториал будет отдельной папкой в проекте. Конкретно этот туториал будет лежать в директории Assets/Tutorials/02 — Platformer.

Оглавление

Подготовка

Накидаем простенькую сцену с платформами и шипами. Я использовал редактор Тайлов, но это могут быть и обычные спрайты с колайдерами на них. Добавляем в иерархию GameObject игрока.


В инспекторе добавляем к объекту компонент Flow Machine.


Нажимаем Edit Graph и приступает к настройке графа.

Движение персонажа

Мы хотим, чтобы персонаж двигался влево и вправо в зависимости от горизонтальной оси ввода, для которой предварительно настроены сочетания клавиш A и D на клавиатуре или левый джойстик на контроллере. Когда вы идёте влево, возвращается -1 , а когда вправо, то +1 . Скорость движения зададим в переменной.

Для начала можно зайти в настройки и задать необходимое управление в Edit > Project Settings > Input Manager, если не нравятся дефолтные настройки.


Теперь добавим переменную, откуда будем читать скорость. В инспектора объекта игрока добавим переменную в компоненте Veriables. Подробнее можно почитать в документации.

Далее, собственно, нам нужно получить горизонтальную ось ввода. Мы можем сделать это с помощью блока Get Axis.

Новый узел будет полупрозрачным. Так Unity нам сообщает, что они пока нигде не используется. Этот эффект можно отключить на панели отжав пункт Dim.


Далее мы хотим на основании инпута вычислить итоговое значение скорости. Для этого нужно считать значение переменной Speed, созданной ранее, перемножить со значением с инпута и записать в новую переменную.

  1. От выхода узла GetAxis тащим указатель и создаём узел Multiply.
  2. От второго входа нового узла тянем указатель и создаём узел для чтения переменной Variables > Object > Get Object Variable.
  3. Выбираем там Speed.
  4. Выход узла Multiply соединяем с новым узлом Variables > Graph -> Set Graph Variable.
  5. Дадим новой переменной имя Movement.
  6. Соединяем управляющий вход с Update.

Каждый кадр (событие Update) мы получаем значение инпута по оси X в диапозоне [-1;1], домножаем на скорость и сохраняем в переменную Movement.

Теперь нужно задать компоненту Rigidbody 2D персонажа скорость. Скорость состоит из двух составляющих — по осям X и Y, которые пакуются в Vector2 .

  1. Добавляем узел Get Variable для получения Movement из предыдущего шага.
  2. Это передаёт на вход X координате новой ноде Vector2.
  3. А в Y передаём считанную Y координату из текущей скорости (Codebase > Unity Engine > Rigidbody 2D -> Get Velocity).
  4. Полученный вектор передаём на вход узлу для установки нового значения скорости (Codebase > Unity Engine > Rigidbody 2D -> Set Velocity).

Остаётся теперь связать выход узла по установке Movement со входом узла, устанавливающего скорость.

Ну и заодно сгруппируем узлы. Это делается выделением с зажатой клавишей Ctrl .

Если запустить редактор, можно увидеть, как персонаж двигает при нажатии на клавиши. Обратите внимание на граф и то, как меняется значение скорости на нём в режиме реального времени.

  1. Если двигаемся вправо (значение Movement больше 0), значение Scale должно быть положительным.
  2. Если движемся влево (значение Movement меньше 0), значение Scale должно быть отрицательным.
  3. Если стоим на месте (значение Movement равно 0), то ничего не делаем.

Значение Y и Z оставляем как есть.


Если запустить редактор, то увидим, что спрайт персонажа отзеркаливается в зависимости от направления движения.

Но сейчас персонаж просто скользит. Хотелось бы сделать анимацию движения.

Анимация

Возьмём готовые спрайты и анимации из примера проекта Penny Pixel.

Если открыть аниматор, то нас там пока интересует всего 2 анимации: айдловая и бега. Если посмотреть на переход для анимации бега, то заметим, что оно зависит от скорости по оси X. Нам всего лишь нужно это значение передавать аниматору.

Ну и флажок grounded пока в true выставим, чтобы не запускалась анимация полёта.


На графе, как я уже сказал, нам нужно всего лишь передать значение скорости аниматору и записать в переменную velocityX.


Остаётся только соединить с остальным графом и запустить.

Следующим шагом добавим возможность прыгать.

Придание силы объекту для прыжка

  1. Добавим глобальную переменную для силы прыжка и назовём JumpPower.
  2. Events > Input, а там On Button Input.
  3. Вместе со считанной силой прыжка передаём в Codebase > Unity Engine > Rigidbody 2D > Add Force (Force, Mode).

Если запустить, то по нажатию на Space персонаж будет прыгать. Но есть одна проблема…

Во-первых, нету анимации прыжка. Во-вторых, если, находясь в воздухе, снова нажать Space, то персонаж прыгнет ещё раз. А нам бы этого не хотелось.

Создадим новый слой и назначим его платформам.


Необходимо дописать логику по проверке, находится ли персонаж на земле. Один из способов — рейкасты. Будем выпускать лучи вниз на небольшое расстояние, чтобы проверить, сталкиваются ли они с платформой. Проверять как раз по этому слою будем.

Переиспользование логики

Так как эта проверку нужна в двух местах, то выделим всю логику в отдельный юнит Assets > Create > Bolt > Flow Macro.

Для каста использовать будем CircleCast . Хотя это не так принципиально.

  1. Получаем позицию текущую.
  2. Делаем рейкаст по слою Platform, направляя вниз с радиусом 2 и дальностью 2.
  3. Результат получаем в отдельную ноду.
  4. Делаем проверку на то, было ли столкновение.
  5. Результат проверки столкновения луча с платформой пишем в bool переменную IsGrounded на выход.

Теперь в графе персонажа нужно немного изменить узлы, обрабатывающие прыжок.

  1. Перетаскиваем на граф персонажа граф GroundCheck.
  2. Добавляем ветвление.
  3. Соединяем с узлом, задающим силу.

Если запустить, то увидим, что персонаж теперь может прыгать только находясь на платформе.

Точно также добавим проверку к анимации.


Теперь, если персонаж в воздухе, будет проигрываться соответствующая анимация.

Хотелось бы как-то визуализировать дебажную информацию для отладки.

Отладка и OnDrawGizmos

Было бы неплохо как-то визуализировать рейкаст. Как минимум, хочется видеть, как далеко он бьёт. Для этого можно воспользоваться событием OnDrawGizmos , которое позволяет в редакторе рисовать отладочную информацию.

В нашем случае просто будет рисовать линию. Увеличим дальность луча до 50 и добавим соответствующие узлы для отрисовки линии.

  1. Вытаскиваем информацию о текущем положении.
  2. Создаём Vecto3 на основе X и Z координаты. Эта позиция будет конечной при отрисовки линии.
  3. Рейкаст мы делаем вниз, поэтому в Y координату вписываем Y координату текущего положения персонажа с за вычетом дальности луча.
  4. Добавляем ивент, который каждый кадр рисует информацию.
  5. На вход узла по отрисовке в начальную координату передаём текущее положение персонажа, а конечной точкой будет новое вычисленное значение позиции.

Ещё нужно в Scene View включить отображение Gizmos.


Теперь запустим и посмотрим.

Увеличив дальность проверки для рейкаста мы дали возможно персонажу прыгать даже в воздухе.

В следующей статье поработаем с окнами и сделаем экран смерти персонажа с перезапуском сцены.

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

Изображение 1 - моя стена, а изображение 2 - мое игрока.

This is the image of my players inspector. Did I add the right things?

Пытаюсь решить стеной сбоку от экрана. Это изображения

This is the inspector of my player.

Этот код у меня работает! :)

Вы можете сделать это без коллайдеров, просто напишите код, который вы используете для перемещения вашего персонажа, и я объясню вам, как вы можете программно установить границы.

Vector3 dir = Vector3.zero; dir.y = Input.acceleration.x; player.transform.Translate (новый Vector2 (dir.y, 0) * Time.deltaTime * 2000f);

Извините за плохое форматирование. Я новичок в stackoverflow. :)

Это код в моей функции обновления.

Ответы 4

Вы можете разместить в своей сцене за пределами области, которая будет отображаться на вашем устройстве, 2 пустых игровых объекта с коллайдером, чтобы игрок столкнулся с ними.

Вы также можете ограничить с помощью кода границы, которые игрок может перемещать. Вы применяете это с помощью Mathf.Clamp (), и там вам нужно будет установить границы в координате x для вашей сцены.

Вы увидите, что вместо изменения положения игрока с помощью его преобразования мы используем вместо этого твердое тело.

Обновлять Другие варианты:

Обновление 2:

Без зажима, просто устанавливая ограничения на скрипт

Спасибо за Ваш ответ! Я добавил код к своему ответу.

@Jul Попробуйте мой обновленный ответ сейчас.

@Jul Кстати, вы должны проверить единицы на своем экране, я использую магическое число 0 и 50 для левого и правого предела, но вам может потребоваться добавить туда что-то еще

@Jul Я обновил свой ответ. Я также добавлю учебник, который может быть вам интересен

Я пробовал этот код, но безуспешно. Поскольку у меня есть 2D-игра, я добавил Rigidbody2D в свой Player-GameObject. Но я не совсем понял ваш код наверху. И это не сработало, потому что к нему не прикреплено (нормальное) Rigidbody. Я попытался решить эту проблему со стеной сбоку, но твердое тело моего игрока не сталкивается. Что я могу сделать сейчас? :)

@Jul вы также добавили к стенам твердое тело и коллайдеры?

@Jul и все еще не обнаружен? так что именно происходит? Игрок игнорирует стены и продолжает двигаться дальше?

Игрок просто движется сквозь стену и вроде ничего не происходит.

Нужно ли мне изменить какие-то настройки в моем rigdbody2D или Box / Edge Collider2D?

@Jul Хорошо, это может быть способ перемещения игрока, который игнорирует коллайдеры. Попробуйте изменить Update () для сценария, который я только что добавил в свой ответ.

@Jul Это код, который я использовал некоторое время назад, но вводом было положение мыши, а не ускорение телефона

Спасибо за Ваш ответ. Завтра попробую. :)

Спасибо за Ваш ответ. Похоже, работает. Отличная работа! Большое спасибо! :)

Читайте также: