Найти тему

Unity3D. Перемещение объекта с компонентом Rigidbody

445 прочитали

Добавление компонента Rigidbody к игровому объекту позволяет передать движение этого объекта под контроль физического движка Unity. Поскольку физическое тело подвержено влиянию различных сил, то перемещать его необходимо путем прикладывания этих сил к исходному объекту. Причем делать это необходимо в методе FixedUpdate(), так как этот метод вызывается непосредственно перед каждым обновлением физики, поэтому любые сделанные там изменения будут выполняться точно синхронно с самим физическим движком.

Иногда при работе с Rigidbody возникает проблема, что физика игры работает как бы «замедлением». В первую очередь необходимо проверить масштаб игрового объекта. Настройки гравитации по умолчанию предполагают, что одна мировая единица на сцене соответствует одному метру расстояния. В нефизических играх не имеет большого значения, если все ваши модели имеют длину 100 единиц, но при использовании физики, то есть компонента Rigidbody, они будут рассматриваться как очень большие объекты. Если для объектов, которые должны быть маленькими, задается большой масштаб (Transform.Scale), то они будут падать очень медленно — физический движок думает, что это очень большие объекты, падающие с очень больших расстояний. Поэтому убедитесь, что ваши объекты более или менее соответствуют их масштабу в реальной жизни (например, автомобиль должен быть примерно 4 единицы = 4 метра).

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

Для начала давайте определим вектор перемещения для объекта с учетом действий пользователя:

float deltaX = Input.GetAxis("Horizontal");
float deltaZ = Input.GetAxis("Vertical");
Vector3 move = newVector3(deltaX, 0, deltaZ);

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

move.Normalize();

И последнее, что необходимо сделать, это умножить компоненты X и Y на переменную скорости:

movement.Set(Speed * move.x, 0, Speed * move.z);

Плавное, равномерное перемещение игрового объекта по сцене реализуется с помощью задания ему скорости (velocity) в методе FixedUpdate():

rb.velocity = movement;

Итоговый скрипт будет выглядеть следующим образом:

Скрипт перемещения
Скрипт перемещения

Теперь наш персонаж может перемещаться по плоскости следующим образом. Обратите внимание, что плоскости и персонажу добавлен компонент Collider, чтобы персонаж не улетал вниз за плоскость.

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

if (Input.GetAxis("Jump") > 0)
{
rb.AddForce(Vector3.up * JumpForce);
}

В этой записи Vector3.up определяет направление прыжка строго вверх по оси Y, а JumpForce определяет высоту прыжка.

Также необходимо внести изменения в определение вектора перемещения - сохранить вертикальную составляющую (координата Y) скорости физического тела, а не обнулять ее. Эта вертикальная появляется, когда мы прикладываем силу для прыжка:

movement.Set(Speed * move.x, rb.velocity.y, Speed * move.z);

Скрипт будет выглядеть следующим образом:

Скрипт перемещения и прыжка
Скрипт перемещения и прыжка

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

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

private bool isGround = true;

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

if (Input.GetAxis("Jump") > 0 && isGround)
{
rb.AddForce(Vector3.up * JumpForce);
isGround = false;
}

И последнее, что нужно сделать - при соприкосновении с объектом плоскости (землей) установим переменную нахождения на земле в истинное значение:

void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == ("Ground"))
{
isGround = true;
}
}

Обратите внимание, чтобы этот метод сработал необходимо, чтобы плоскости и персонажу был добавлен компонент Collider. А также у плоскости был задан тег "Ground":

Плоскость земли
Плоскость земли

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

Скрипт перемещения и прыжка
Скрипт перемещения и прыжка

Прыжок одновременно с перемещением будет выглядеть теперь следующим образом: