Rotations in 3D applications are usually represented in one of two ways, Quaternions or Euler angles. Each has its own uses and drawbacks. Unity uses Quaternions internally, but shows values of the equivalent Euler angles in the inspector to make it easy for you to edit.
Euler angles have a simpler representation, that being three angle values for X, Y and Z that are applied sequentially. To apply a Euler rotation to a particular object, each rotation value is applied in turn, as a rotation around its corresponding axis.
Quaternions can be used to represent the orientation or rotation of an object. This representation internally consists of four numbers (referenced in Unity as x, y, z & w) however these numbers don’t represent angles or axes and you never normally need to access them directly. Unless you are particularly interested in delving into the mathematics of Quaternions , you only really need to know that a Quaternion represents a rotation in 3D space and you will never normally need to know or modify the x, y & z properties.
In the same way that a Vector can represent either a position or a direction (where the direction is measured from the origin), a Quaternion can represent either an orientation or a rotation - where the rotation is measured from the rotational “origin” or “Identity ”. It because the rotation is measured in this way - from one orientation to another - that a quaternion can’t represent a rotation beyond 180 degrees.
In Unity all Game Object rotations are stored internally as Quaternions, because the benefits outweigh the limitations.
In the Transform Inspector however, we display the rotation using Euler angles, because this is more easily understood and edited. New values entered into the inspector for the rotation of a Game Object are converted “under the hood” into a new Quaternion rotation value for the object.
As a side-effect, it is possible in the inspector to enter a value of, say, X: 0, Y: 365, Z: 0 for a Game Object’s rotation. This is a value that is not possible to represent as a quaternion, so when you hit Play you’ll see that the object’s rotation values change to X: 0, Y: 5, Z: 0 (or thereabouts). This is because the rotation was converted to a Quaternion which does not have the concept of “A full 360-degree rotation plus 5 degrees”, and instead has simply been set to be oriented in the same way as the result of the rotation.
When dealing with handling rotations in your scripts, you should use the Quaternion class and its functions to create and modify rotational values. There are some situations where it is valid to use Euler angles, but you should bear in mind: - You should use the Quaternion Class functions that deal with Euler angles - Retrieving, modifying, and re-applying Euler values from a rotation can cause unintentional side-effects.
Unity’s Quaternion class has a number of functions which allow you to create and manipulate rotations without needing to use Euler angles at all. For example:
Добавление случайных элементов в игру
Сделать так, чтобы объект вращался вокруг своей оси очень просто, для этого есть функция 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 Я думаю, что я должен был исправить некоторые из значений положения/поворота, потому что я использовал BoxCollider , чтобы вызвать поворот, так что может быть лучше всего подходит.
Сортировка:
Активность
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 обрабатывает крутящий момент, но это физика путь. Если вы хотите полный контроль, вы можете установить вращение вручную, но это приводит к множеству неудобных вещей. Вам также придется изменить скорость вращения для реалистичных столкновений. Просто придерживайтесь стандартного (хотя и ошибочного) колеса и не изобретайте его повторно. У вас будет меньше головных болей.