Изучая физику, вы обнаружите, что все движения объектов представляют собой комбинацию сил. Например, если вы пытаетесь толкнуть коробку, то на нее будут действовать следующие силы:
- сила тяжести, которая тянет коробку вниз;
- сила толчка, которую вы применяете, чтобы толкнуть коробку;
- сила трения о землю, направленная против этого толчка.
Чтобы рассчитать вектор перемещения коробки, нужно воспользоваться физическими формулами и выполнить ряд математических вычислений. В игре также необходимо отслеживать столкновения коробки с другими объектами, например, препятствиями. При этом другие объекты тоже могут двигаться, и нам необходимо делать вычисления и для них тоже. Представьте, что таких объектов в игре будет сотни: объекты могут быть сложной формы, двигаться и пересекаться между собой, их пересечение необходимо проверять со всех четырех сторон и т.д. В итоге, чтобы на игровой сцене смоделировать движение всех объектов и отследить их взаимодействия между собой, потребуется выполнять много сложных физических и математических вычислений.
Но, можно один раз написать весь этот сложный код, а потом использовать его во всех играх, что и делает физический движок Unity. Unity имеет встроенную физическую систему, которая может вычислять движения и столкновения объектов, а нам нужно только научиться правильно ее использовать в играх.
Компонент, который позволяет использовать возможности физического движка Unityназывается «Rigidbody2D» для двумерных проектов или «Rigidbody» для трехмерных. Этот компонент дает игровому объекту свойства твердого тела. Чтобы избежать дорогостоящих математических и физических операций над каждым игровым объектом на сцене, Unity выполняет вычисления только для тех объектов, к которым прикреплен этот компонент.
Рассмотрим работу с этим компонентом сразу на примере двумерного проекта. Создадим игровой объект птицы и добавим ему компонент «Rigidbody2D». Дополнительный материал про компоненты и работу с ними можно изучить по ссылке: https://dzen.ru/a/Za437i6Q937jiND_
Если теперь запустить игру, то персонаж просто улетит вниз. Это хорошо видно в режиме паузы. Если вы не знаете, как пользоваться режимом паузы, то просчитайте статью https://dzen.ru/a/Zbd_J6TwtSEEHWyt
Персонаж упал, потому что на него стала действовать сила тяжести. Физический движок считает, что где-то внизу бесконечно далеко находится поверхность («земля»), поэтому персонаж при запуске игры будет просто бесконечно падать.
Можно отключить действие силы гравитации при помощи свойства «Gravity Scale», установив для него значение 0.
Теперь при запуске игры персонаж перестанет падать вниз.
У компонента твердого тела есть три типа:
· Dynamic
· Kinematic
· Static
Динамическое твердое тело обладает полным набором физических свойств для моделирования его движения. Этот тип тела устанавливается по умолчанию, потому что используется чаще всего.
Расчеты его перемещения и взаимодействия с другими объектами полностью берет на себя физический движок Unity, поэтому это самый «дорогой» тип. Не стоит использовать его бесконтрольно для большого количества объектов в игре.
Динамическое тело может взаимодействовать с любым другим типом тела.
Кинематическое твердое тело предназначено для моделирования перемещения под контролем программиста. На такое тело не действуют силы, реализованные в физическом движке Unity, поэтому расчеты по перемещению и взаимодействию с другими объектами для кинематического тела реализует программист. По этой причине такой тип тела более быстрый и требует меньше системных ресурсов, чем динамический тип. Зато при помощи кинематического тела можно реализовать абсолютно новую, авторскую физику в вашей игре.
Физический движок Unity не поддерживает обработку взаимодействий кинематического тела с другими кинематическими или статическими телами, взаимодействие возможно только с динамическим телом.
Статическое тело ведет себя как неподвижный объект. Это наименее ресурсоемкий тип тела. Взаимодействие такого тела возможно только с динамическим типом тела.
Частая ошибка – использование данного типа твердого тела для всех стационарных объектов на сцене – стен, деревьев, блоков и т.д. Но это неправильно! Компонент физического тела необходим для придания определенных свойств именно игровому объекту, а не взаимодействиям между объектами. Стенам и деревьям не нужны никакие свойства, это просто стационарные твердые препятствия, которым достаточно добавить коллайдеры, чтобы персонаж не смог проходить сквозь них.
Для перемещения физического тела нельзя использовать компонент «Transform» и просто изменять позицию игрового объекта. Компонент «Transform» отвечает за позицию отрисовки спрайта на сцене и связан с графическим движком. Поэтому при таком перемещении физического тела будут возникать проблемы. Например, персонаж будет проваливаться сквозь пол или проходить через стены.
Такой код для игрового объекта с компонентом «Rigidbody» недопустим:
transform.position = transform.position + new Vector3 (1, 0, 0);
Для вычисления правильной позиции игрового объекта с компонентом «Rigidbody» необходимо заставить работать физический движок Unity, который просчитывает перемещение именно физического тела. Тогда персонаж будет вовремя останавливаться возле стен и других твердых препятствий.
Поэтому изменение положения или поворота игрового объекта с компонентом «Rigidbody» или «Rigidbody2D» ВСЕГДА осуществляется только через этот компонент.
Доступ к компоненту «Rigidbody(2D)» можно получить через метод GetComponent<Rigidbody(2D)>().
Подробнее про компоненты и работу с ними можно почитать в статье https://dzen.ru/a/ZdLxUjWs1kpwHFql
Полный список методов и свойств для управления физическим телом можно найти на официальном сайте с документацией:
https://docs.unity3d.com/ScriptReference/Rigidbody.html
Для управления компонентом динамического твердого тела рекомендуется использовать метод:
- public void AddForce(Vector3 force, ForceMode mode = ForceMode.Force);
С помощью этого метода можно воздействовать на физическое тело с указанной силой. У метода есть несколько режимов, отличающихся для двух- и трехмерных объектов. Подробнее можно почитать по ссылкам на официальную документацию:
https://docs.unity3d.com/ScriptReference/Rigidbody2D.AddForce.html
https://docs.unity3d.com/ScriptReference/Rigidbody.AddForce.html
Для управления компонентом кинематического твердого тела рекомендуется использовать метод:
- public void MovePosition(Vector3 position)
С помощью этого метода можно переместить кинематическое жесткое тело в указанную позицию. Ссылки на официальную документацию:
https://docs.unity3d.com/ScriptReference/Rigidbody2D.MovePosition.html
https://docs.unity3d.com/ScriptReference/Rigidbody.MovePosition.html
Часто метод MovePosition() используют и для динамического твердого тела, когда необходимо выполнить быстрое перемещение тела без учета сил, действующих на него. Но нужно понимать, что этот метод поместит объект в указанную позицию, несмотря ни на что, даже если текущая позиция будет находится внутри другого объекта (например, внутри другого персонажа). Поэтому, используя этот метод для динамического тела, самостоятельно проверяйте куда вы его перемещаете. Подробнее про особенности перемещения с помощью метода MovePosition() можно почитать в статье: https://dzen.ru/a/Zj4I-l3F5hhJWKsb
Реализуем в нашем примере перемещение птицы через компонент физического тела. У птицы есть постоянная горизонтальная скорость, с которой она летит вправо, а игрок, нажимая клавиши вверх и вниз может управлять соответствующим вертикальным перемещением птицы.
Если вы еще плохо разбираетесь в скриптах, то рекомендую почитать следующие статьи:
Что такое переменные: https://dzen.ru/a/ZdLo9tHxawyW7tHU
Для чего нужны скрипты в Unity: https://dzen.ru/a/ZdLxUjWs1kpwHFql
Публичные переменные: https://dzen.ru/a/ZgUlGyfWFU6VlNp3
Разница методов Update и FixedUpdate: https://dzen.ru/a/Zj4BdeMczhLKhjck
Для начала реализуем перемещение с постоянной скоростью вправо. Вот так будет выглядеть скрипт.
У нас есть публичная переменная для управления горизонтальной скоростью птицы, а также закрытая переменная типа Rigidbody2D. В методе Start() мы связываем закрытую переменную с компонентом физического тела, а затем применяем к ней силу, направленную вправо (Vector2.right) с величиной горизонтальной скорости (HorizontalSpeed).
Теперь попробуем добавить вертикальное перемещение. Нам понадобится вспомогательная переменная UserInput, чтобы передать пользовательский ввод из метода Update() в FixedUpdate().
В методе Update() мы считываем пользовательский ввод по вертикали (клавиши строк вверх или вниз) в переменную UserInput. А в методе FixedUpdate() применяем к компоненту физического тела силу, направленную вверх (Vector2.up) с величиной вертикальной скорости (VerticalSpeed), умноженной на значение пользовательского ввода.
Перемещение птицы будет выглядеть вот так:
Движение птицы по вертикали приходится все время корректировать то вниз, то вверх, иначе на просто улетает за пределы экрана. Это нормальное поведение: в реальной жизни вы не можете контролировать катящийся вперед мяч. Если вы толкнете его вправо, то он не остановится, он продолжит движение чуть правее.
В игре с птицей такое движение смотрится интересно, оно придает процессу некую сложность и азарт. Но допустим, нам нужно реализовать более четкое управление, чтобы птица останавливалась после небольшого перемещения.
В этом случае можно немного изменить код:
В 27 строке используется свойство скорости компонента физического тела. Когда вы применяете к объекту силу, объект начинает двигаться с какой-то скоростью. Мы можем напрямую обратиться к этой скорости и изменить ее, если хотим добиться мгновенного контроля.
Чтобы птица стала более управляемая, мы обнуляем у нее скорость, а затем формируем новый вектор силы, учитывая горизонтальную и вертикальную составляющую.
Движение птицы будет выглядеть следующим образом:
В двумерных платформерах очень часто реализуют перемещение персонажа через обращение к скорости напрямую, так как в платформерах скорость и направление перемещения меняются очень быстро.
Работать напрямую со скоростью иногда даже проще, но нужно очень хорошо понимать работу с векторами. Можно реализовать аналогичное перемещение птицы через ее скорость. Скрипт будет выглядеть вот так:
Обратите внимание, что скорости необходимо сильно уменьшить, потому что это теперь не величина прикладываемой силы, а именно скорость перемещения тела.
Вот так выглядит перемещение птицы, если изменять его через скорость.
Перемещение твердого тела в трехмерных проектах реализуется аналогичным образом. Игровому объекту необходимо добавить компонент твердого тела, у которого снять галочку «Use Gravity». Это аналог свойства «Gravity Scale» для двумерных тел. В трехмерных проектах гравитация задается при помощи флажка, а не числа – либо она используется, либо нет.
Для примера в скрипте реализовано перемещение при помощи метода AddForce() в режиме изменения скорости «ForceMode.VelocityChange», который плавно изменяет скорость объекта.
Вот так это будет выглядеть в режиме игры:
Для резкого изменения скорости объекта используется режим «ForceMode.Impulse».
В этой статье мы рассмотрели простое перемещение физического тела без учета поверхностей и препятствий. Изучить материал по коллизиям физических тел можно в статье про коллайдеры
https://dzen.ru/a/Zj4I-l3F5hhJWKsb
Реализация перемещения двумерного твердого тела под управлением пользователя в разных направлениях с добавлением прыжков рассмотрена в статье:
https://dzen.ru/a/Y4edRLeFPjKh9HUV
Реализация перемещения трехмерного твердого тела под управлением пользователя в разных направлениях с добавлением прыжков рассмотрена в статье: