Как сделать проверку на столкновение unity

Обновлено: 07.07.2024

В прошлой статье было небольшое введение в принцип работы 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, созданной ранее, перемножить со значением с инпута и записать в новую переменную.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Я бы еще добавил сюда что-нибудь про слоупы. Диагонали очень неприятная тема для начинающих, но с ними рано или поздно придется столкнутся (pun intended).

Для тех, кто думает, что рейкасты это плохо - это не так. Рейкасты можно и нужно использовать. Они очень дешевые по перфомансу. Бахать можно в достаточно большом кол-ве.

Еще с рейкастами можно делать вот такие штуки:

Но есть одна проблема…
находясь в воздухе, снова нажать Space, то персонаж прыгнет ещё раз
Золотой стандарт туториалов по платформерам соблюден, лайк.

Жаль что для сравнения не показано как комапактно выглядел бы весь этот клубок нодов в виде кода. Как по мне для взрослого человека особо не будет никакой разницы по сложности: прочитать туториал по нодам, или ознакомится с несколькими строками кода с развернутыми комментариями, ведь в нодах по сути всё тоже самое, только сделано громоздко, и так чтобы ты ни дай бог от мышки не оторвался.)

Кодом проще, если у есть навыки. Тот же геймдизайнер вряд ли сможет быстро кодом что-то сделать, а вот в Bolt'е прототипчик накидать вполне.

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

На самом деле нет, мне понадобилось три-четыре дня, чтобы освоиться в Bolt'e(при том, что до этого с Unity вообще не работал), а всё остальное уже получается по наитию + помогает Google с конкретными вопросами.

а всё остальное уже получается по наитию + помогает Google с конкретными вопросами

С кодом было бы ровно также. Ну и на разборки потратил бы от 3 дней до недели.

С кодом всё же больший шанс наделать ошибок, да и всё придётся заучивать, когда в Bolt'e есть специально контекстное окно с вызовом нодов, которые ещё и отсортированы.

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

А вот для чего бы такие штуки пригодились так это для сложной скриптовой логики:
- дерево квестов
- игровые события
- процедурная генерация (там что бы добиться вразумительного результата приходиться использовать достаточное сложное дерево функций со сложением, умножением, вычитанием, масштабированием и прочими операциями над шумами)
- искусственный интеллект, так как более-менее сложный ИИ тоже представляет из себя дерево
- анимационные и игровые состояния
В общем везде где есть сложная ветвящееся логика, которую действительно иногда проще прдеставлять визуально.

А такие вещи, как движение и прыжки должны быть реализованы в виде отдельного компонента, который получает только на вход вектора (x,y,z) и (alpha, beta, gamma), да двигает и вращает персонажа.

Однако что на этот счет думает сама Unity Technology, для меня загадка — как я вижу Bolt в Unity живет сам по себе, а конечный автомат в Меканиме сам по себе, хотя по логике они должны быть объеденены и использовать общий механизм, визуальный интерфейс и API, как вот здесь, например,

Кодом проще, если у есть навыки. Тот же геймдизайнер вряд ли сможет быстро кодом что-то сделать, а вот в Bolt'е прототипчик накидать вполне.

Программирование — вторая грамотность

Академик Андрей Петрович Ершов, 1981 год.

Надо уметь программировать, также как уметь читать, писать и считать. И по-моему сейчас многие умеют программировать так или иначе (художники вот умеют в Пухтон-скриптики, например)

а вот в Bolt'е прототипчик накидать вполне

А потом придет менеджер и скажет: "Давай больше фич прикручивай, нам на выставку ехать геймплей показывать!" :-)

Unity | Unreal

Алексей Суслин

Алексей Суслин запись закреплена

как сделать проверку на столкновение с объектом с определённой силой?

Евгений Сыроежкин

if( объекты столкнулись и скорость больше такой-то) <. >else .

Влад Куренков


Влад Куренков ответил Евгению

Евгений, ахахаахах, мне кажется ему как раз и нужно условие в нормально виде)))

Евгений Сыроежкин

А что сложного в справку залезть и посмотреть? Найти там риджид боди и посмотреть его свойства. Там все что надо с примерами.

Я делаю 2D-игру с Unity 5, и у меня проблема с дочерним коллайдером GameObject. Я хочу обнаружить столкновение дочернего GameObject с другим объектом, сделав это из родительского скрипта и используя теги.

Следуйте моему родительскому сценарию ниже:

Когда происходит коллизия, Unity будет искать в иерархии ближайший Rigidbody и запускать любые скрипты на том же GameObject.

Итак, простой подход - убедитесь, что твердое тело находится на родительском объекте со сценарием. Вот пример иерархии:

Когда коллайдер бокса сталкивается с чем-то, событие всплывает прямо через дочерний элемент A и принимается Rigidbody на родительском элементе, который затем запускает скрипт.

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

Пытаюсь найти как сделать такое, казалось бы, простое действие.

К примеру у меня есть объект (завод/шахта), к этому объекту я добавил 2d box collider. Также я добавил ему скрипт Factory.cs В этом скрипте есть к примеру функция (аля корутина) void Dig() которая раз в секунду хочет проверить какие ресурсы есть в области коллайдера завода и выкопать их.

Мне такое решение кажется ну очень неудобным и непонятным. Также оно не работает без добавления rigitbody2D.

Неужели в 2020 нет удобного способа посмотреть с кем мой объект пересекается?

После запуска программы можно наблюдать что при нажатии на Объект с соседями система находит их.


Если же выбрать одиноко стоящий объект у которого визуально нет соседей то наша функция не найдет их что логично.


Теперь когда мы будем находить соседей мы будем их прятать изменяя в них параметр Indeximg на 0. Чтобы проверить как правильно ли наша функция ищет их. Итак для того чтобы понять есть ли у нас соседи мы введем переменную она будет увеличиваться каждый раз на 1 при нахождении соседа. Далее в функции где мы выводили на console (консоль лога) что сосед найден мы получим его свойство Indeximg и изменим его на 0 тем самым стерев его с экрана. В конце работы функции мы проверим нашла ли функция соседей если да то изменим и в выделенном объекте значение IndexImg на 0 если же нет то все оставим как есть.

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