Как сделать трение в юнити

Обновлено: 04.07.2024

3D-игры определенно добавляют уровень сложности по сравнению с 2D, но шаг за шагом вы постепенно создаете интересную 3D-игру. Новые параметры проектов как для 2D, так и для 3D, в Unity поддерживают 3D. В 2D-игре могут быть 3D-объекты и наоборот.

Из чего состоит трехмерная сцена?

Трехмерная (3D) сцена состоит главным образом из трех основных визуальных компонентов: источников света (lights), рендеров мешей (mesh renderers) и шейдеров. Unity поддерживает четыре типа источников света. Вы найдете их в меню GameObject. Поэкспериментируйте, добавляя разные типы и изменяя их свойства. Самый простой из них — источник направленного света (directional light), который подобен солнцу на небе.

Меш (mesh), или модель, — это набор вершин, образующие многоугольники, из которых состоит какой-либо объект. Шейдер является скомпилированной подпрограммой, содержащей код для управления тем, как будет отображаться ваш объект или как он будет взаимодействовать с источником света. Некоторые шейдеры просто берут освещение и отражают его подобно зеркалу, другие — принимают текстуру (изображение, применяемое к мешу) и могут создавать тени и глубину, а некоторые даже позволяют прорезать визуальные дыры в ваших моделях (пример — изгородь).

Asset Store

Я вкратце рассказывал об Asset Store (магазине ресурсов) в своей первой статье, но по-настоящему полезным он становится при разработке 3D-игр. Я не художник и, поскольку это технический журнал, полагаю, что большинство из вас тоже не являются художниками. (Если же вы художник, пожалуйста, примите мои поздравления — это редкий дар.) Но, если вы хотите создать игру, например, с буйной растительностью и старыми полуразрушенными зданиями, это не проблема. Я могу купить то, что мне нужно, в Asset Store. Если мне нужны 15 видов зомби, я могу приобрести пакет от Mixamo в Asset Store. Потенциально возможные комбинации почти бесконечны, так что не волнуйтесь о том, что чья-то игра будет выглядеть похожей на вашу. А самое главное в том, что Asset Store интегрирован с Unity. Вы можете обновлять свои пакеты, щелкая Window | Asset Store, а затем значок корзины. Вы также можете просматривать рецензии и комментарии, чтобы быстрее понять, подойдет ли конкретный элемент для вашего проекта, например оптимизирован ли он для мобильного устройства. Настольные игры обычно используют гораздо больше объектов, текстур, вершин, памяти, чем мобильная игра, хотя некоторые из более новых чипов делают сегодня мобильные устройства близкими по своим возможностям к Xbox 360.

В типичной 3D-игре применяются многие из тех же концепций, что и в 2D-играх: коллайдеры, триггеры, абсолютно твердые тела (rigid bodies), игровые объекты/преобразования, компоненты и др. Независимо от типа 3D-игры обычно вам нужно контролировать ввод, перемещения и персонажей, использовать анимации и эффекты частиц, а также выстраивать воображаемый мир так, чтобы он был и фантастическим, и реалистическим. Мы обсудим некоторые способы, которыми Unity может помочь добиться всего этого.

Контроллеры ввода, перемещения и персонажей

Чтение ввода для перемещения в 3D немного усложняется, потому что вместо простого движения в плоскостях X и Y теперь можно двигаться в трех измерениях: X, Y и Z. Варианты 3D-перемещения включают (но не исчерпываются ими) движение сверху вниз, где персонаж двигается только горизонтально и вертикально; поворачивание камеры или персонажа при считывании ввода от мыши, как это делается во многих шутерах от первого лица (first-person shooter, FPS); смещение влево и вправо при чтении ввода по горизонтали; вращение вокруг себя при чтении ввода по горизонтали или простое движение в обратном направлении. Вариантов перемещения очень много, так что вам есть из чего выбирать.

Рис. 1. Различные методы перемещения объектов

У каждого подхода есть свои плюсы и минусы. При перемещении только с помощью преобразования производительность может пострадать (методы 1–2), хотя это очень простой способ перемещения. Unity предполагает: если у объекта нет компонента rigidbody, он, вероятно, не является перемещаемым объектом. Она создает на внутреннем уровне статическую матрицу столкновений (static collision matrix), чтобы знать, где находятся объекты; это повышает производительность. Когда вы перемещаете объекты с помощью преобразования, эту матрицу нужно пересчитывать, что приводит к уменьшению производительности. В простых играх вы никогда не заметите этого падения производительности, и такие варианты могут оказаться для вас самыми простыми, хотя по мере усложнения ваших игр важно перемещать само абсолютно твердое тело, как в методах 4–6.

Поворачивание объектов

Поворачивание объектов — операция сравнительно несложная, во многом аналогичная перемещению объектов, но теперь векторы представляют градусы, а не позицию или нормализованный вектор. Нормализованный вектор — это просто вектор с максимальным значением 1 для любого значения, и он может использоваться, когда вам нужно лишь ссылаться на направление по вектору. Вам доступны некоторые ключевые слова, относящиеся к векторам, например Vector3.right, back, forward, down, up, left, right, zero и one. Все, что будет перемещаться или поворачиваться в положительном горизонтальном направлении, может использовать Vector.right, под которым подразумевается (1,0,0), или одна единица вправо, а в случае поворачиваемого объекта это один градус. На рис. 2 я просто понемногу поворачиваю объект в каждом кадре.

Рис. 2. Метод для поворачивания объекта

У каждого из этих методов есть свои нюансы. Какой из них следует использовать вам? Я попытался бы по возможности приложить силы к rigidbody. Наверное, я просто немного запутал вас этим вариантом. Хорошая новость в том, что уже имеется код, способный делать за вас практически все из этого.

Вы обратили внимание на Quaternion в методе 3? Unity использует на внутреннем уровне эти Quaternion для представления всех поворачиваний. Quaternion — эффективные структуры, предотвращающие эффект, который называется шарнирной блокировкой (gimbal lock). Он возможен, если для поворачивания вы используете обычные углы Эйлера (Euler angles). Шарнирная блокировка происходит, когда две поворачиваемые оси оказываются в одной плоскости, после чего их нельзя разделить. (Наглядную демонстрацию см. в видеоролике по ссылке bit.ly/1mKgdFI.) Чтобы избежать этой проблемы, Unity использует структуры Quaternion вместо углов Эйлера, хотя вы можете задавать углы Эйлера в Unity Editor и он в конечном счете будет выполнять их преобразование в Quaternion. Многие никогда не сталкиваются с шарнирной блокировкой, но я хотел указать на то, что, если вы хотите напрямую задавать поворачивание в коде, то должны делать это через Quaternion; кроме того, вы можете сами преобразовывать углы Эйлера с помощью Quaternion.Euler.

Теперь, когда вы увидели множество вариантов, должен отметить, что самым простым методом я нахожу использование rigidbody и простое применение .AddForce к персонажу. По возможности я предпочитаю повторно использовать код, и, к счастью, Unity предоставляет целый ряд заготовок (prefabs).

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

Unity предоставляет пакет Sample Assets в Asset Store (bit.ly/1twX0Kr), который содержит кросс-платформенный диспетчер ввода, элементы управления для контроля джойстиков на мобильных устройствах, некоторые анимации, эффекты частиц и, что самое важное, ряд заранее скомпилированных контроллеров персонажей.

В Unity (версии 4.6 на момент написания этой статьи) также включены некоторые более старые ресурсы. Эти ресурсы теперь распространяются как отдельный пакет, который Unity может обновлять индивидуально. Вместо написания всего кода для создания в игре персонажа от первого или третьего лица или даже самостоятельно движущегося автомобиля вы можете просто использовать заготовки (prefabs) из ресурсов-образцов. Перетащите заготовку в свою сцену и вы моментально получите персонаж с видом от третьего лица со множеством анимаций и полным доступом к исходному коду, как показано на рис. 3.

Заготовка персонажа от третьего лица


Рис. 3. Заготовка персонажа от третьего лица

Анимации

Системе анимации Mecanim в Unity можно было бы посвятить целую книгу (и такая книга уже написана, кстати). Анимации в 3D, как правило, сложнее, чем в 2D. В 2D файл анимации обычно изменяет спрайт для рендеринга в каждом ключевом кадре. В 3D данные, связанные с анимацией, гораздо сложнее. Вспомните: в предыдущей статье я говорил, что файлы анимации содержат ключевые кадры. В 3D может быть много ключевых кадров, каждый из которых содержит массу точек данных для движений пальцев, руки или ноги или для выполнения любого количества и типа перемещений. Кроме того, меши могут определять кости в них и использовать компоненты, называемые рендерами мешей со скинами (skinned mesh renderers), которые деформируют меши на основе того, как движутся кости; это во многом напоминает то, как движутся живые существа.

Файлы анимации обычно создаются в сторонней системе моделирования/анимации, хотя их можно создавать и в Unity.

Контроллер анимации для управления состояниями анимации персонажа


Рис. 4. Контроллер анимации для управления состояниями анимации персонажа

Помните, что персонажи и анимации можно получать из Unity Asset Store, создавать с помощью средств моделирования и использовать сторонние продукты вроде Fuse от Mixamo, которые позволяют быстро генерировать адаптированные под ваши потребности персонажи. Просмотрите мои видеоролики на Channel 9 — они дадут вам начальное представление об анимации в Unity.

Создание мира

В Unity встроена система террейнов для генерации миров. Можно создать террейн, а затем использовать имеющиеся инструменты для приданию террейну нужных форм, создания гор, размещения деревьев и травы, рисования текстур и др. Можно добавить в мир небо, импортировав пакет скайбоксов (Assets | Import Package | Skyboxes) и назначив их в Edit | Render Settings | Skybox Material. У меня ушло около пары минут на создание террейна с динамической отражающей водой, деревьями, песком, горами и травой (рис. 5).

Быстро созданный террейн


Рис. 5. Быстро созданный террейн

Системы координат в Unity

В Unity есть четыре метода для ссылки на какую-либо точку в игре или на экране (рис. 6). Существует экранное пространство, диапазон которого простирается от 0 до количества пикселей; оно обычно используется для получения местоположения, где пользователь коснулся экрана или щелкнул мышью.

Пространство области просмотра (viewport space) — просто значение от 0 до 1, благодаря которому можно сообщить, что полпути — это .5, а не делить пиксели на 2. Поэтому я могу разместить объект посреди экрана, указав в качестве его позиции координаты (.5, .5).

Мировое пространство (world space) относится к абсолютному позиционированию объекта в игре на основе трех координат: (0, 0, 0). Все игровые объекты верхнего уровня в сцене имеют свои координаты, перечисленные в мировом пространстве.

Наконец, локальное пространство (local space) всегда относительно родительскому игровому объекту. В случае игрового объекта верхнего уровня оно идентично мировому пространству. Все дочерние игровые объекты перечисляются в Editor с координатами относительно их предку, поэтому, например, в вашей модели у дома могут быть мировые координаты (200, 0, 35), тогда как у его передней двери (предполагая, что это дочерний игровой объект, принадлежащий дому) — только (1.5, 0, 0), поскольку они относительны предку. В коде, когда вы ссылаетесь на transform.position, всегда используются мировые координаты, даже если это дочерний объект. В данном примере у двери были бы мировые координаты (201.5, 0, 35), но, если вместо этого вы ссылаетесь на transform.localPosition, вы получили бы (1.5, 0, 0). В Unity есть функции для преобразований между различными системами координат.

Координаты в Unity


Рис. 6. Координаты в Unity

Screen space: Экранное пространство:
Viewport space: Пространство области просмотра:
World space: Мировое пространство:

Потоки и сопрограммы

Рис. 7. Применение сопрограммы для приостановки действия

Физика и обнаружение коллизий

Физика и средства обнаружения коллизий в 3D почти такие же, как в 2D, с тем исключением, что коллайдеры имеют другую форму и у компонента rigidbody есть несколько других свойств, таких как способность свободного вращения или перемещения по осям X, Y и Z. В 3D теперь имеется коллайдер меша, который обертывает всю фигуру модели как зону распознавания коллизии. Звучит грандиозно, и для коллизий это все весьма хорошо, но плохо для производительности. В идеале, нужно упростить формы коллайдеров и ограничить процессорные ресурсы, необходимые для их использования. У вас есть зомби? Нет проблем — используйте коллайдер капсулы (capsule collider). Сложный объект? Используйте несколько коллайдеров. По возможности избегайте коллайдера меша.

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

Методов гораздо больше, чем перечислено здесь, в частности есть методы OnTriggerExit и OnCollisionExit, почти идентичные своим аналогам в 2D.

Создание объектов

Когда вам нужно создать в период выполнения новые элементы на основе GameObject, не пользуйтесь конструкторами. Вместо них применяйте Instantiate. У вас определенно могут быть классы с конструкторами, которые в скриптах неявно наследуются от MonoBehavior; это происходит во всех скриптах верхнего уровня, назначенных любому GameObject. Однако эти скрипты могут вызывать конструкторы для других объектов:

Эффекты частиц

Если вы хотите, чтобы у вас были мерцающие звезды, пыль, снег, взрывы, огонь, туман, поднимающийся от водопада, всякие кровавые и другие эффекты, нужно использовать эффект частиц (particle effect). В Unity есть старая система частиц и более новая, лучше оптимизированная — Shuriken. С помощью Shuriken в Unity можно делать массу потрясающий вещей, в том числе заставить падающие частицы поддерживать коллизии. Поскольку на этот счет существует множество учебных пособий, например по ссылке bit.ly/1pZ71it, и эффекты, как правило, создаются в Editor с дизайнером, здесь я просто покажу, как можно создавать их экземпляры, когда, скажем, некий персонаж попадает в область триггера монеты, которую он должен подобрать.

Чтобы начать работу с частицами, выберите Game Object | Particle System и вы сразу же увидите, что в вашу сцену добавлен один из эффектов, как на рис. 8.

Эффект частиц


Рис. 8. Эффект частиц

Я предпочитаю создавать из своих систем частиц заготовки (о которых я рассказывал во второй статье), чтобы их можно было легко использовать повторно. Достаточно создать их экземпляры в коде, сначала назначив скрипт игровому объекту (предполагая, что его класс наследует от MonoBehavior, как и все компоненты script игровых объектов), а затем перетащив нужный эффект частиц в Editor из сцены или заготовки в проект, например, на предоставляемое свойство SmokeEffect (рис. 9).

Рис. 9. Предоставляемое свойство SmokeEffect

Создание UI

В Unity 4.6 добавили совершенно новую систему UI для создания элементов HUD (heads-up display) в игре с использованием текста, панелей, виджетов и др. Добавление текста в HUD вашей игры сводится к выбору GameObject | UI | Text и заданию шрифта и текста. Если вам нужно позднее управлять текстом в коде, например для обновления счета, вы просто используете:

Если мне требуется некое изображение в UI, я открываю GameObject | UI | Image и назначаю спрайтовое 2D-изображение этому новому компоненту. Значения задаются, как и в случае любого другого игрового объекта. Надеюсь, что к этому моменту вы уже заметили шаблон. Чтобы создать простой GUI, создайте UI-объекты через меню GameObject | UI, укажите начальные значения в Editor и позже контролируйте их, получая ссылки на данные UI-компоненты и изменяя значения или даже анимируя их. Я сформировал базовый GUI, показанный на рис. 10, создав элементы под новым компонентом Canvas. Новая UI-система в Unity 4.6 содержит ряд базовых типов объектов, таких как Panel, Button, Text, Image, Slider, Scrollbar и Toggle, и с ними невероятно легко работать при создании UI.

UI с изображением и текстов в HUD


Рис. 10. UI с изображением и текстов в HUD

Искусственный интеллект в вашей игре

Заключение

3D-мир вносит дополнительный уровень сложности по сравнению с 2D, так как в нем вы имеете дело с полноценными мешами и еще одним измерением. Asset Store — важнейший источник ресурсов как для начинающих, так и для продвинутых разработчиков игр, и вы действительно можете значительно ускорить создание своей игры, используя готовые ресурсы.

Когда я только начинал разрабатывать игры, я едва не сошел с ума в поисках множества моделей и текстур в Интернете. В Интернете есть некоторые великолепные торговые площадки, предлагающие такие ресурсы, но вы быстро поймете, что не все они годятся для игр. Как-то раз я скачал модель небольшого валуна, в которой оказалось почти 100 000 вершин! Ищите ресурсы, оптимизированные под мобильные устройства, или проверяйте количество вершин/многоугольников, чтобы они гарантированно работали в ваших играх. А иначе они значительно замедлят вашу игру. Существуют средства оптимизации моделей, в том числе Cruncher, включенный в Unity. В следующей статье я рассмотрю, как перенести игру или приложение из Unity на платформу Windows. Заходите в мой блог на Channel 9 (aka.ms/AdamChannel9), где я периодически выкладываю свои учебные видеоролики и ссылки на различный контент для скачивания.

Выражаю благодарность за рецензирование статьи экспертам Мэтту Ньюмену (Matt Newman) из Subscience Studios и Тоутвидасу Цилису (Tautvydas Žilys) из Unity.

Здравствуйте.
Возникла проблема:в 2d пространстве есть колесо, которое должно просто висеть в воздухе вращаться, и есть главный герой который должен с него соскальзывать.

Попробовал это реализовать это так: на колесо повесил круговой колайдер, и вращал его через трансформ. Однако при такой реализации главный герой находясь на этом колесе просто стоит на нем, проскальзывая и никуда не падая при любом трении.
Что бы этого избежать видимо надо вращать колесо через ригидбоди, но при его добавлении колесо начинает падать и не совсем понятно как быть.
По сему вопрос: как быть?
P.s. заранее благодарен за помощь.

Ну а Constraints зачем придуманы? Фризиш по Y - никуда падать не будет.
PS^ убрать гравити не пойдет - под тяжестью стоящего на нем предмета все равно падать начнет

Дело в том что в в 2d ригидбоди нельзя фризить по координатам.
На самом деле решением является поставить галку isKinematic, тогда как раз объект и остается на месте.

Из этого туториала вы узнаете, как создать игру с использованием Unity3D! Попутно вы узнаете о важности использования физического движка и о том, как это сэкономит бесчисленные часы ручной анимации. Читай дальше!

Какой современный игровой движок будет полным без физического движка? Каждый текущий игровой движок, будь то 3D или 2D, имеет какую-то физическую библиотеку, и Unity не является исключением. Физика в реальном времени идеально подходит для моделирования сложных взаимодействий между объектами в вашей игре. Физический движок может сэкономить много ручного кодирования и анимации для достижения реалистичного движения, может упростить выполнение обнаружения ударов и быстро внедрить множество новых игровых механизмов в ваши игры.

В этом уроке мы будем использовать физический движок в Unity для создания трехмерной игры, похожей на BoomBlox и Angry Birds. Мы научимся придавать объектам разные физические свойства, делать их способными к столкновению и даже позволять им разрушаться, если столкновения достаточно сильны.

Финальная игра

Что такое физический движок?

Настройка проекта

Коллайдеры

Удобно, когда бы ни создавался GameObject, ему автоматически назначается соответствующий коллайдер. Куб получает BoxCollider, Сфера получает SphereCollider, Цилиндр получает CapsuleCollider и так далее.

Коллайдеры

В конечном итоге нам понадобится несколько блоков, чтобы сбить:

Если мы нажмем Play, блок ничего не сделает. Хотя у него есть коллайдер, у него нет твердого тела, поэтому на него не влияют никакие физические силы.

Rigidbodies

Твердое тело — самый важный элемент физического движка. Любой GameObject, к которому он прикреплен, включается в симуляцию.

Компонент твердого тела

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

Построить структуру

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

Земля автоматически получит MeshCollider, который будет препятствовать прохождению любых твердых тел через нее. Нажмите Play, и блок должен упасть и осесть на землю.

Сила тяжести

Теперь нам нужна структура, чтобы сбить с ног. Выберите блок и нажмите Ctrl + D в Windows или Cmd + D в OSX, чтобы дублировать блок несколько раз. Используйте инструменты масштабирования и перемещения, чтобы растянуть и расположить блоки примерно в той же конфигурации, что и на рисунке ниже.

Снаряжение персонажей в Shadow Fight 3 имеет множество элементов, подверженных физической симуляции, которая добавляет динамики происходящему на экране. Одной из основных трудностей, с которой мы столкнулись при настройке физики для данных элементов, является тот факт, что кости, к которым они прискинены, находятся внутри иерархии скелета самого персонажа. При движении они повторяют трансформации родительских костей и не получают физически реалистичного импульса.

Самым простым решением стал детач костей. После инициализации всех элементов снаряжения с помощью скрипта мы вынимаем кости физически активных элементов из иерархии скелета персонажа и, используя компонент Character Joint, создаем связь с родительской костью.

Рассмотрим это решение на примере шлема мародёра, спартанский гребень которого подвержен физической симуляции. Мы разбили гребень на 5 частей, каждая из которых была прискинена к разным костям. В настройках Joint этих костей выставили лимиты на поворот по нужной оси и задали параметр Twist Limit Spring, отвечающий за эффект пружины.

Поэтому кости гребня мы решили оставить внутри иерархии персонажа, а для повышения динамичности придать им фейковый импульс. Для этого нам потребовалось в каждой анимации (кроме боевой стойки) определить момент, когда прикладывать импульс, а также его направление.

Можно было бы считывать количество кадров в текущей анимации, потом вычитать из этого значения 15‑20 кадров и прикладывать импульс по истечении полученной разницы. Однако лишней арифметики нам удалось избежать, привязав момент срабатывания импульса к окончанию интервала анимации uninterrupted.

У каждой анимации (опять же кроме боевой стойки) есть преднастроенный период, в течение которого игрок не может её прервать. По истечении этого срока или в момент получения удара интервал uninterrupted заканчивает своё действие, и в этот момент срабатывает наш импульс. Нужно было только настроить исключения для нескольких анимаций.

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

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

В ряде случаев (например, с металлическими пластинами) использование коллайдеров неизбежно. Однако основную нагрузку несёт не само наличие коллайдеров, а расчёт их столкновений. Минимизировать эту нагрузку помогает тонкая настройка матрицы столкновения слоёв (Layer Collision Matrix) в Project Settings. Для подобных элементов мы используем два отдельных слоя, которые коллизятся только между собой, таким образом избегая просчёта столкновения с коллайдерами других слоев (оружия, пола, стен и так далее).

В Shadow Fight 3 есть несколько типов оружия, для которых применяется физическая симуляция вне атакующих анимаций. На текущий момент это нож на цепи, кусаригама, нунчаки и цеп. По описанным выше причинам мы решили вынимать кости оружия из иерархии персонажа вне атакующих анимаций и возвращать обратно тогда, когда физическая симуляция не требуется.

Манипулируя параметром Is Kinematic в компоненте Rigidbody костей, в зависимости от ситуации мы включаем и выключаем физику для них.

Однако при использовании кусаригамы и ножа на цепи мы столкнулись с повышенной нагрузкой на слабых устройствах и получили просадку FPS. Проблема возникала именно тогда, когда кости возвращались в иерархию персонажа и физическая симуляция для них отключалась. Связано это с тем, что изменение трансформов родительской кости в иерархии скелета даёт нагрузку на физический движок для каждой дочерней кости, на которой есть компонент Rigidbody, даже если активен параметр Is Kinematic. И чем длиннее иерархия, тем больше нагрузка.

Решением стало создание физического клона. Рассмотрим это на примере ножа на цепи.

Во время загрузки боя для него инициализируется два скелета: основной, который находится внутри иерархии персонажа, и его физический клон. В костях основного скелета отсутствует компонент Rigidbody, на их трансформацию влияют только анимационные треки. Кости второго имеют настроенные связи (Joint) и компонент Rigidbody с активным параметром Is Kinematic.

В то время как на трансформацию костей основного скелета влияет анимационный трек, например, во время удара, параметр Is Kinematic в компоненте Rigidbody костей физического клона остаётся активным. Кости не трансформируются и не подвергаются физической симуляции. Во время последнего кадра анимации происходит синхронизация трансформов костей двух скелетов.

Физический клон считывает положение и ротацию костей основного скелета и задаёт своим точно такие же параметры. Затем деактивируется Is Kinematic, и кости физического клона подвергаются симуляции. Далее, вплоть до начала следующей атакующей анимации, уже основной скелет считывает каждый кадр трансформ костей физического клона, которые в этот момент двигаются по физике, и задаёт эти параметры своим костям. Такой подход позволил существенно снизить нагрузку на физический движок и улучшить производительность на слабых устройствах.

Также симуляцию тканей мы использовали при создании FX-эффекта пламени на оружиях и на голове босса Теневой разум. В настройках Cloth для этих элементов мы отключили влияние гравитации и задали значения ускорения (Acceleration) по оси Y: постоянный, чтобы пламя стремилось вверх, и рандомный — для эффекта трепыхания. Чтобы при движении не было резкого искажения геометрии, мы выставили повышенное значение сопротивления (Damping). Таким образом мы получили достаточно реалистичный и дешёвый в плане производительности эффект пламени.

В момент смерти и в определённых ситуациях при получении удара для персонажей в Shadow Fight 3 активируется симуляция физики. Долгое время для этого использовалась стоковая физика твёрдых тел Unity. Однако при внедрении синхронного PvP в проект от неё пришлось отказаться в пользу собственной разработки.

Синхронное PvP подразумевает одинаковую симуляцию игры на двух клиентах. С анимацией проблем нет, поскольку всё рассчитано заранее, в то время как с физикой возникают определённые проблемы.

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

Самое простое, на первый взгляд, решение — во время физической симуляции брать положение персонажа на одном клиенте и передавать на другой, синхронизируя их. Но регдолл персонажа представляет из себя длинную иерархию костей с большим количеством отдельных независимых твердых тел (конечности, голова), для корректной синхронизации положения которых нужно передать большой объем данных за короткий промежуток времени.

Итак, что же представляет из себя наш регдолл? Тело состоит из узлов, которые являются материальными точками. У них нет ориентации, но есть положение и масса, и между ними реализованы связи регулируемой жесткости. К каждой кости внутри скелета персонажа привязана группа таких узлов. Данная архитектура подразумевает отсутствие внутренних коллизий и ограничений в суставах, а внешние коллизии и трение реализованы на уровне узлов. При движении узлов в пространстве учитываются гравитация, внешние силы и инерция.

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

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

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

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

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

Изначально при переходе в физику мышцы жёстко расталкивали узлы, приводя их в нужную позицию. Зачастую резкость этого расталкивания также приводила к тому, что конечности сильно выкручивались. Мы добавили плавное увеличение силы мышц, чем сильно улучшили ситуацию.

В течение первых двух кадров после начала симуляции физики сила мышц сохраняется максимальной, чтобы стабилизировать узлы после применения к ним импульса. Затем мышцы расслабляются, их сила становится 55% , а далее в течение 120 кадров сила постепенно увеличивается вплоть до 100%.

Последним шагом стало добавление двух стабилизирующих узлов: спереди на уровне груди и сзади на уровне ног. Эти узлы имеют рёберные связи с фиксированными узлами груди и таза соответственно, а мышцами стягивают нестабильные узлы. Стабилизирующие узлы имеют низкое значение массы и не имеют коллизии с полом, в отличие от остальных узлов.

На гифке ниже вы видите результат: мы получили полностью детерминированную физику, построенную на целочисленных вычислениях, стабильно работающую при 60 FPS даже на самых слабых устройствах, которые мы поддерживаем.

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

Джоинты

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

Все компоненты джоинтов можно найти во вкладке Component -> Physics 2D .

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

Как это работает

Давайте взглянем на изображение ниже, где показаны общие для всех джоинтов настройки компонента.


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

Здесь, на изображении, специально не показано название компонента джоинта, так как эти настройки являются общими для них всех. Исключением является Target joint , который мы разберем в самом конце статьи.

Начнем с поля Connected Rigid Body . В это поле можно поместить любой физический объект с которым необходимо установить связь.


Далее поле Enable Collision , которое включает и отключает коллизии между джоинтом и присоединенным объектом.


Поле Anchor , представляет собой Vector2, в котором можно указать место расположения крепления джоинта относительно его Transform’а . Обычно место расположения джоинта указывают сразу при создании на сцене и поле Anchor оставляют без изменений.


Следующее поле Connected Anchor, также представляет собой Vector2 , где уже в свою очередь необходимо указать конкретно точку крепления объекта к джоинту относительно самого Transform’а джоинта.


По умолчанию поле Auto Configure Connected Anchor включено и поэтому точка крепления объекта к джоинту указывается автоматически как “ центр ” самого объекта. К примеру, когда нужно “ зацепить ” объект за какой либо край, галочку напротив поля Auto Configure Connected Anchor необходимо снять и вручную установить “ место зацепления ”.


Поле Break Force указывает силу, при превышении которой произойдет разрыв соединения между джоинтом и объектом. По умолчанию стоит значение Infinity , при котором разрыва соединения не произойдет.


У большинства джоинтов также имеется поле Break Torque , где можно указать силу, при которой произойдет разрыв соединения при вращении. Также как и поле Break Force – по умолчанию имеет значение Infinity .

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

Fixed joint

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

У этого джоинта помимо стандартных настроек Break Force и Break Torque есть новые поля Damping Ratio и Frequence , изменяя которые можно определить, как сильно объект фиксируется в точке. Оба поля принимают числовое значение, где 0 означает полную фиксацию объекта, вне зависимости от внешних воздействий на объект.


Hinge joint

Следующий Hinge joint , также фиксирует объект в точке, и в отличие от Fixed joint не прерывает “ воздействия ” физики на сам объект.

Этот джоинт позволяет применять силу для совершения вращения объекта, а также вводить ограничения на угол вращения. Для этого в компоненте есть поле Motor , где указаны две переменные – Motor Speed и Maximum Motor Force , для скорости вращения и максимальной силы, применяемой для совершения вращения. Ограничивать угол вращения можно в поле Angle Limits , где для этого введены две переменные – Lower и Upper Angle – нижнего и верхнего предела угла вращения.

Slider joint

Этот джоинт немного похож на предыдущий Hinge joint , он тоже позволяет применять силу к объекту. Разница в том, что Hinge joint это делает для вращения объекта, а Slider joint применяет эту силу, чтобы двигать объект под определенным углом.

Также этот джоинт имеет новое поле Angle, где можно указать под каким углом объект будет перемещаться.


Distance joint

Следующий джоинт, как и остальные, имеет стандартный набор настроек, а также новое поле Distance, где можно указать минимальное расстояние между джоинтом и объектом. Если собрать “ цепь ” из нескольких таких джоинтов, то можно получить отличный аналог веревки, которая не растягивается и не рвется.

Spring joint

Этот джоинт также имеет поле Distance , но в отличие от Distance joint – позволяет имитировать “ пружину ” при растягивании. Как и Fixed joint – имеет поля Damping Ratio и Frequency , где можно указать – как быстро и сильно необходимо фиксировать объект к джоинту.

Target joint

Особый джоинт из всего списка, которому нельзя указать объект для присоединения – у него просто нет такого поля. Дело в том что если раньше мы сначала определяли позицию джоинта на сцене и к нему уже крепили объект, то в случае с Target joint – сам объект и является джоинтом, и вместо крепления к другому джоинту, он крепится к определенной точке на сцене. Для этого у него есть новое поле – Target, представленное в виде Vector2 , где можно указать локальную точку крепления относительно объекта.

По принципу работу он немного похож на Spring joint, в котором также есть поля Damping Ratio и Frequency.

Заключение

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

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