Единство - глядя через прицел
Прямо сейчас у меня есть 2 камеры: основная камера отображает пистолет в его нормальном состоянии, а вторая камера прикреплена к пистолету (пистолет является дочерним элементом основной камеры), и при переключении он просматривает область действия пистолета и увеличивает поле зрения.
Вот визуал для лучшего понимания:
Теперь, если бы я просто включил вторую камеру и выключил основную камеру, это работало бы замечательно, но это не очень идеально. Вы должны иметь только 1 камеру на сцену.
Поэтому я хочу, чтобы Lerp положение камеры, чтобы просмотреть область и вручную уменьшить поле обзора. Итак, я написал следующий скрипт:
[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {
private Transform CameraTransform = null;
public Transform ZoomedTransform;
private bool zoomed = false;
void Start () {
CameraTransform = Camera.main.transform;
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.LeftShift))
{
CameraTransform.position = Vector3.Lerp (
CameraTransform.position,
CameraTransform.position + ZoomedTransform.position,
5f * Time.deltaTime
);
CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
}
}
}
Проблема в том, что это не работает: когда я нажимаю кнопку зума, камера перемещается по сцене со скоростью света, и трудно точно сказать, что происходит.
Кто-нибудь может дать мне некоторое представление о том, что я делаю неправильно? Я думаю, что это как-то связано с отношениями родитель-ребенок, но даже когда я пытался использовать статические значения, я не могу воспроизвести правильное решение.
Иерархия:
3 ответа
(Этот ответ работает при условии, что ZoomedTransform
является относительным преобразованием, а не абсолютным положением камеры, как подозревает ответ 31eee384.)
Я думаю, что есть несколько проблем с вашим кодом. Я рассмотрю их индивидуально, чтобы их было легче понять, но они оба относятся к следующей строке:
CameraTransform.position = Vector3.Lerp (CameraTransform.position, CameraTransform.position + ZoomedTransform.position, 5f * Time.deltaTime);
Во-первых, давайте посмотрим, как вы используете Vector3.Lerp()
, Для третьего аргумента Vector3.Lerp()
поставляешь 5f * Time.deltaTime
, Что именно это значение работает? Ну, стандартная частота кадров составляет около 60 кадров в секунду, так Time.deltaTime
= ~1/60. Следовательно, 5f * Time.deltaTime
= 5/60 = ~0,0833.
Что такое Vector3.Lerp()
ожидая третьего аргумента? Согласно документации, этот третий аргумент должен быть между 0 и 1 и определяет, будет ли возвращен Vector3
должно быть ближе к первому или второму Vector3
, Так да, 5f * Time.deltaTime
попадает в этот диапазон, но интерполяция не произойдет - потому что она всегда будет около ~0,0833, а не прогрессирует от 0 до 1 (или от 1 до 0). Каждый кадр, ты в основном всегда возвращаешься cameraPos + zoomTransform * 0.0833
,
Другая заметная проблема заключается в том, как вы обновляете значение CameraTransform.position
каждый кадр, но затем использовать это новое (увеличенное) значение в качестве аргумента для Vector3.Lerp()
следующий кадр. (Это немного похоже на int i = i + 1;
в цикле.) Это причина, почему ваша камера летит по карте так быстро. Вот что происходит в каждом кадре, используя гипотетический результат вашего Vector3.Lerp()
что я рассчитал ранее (псевдокод):
// Frame 1
cameraPosFrame_1 = cameraPosFrame_0 + zoomTransform * 0.0833;
// Frame 2
cameraPosFrame_2 = cameraPosFrame_1 + zoomTransform * 0.0833;
// Frame 3
cameraPosFrame_3 = cameraPosFrame_2 + zoomTransform * 0.0833;
// etc...
Каждый кадр, zoomTransform * 0.0833
добавляется к позиции камеры. Что в итоге приводит к очень, очень быстрому и безостановочному увеличению стоимости - так ваша камера летит по карте.
Один из способов решения этих проблем состоит в том, чтобы иметь переменные, в которых хранится исходное локальное положение вашей камеры, прогресс увеличения и скорость увеличения. Таким образом, мы никогда не теряем исходное положение камеры, и мы можем отслеживать, как далеко продвинулся зум, и когда остановить его.
[RequireComponent(typeof(Camera))]
public class Zoom : MonoBehaviour {
private Transform CameraTransform = null;
public Transform ZoomedTransform;
private Vector3 startLocalPos;
private float zoomProgress = 0;
private float zoomLength = 2; // Number of seconds zoom will take
private bool zoomed = false;
void Start () {
CameraTransform = Camera.main.transform;
startLocalPos = CameraTransform.localPosition;
}
// Update is called once per frame
void Update () {
if (Input.GetKey (KeyCode.LeftShift))
{
zoomProgress += Time.deltaTime;
CameraTransform.localPosition = Vector3.Lerp (startLocalPos, startLocalPos + ZoomedTransform.position, zoomProgress / zoomLength);
CameraTransform.Rotate(ZoomedTransform.rotation.eulerAngles);
}
}
}
Надеюсь это поможет! Дайте знать, если у вас появятся вопросы. Этот ответ немного интересен, поэтому я надеюсь, что у вас не возникнет проблем с получением важных моментов.
Ваша цель lerp относительно текущей позиции камеры, поэтому она постоянно движется. Это ваша цель:
CameraTransform.position + ZoomedTransform.position
Это означает, что когда ваша камера перемещается, чтобы приблизиться к этому положению, новое положение камеры вызывает изменение места назначения. Так что ваша камера продолжает двигаться вечно.
Ваш пункт назначения должен быть ZoomedTransform.position
, Нет необходимости в добавлении, потому что position
находится в мировых координатах. (И когда вам действительно нужно конвертировать между пробелами, проверьте TransformPoint
и аналогичные методы.)
Прошло много времени с тех пор, как я что-то делал в Unity, но я думаю, что он обрабатывает функцию Lerp во время кадра, а не в реальном времени. Вам нужно будет вызвать его в другой функции, которая не обрабатывается во время кадра.