Unity c вращение объекта. Вращение камеры вокруг объекта

Nokia 11.04.2019

Доброго времени суток, уважаемый читатель! На Хабре неоднократно публиковались статьи о разработке игр с использованием замечательного движка Unity3d . Большинство этих статей были посвящены вполне определенным задачам, я же хотел сделать общий экскурс в данный движок. Данная часть будет посвящена наиболее часто используемым скриптовым методам и объектам, которые используются мной в процессе разработки на данном движке. Примеры я буду приводить на JavaScript, как на наиболее близком мне языке.

Игровой объект

Создание нового игрового объекта с именем MyObject.
var myObject = new GameObject("MyObject"); Созданный объект будет доступен по ссылку myObject.

Поиск объекта по его имени.
var myObject = GameObject.Find("MyObject");

Теги можно использовать для помечания группы объектов со сходными свойствами, либо использующиеся в единой сцене.
Поиск объекта по тегу, возвращает единственный объект:
var myObject = GameObject.FindWithTag("MyTag");

Возвращает список всех объектов с указанным тегом:
var objectList = GameObject.FindGameObjectsWithTag("MyTag");

Проверка на наличие у объекта требуемого тега. Возвращает true, если у указанного объекта имеется тег MyTag:
var isCompare = GameObject.CompareTag("MyTag");

Уничтожение объекта:
Destroy(myObject);

Уничтожение объекта через минуту, после его создания:
Destroy(myObject, 60);

Возвращает компонент component, привязанный к объекту GameObject, либо null, если объект не содержит данного компонента. Может использоваться, например, для доступа к другим скриптам, привязанным к объекту.
var objectComponent = GameObject.GetComponent(component);

Возвращает все имеющиеся у объекта компоненты типа componentType.
var objectComponents = GameObject.GetComponents(componentType);

Привязать компонент myComponent к объекту GameObject и получить ссылку на него.
var component = GameObject.AddComponent(myComponent);

Положение игрового объекта

Свойство transform объекта GameObject содержит в себе данные о положении объекта в игровом мире.

Возвращает глобальные координаты объекта в игровом мире. Возвращаемая величина имеет тип Vector3, который представляет из себя список из 3 координат - x, y и z:

Var position = GameObject.transform.position; var x = position.x;

Переместить объект в точку 0, 10, 0 игрового мира.
GameObject.transform.position = Vector3(0, 10, 0);

Тоже самое, что и в случае глобальных координат, но с локальными. Локальные координаты расситываются относительно родительского объекта. В случае отсутствия родительского объекта локальные координаты совпадают с глобальными:
var localPosition = GameObject.transform.localPosition; var x = localPosition.x;

Поворот объекта в углах Эйлера . Метод также возвращает координаты в виде объекта Vector3:
var eulerAngle = GameObject.transform.eulerAngles;

Тоже самое, что и предыдущий пример, но поворот объекта рассчитывается относительно родительского объекта:
var localEulerAngle = GameObject.transform.localEulerAngles;

Текущий угол поворота объекта, основанный на кватернионах . Возвращает объект типа Quaternion.
var quaternionAngle = GameObject.transform.rotation;

Текущий поворот объекта, основанный на кватернионах, но относительно родительского объекта:
var localQuaternionAngle = GameObject.transform.localRotation;

Сброс угла поворота объекта:
GameObject.transform.rotation = Quaternion.identity; GameObject.transform.localRotation = Quaternion.identity;

Вращаем наш объект в указанную сторону со скоростью 1 градус в секунду. Принимает в качестве координат объект типа Vector3. Метод deltaTime объекта Time содержит время в секундах, затраченное на выполнение предыдущего кадра:
GameObject.transform.Rotate(Vector3.left * Time.deltaTime);

Тоже самое, что и предыдущий пример, но вращение объекта относительно координат родителя:
GameObject.transform.localRotate(Vector3.left * Time.deltaTime);

Перемещаем наш объект в указанном направлении со скоростью 1 юнит в секунду. Также принимает в качестве координат объект класса Vector3:
GameObject.transform.Translate(Vector3.up * Time.deltaTime);

Физические свойства игрового объекта

Метод rigidbody объекта GameObject хранит в себе его физические свойства. Прежде, чем использовать метод rigidbody, его необходимо добавить к игровому объекту.

Получаем/задаем вектор скорости объекта:
var velocity = GameObject.rigidbody.velocity; GameObject.rigidbody.velocity = Vector3(0, 1, 0);

Сила противодействия объекта. Может использоваться для замедления скорости, в среде с отсутствующей силой трения. Наиболее часто используется для замедления падающих объектов, например при создании парашюта. Принимает в качестве параметра целое число:
GameObject.rigidbody.drag = 100;

Влияние на объект гравитации. Принимает в качестве параметра булево значение. Позволяет отключить влияние гравитации на отдельные объекты:
GameObject.rigidbody.useGravity = false;

Влияние физики на игровой объект. Позволяет отключить частично, либо полностью влияние физических законов на объект:
GameObject.rigidbody.isKinematic = true;

Запрет на вращение объекта. Наиболее часто используется, когда необходимо сохранить определенный угол поворота даже после столкновения с другими объектами:
GameObject.rigidbody.freezeRotation = true;

Указание координат точки центра массы объекта. Применяет координаты в виде уже знакомого нам объекта Vector3.
GameObject.rigidbody.centerOfMass = Vector3(1, 0, 0);

Использовать ли для объекта обнаружение столкновений с другими объектами. Можно выключить, тогда ваш объект будет игнорировать любые столкновения:
GameObject.rigidbody.detectCollisions = false;

Режим определения столкновений между объектами. Можно указать несколько разных режимов:
CollisionDetectionMode.ContinuousDynamic для быстро движущихся объектов;
CollisionDetectionMode.Continuous для столкновений с быстро движущимися объектами;
CollisionDetectionMode.Discrete (по умолчанию) для обычных столкновений;
В случае отсутствия проблем с определением столкновений рекомендуется использовать свойство по умолчанию.

Задать плотность объекта:
GameObject.rigidbody.SetDensity(1.5);

Применить импульс к объекту с указанным вектором. В результате применения импульса объект придет в движение пропорционально силе импульса.
GameObject.rigidbody.AddForce(5, 0, 0);

Применить импульс к объекту с вектором в его (объекта) системы координат:
GameObject.rigidbody.AddRelativeForce(0, 0, 5);

Добавить объекту крутящий момент. Применение данного метода заставит объект вращаться вокруг своего центра масс GameObject.rigidbody.centerOfMass.
GameObject.rigidbody.AddTorque(0, 1, 0);

Тоже самое, что и предыдущий пример, но относительно координат объекта:
GameObject.rigidbody.AddRelativeTorque (1, 0, 0);

Применение импульса к объекту из внешней указанной точки. Заставляет объект двигаться и вращаться одновременно. Может использоваться, например, для симуляции попадания в объект пули. Первый параметр указывает вектор направления силы, второй параметр - исходную точку направления силы.
GameObject.rigidbody.AddForceAtPosition(Vector3(0, 5, 7), Bomb.transform.position);

Для полноценной симуляции объемных взрывов в Unity3D есть отдельный метод. Первый параметр метода позволяет указать мощность импульса, второй параметр - точку, из которой исходит импульс, третий параметр - радиус распространения импульса, четвертый параметр - модификатор сжатия сферы распространения силы, пятый, необязательный, параметр указывает тип используемого импульса:
GameObject.rigidbody.AddExplosionForce(power, explosionPos, radius, 2.0);

Заставить объект «уснуть», и запретить дальнейший расчет физических показателей для него:
GameObject.rigidbody.Sleep();

Проверить «заснул» ли объект:
GameObject.rigidbody.IsSleeping();

«Разбудить» объект для возможности дальнейшего применения влияния физики на него:
GameObject.rigidbody.WakeUp();

Трассировка лучей

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

Создаем объект класса RaycastHit, который содержит информацию об объекте, с которым столкнулся луч:
var hit: RaycastHit;

Отправляем луч длиной в 50 юнитов из позиции rayPosition в направлении rayVector, и заносим объект, с которым столкнулся луч в переменную hit:
Physics.Raycast(rayPosition, rayVector.forward, hit, 50);

Получаем дистанцию до объекта, с которым столкнулся луч. Дистанция не может быть больше, чем протяженность луча:
var distance = hit.distance;

Иногда бывает необходимо получить имя объекта, с которым произошло столкновение луча. Наиболее простой способ это сделать:
var objectName = hit.collider.gameObject.name;

Для получения тега объекта используем следующий способ:
var Tag = hit.collider.tag;

Unity3D содержит еще множество различных методов и объектов, полезных и не очень. К сожалению полный их обзор увеличил бы и без того объемную статью, поэтому я постараюсь рассказать об остальном более подробно в будущем, если мне представится такая возможность. Я бы хотел пожелать опытным разработчикам побольше интересных проектов, а начинающим - успехов и интересных открытий. Спасибо, что уделили внимание данной статье.

Сделать так, чтобы объект вращался вокруг своей оси очень просто, для этого есть функция Rotate. Кроме обычного вращения, еще можно сделать орбиту, по которой будет задано вращение относительно другого объекта, здесь поможет функция RotateAround, достаточно указать цель, ось и скорость. Но что если, нужно чтобы вращение управлялось с помощью мышки? Например, есть некая планета и надо, чтоб камера крутилась вокруг нее. Именно это мы попробуем реализовать в сегодняшнем скрипте. Дополнительно, сделаем небольшую модификацию, чтобы вращение какого-нибудь объекта тоже управлялось мышкой.

C# скрипт CameraRotateAround:

Using UnityEngine; using System.Collections; public class CameraRotateAround: MonoBehaviour { public Transform target; public Vector3 offset; public float sensitivity = 3; // чувствительность мышки public float limit = 80; // ограничение вращения по Y public float zoom = 0.25f; // чувствительность при увеличении, колесиком мышки public float zoomMax = 10; // макс. увеличение public float zoomMin = 3; // мин. увеличение private float X, Y; void Start () { limit = Mathf.Abs(limit); if(limit > 90) limit = 90; offset = new Vector3(offset.x, offset.y, -Mathf.Abs(zoomMax)/2); transform.position = target.position + offset; } void Update () { if(Input.GetAxis("Mouse ScrollWheel") > 0) offset.z += zoom; else if(Input.GetAxis("Mouse ScrollWheel") < 0) offset.z -= zoom; offset.z = Mathf.Clamp(offset.z, -Mathf.Abs(zoomMax), -Mathf.Abs(zoomMin)); X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity; Y += Input.GetAxis("Mouse Y") * sensitivity; Y = Mathf.Clamp (Y, -limit, limit); transform.localEulerAngles = new Vector3(-Y, X, 0); transform.position = transform.localRotation * offset + target.position; } }
Итак, у нас тут есть цель target , вокруг которой будем крутить камеру. Чувствительность мышки, регулируется переменной - sensitivity . И конечно же, предусмотрено смещение offset , на старте, нужно установить позицию таргета и добавить смещение. По поводу, limit , это ограничение по оси Y , если значение будет больше 90, то картинка начнет глючить, поэтому присутствует страховка. Вешаем скрипт на камеру, указываем объект + смещение и собственно смотрим, что получилось.

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

Назовем его ObjectRotate:

Using UnityEngine; using System.Collections; public class ObjectRotate: MonoBehaviour { public float sensitivity = 3; // чувствительность мышки private float X, Y; void Update () { X = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivity; Y += Input.GetAxis("Mouse Y") * sensitivity; Y = Mathf.Clamp (Y, -90, 90); transform.localEulerAngles = new Vector3(-Y, X, 0); } }
Этот скрипт вешаем на тот объект, который хотим вращать.

3

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

Вот код, у меня есть для перемещения объекта вперед:

Velocity += (_velocity * Time.deltaTime) + (_acceleration/2f) * Time.deltaTime * 2f; _velocity = Mathf.Clamp(_velocity, 0f, MaxVelocity); Vector3 position = this.transform.position; position += -this.transform.forward * _velocity * Time.deltaTime; this.transform.position = position;

Переменные объявляются как члены класса:

Private const float MaxVelocity = 10; private float _velocity; private float _acceleration;

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

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

Я пробовал несколько вариантов, за бесчисленные часы, но мне не повезло!

Любые идеи?

UPDATE # 1 :

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

Из-за того, что я разработал вращение LERP с текущего направления в новое направление, сделал трюк (вид!). Итак, я создал поведение называется VehicleController и в методе Awake я добавил следующее:

Target = this.transform.rotation * Quaternion.Euler(0f, 90f, 0f);

Это дало мне цель вращение относительно моего текущего вращения, то есть мое вращение было бы равным _target для меня, чтобы быть лицом в желаемое направление. Затем я добавил следующее к методу FixedUpdate:

// Rotate if(_doTurn) { this.transform.rotation = Quaternion.Lerp(this.transform.rotation, _target, Time.fixedDeltaTime * _velocity); }

Это выполняется фактическое вращение. Ключевой частью была установка третьего параметра Time.fixedDeltaTime * _velocity . Это означало, что моя скорость вращения соответствовала моей скорости.

Мой последний FixedUpdate метод выглядел следующим образом:

// Forward _velocity += (_velocity * Time.deltaTime) + (_acceleration/2f) * Time.fixedDeltaTime * 2f; _velocity = Mathf.Clamp(_velocity, 0f, MaxVelocity); Vector3 position = this.transform.position; position += -this.transform.forward * _velocity * Time.fixedDeltaTime; this.transform.position = position; // Rotate if(_doTurn) { this.transform.rotation = Quaternion.Lerp(this.transform.rotation, _target, Time.fixedDeltaTime * _velocity); }

В этом примере я имел BoxCollider , который вызвал поворот, так что в методе OnTriggerEnter я просто установить _doTurn в true .

В настоящее время существует несколько вещей с этим:

  1. После поворота я должен был исправить позиционирование и немного вращения. Значения были примерно на 0,2, но я не мог заметить каких-либо странностей.
  2. Этот подход дает быстрое сменное изменение в направлении, которое не было тем, чем я действительно был после.В идеале мне нужна была ситуация, когда поворот был бы постепенным под определенным углом и заканчивался бы в той же точке. Но, честно говоря, все выглядит нормально, и теперь меня заставляет двигаться дальше! :)

Что касается # 1 Я думаю, что я должен был исправить некоторые из значений положения/поворота, потому что я использовал BoxCollider , чтобы вызвать поворот, так что может быть лучше всего подходит.

  • 1 ответ
  • Сортировка:

    Активность

1

Самый простой способ повернуть объект в направлении его скорости - представлять поворот в качестве вектора. Физика Юнити делает это внутренне, но, к сожалению, не позволит вам получить доступ к любой из этих переменных. Вместо этого вы можете просто применить Torque, который сделает все для вас (неплохо использовать физический движок и самостоятельно применять физику).

Сначала получите требуемое вращение.

Vector3 DesiredRotation = Quaternion.LookRotation(rigidbody.Velocity).EulerAngles;

Затем найти вращение вам нужно повернуть, чтобы попасть:

Vector3 RotationSteering = DesiredRotation - rigidbody.rotation;

Normalize RotationSteering так что вы можете получить больше контроля над степенью вращения:

RotationSteering.Normalize();

Multiply вращения управляя любой суммой, на которую вы хотите повернуть.

RotationSteering *= 30;

Применить силу затем $:

Rigidbody.AddTorque (RotationSteering);

Я не уверен, как Unity обрабатывает крутящий момент, но это физика путь. Если вы хотите полный контроль, вы можете установить вращение вручную, но это приводит к множеству неудобных вещей. Вам также придется изменить скорость вращения для реалистичных столкновений. Просто придерживайтесь стандартного (хотя и ошибочного) колеса и не изобретайте его повторно. У вас будет меньше головных болей.



Рекомендуем почитать

Наверх