繁体   English   中英

Unity3D 平滑的相机移动和外观

[英]Unity3D smooth camera movement and lookAt

在我的 Unity3D C# 项目中遇到相机移动问题。

我拥有的:

  • 现场的一些物体
  • 一个相机,它会从任何物体的位置或它自己的当前位置飞行

我需要的:

  • 平滑旋转相机到物体的原点之一
  • 飞到物体附近的地方(有一个空的,所以我飞到空的坐标)

算法:旋转到物体的原点,旋转完成后,开始飞到空的位置。 飞行时,观察物体的起源。

问题是它不流畅,相机在运动结束时“跳跃”。

我的 C# 代码(附加到相机):

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class testMove : MonoBehaviour {
    public GameObject startObj;
    public GameObject endObj;    
    public float speed = 1.0F;
    private float startTime;
    private float journeyLength;
    private string endObjName;
    private GameObject endObjLookAt;
    void Start () {
        startTime = Time.time;        
        if (startObj) {            
        } else {
            startObj = this.gameObject;
        }       
        journeyLength = Vector3.Distance(startObj.transform.position, endObj.transform.position);        
        endObjName = endObj.name;
        endObjLookAt = GameObject.Find(endObjName + "LookAt");
    }   

    void Update () {
        if (endObj) {            
            float distCovered = (Time.time - startTime) * speed;
            float fracJourney = distCovered / journeyLength;
            tweenLook(endObjLookAt, fracJourney);
            float angle = Quaternion.Angle(transform.rotation, Quaternion.LookRotation(endObjLookAt.transform.position - transform.position));            
            if (angle <= 0.0001) { 
                Debug.Log("rotation finished");
                tweenPos(startObj, endObj, fracJourney);
                transform.LookAt(endObjLookAt.transform.position);                
            }
        }
    }

    private void tweenPos(GameObject startObj, GameObject endObj, float fracJourney) {
        Vector3 newposition = Vector3.Lerp(startObj.transform.position, endObj.transform.position, fracJourney);        
        transform.position = newposition;        
    }

    private void tweenLook(GameObject endObjLookAt, float fracJourney) {
        Quaternion newrotation = Quaternion.LookRotation(endObjLookAt.transform.position - transform.position);
        transform.rotation = Quaternion.Slerp(transform.rotation, newrotation, fracJourney);
    }
}

由于您要实现的目标意味着一个接一个地执行操作,因此我建议使用Coroutine

public class testMove : MonoBehaviour
{
    public Transform startObj;
    public Transform endObj;
    private Transform endObjLookAt;

    public float rotationDuration;
    public AnimationCurve rotationCurve;

    public float movementDuration;
    public AnimationCurve movementCurve;

    private IEnumerator moveAndRotateCameraIEnumerator;

    void Start()
    {
        // If you want to do it on start just call MoveAndRotateCamera() here, else call if from anywhere you want (a script, a game button, ...)
    }

    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            MoveAndRotateCamera();
        }
    }

    public void MoveAndRotateCamera(Transform startTransform = null, Transform endTransform = null)
    {
        if(startTransform)
        {
            startObj = startTransform;
        }
        else
        {
            startObj = this.transform;
        }

        if(endTransform)
        {
            endObj = endTransform;
        }
        endObjLookAt = GameObject.Find(endObj.name + "LookAt").transform;

        if(moveAndRotateCameraIEnumerator != null)
        {
            StopCoroutine(moveAndRotateCameraIEnumerator);
        }
        moveAndRotateCameraIEnumerator = MoveAndRotateCameraCoroutine();
        StartCoroutine(moveAndRotateCameraIEnumerator);
    }

    private IEnumerator MoveAndRotateCameraCoroutine()
    {
        //ROTATION
        Vector3 startEulerAngles = transform.eulerAngles;
        transform.LookAt(endObjLookAt);
        Vector3 deltaEulerAngles = new Vector3(Mathf.DeltaAngle(startEulerAngles.x, transform.eulerAngles.x), Mathf.DeltaAngle(startEulerAngles.y, transform.eulerAngles.y), Mathf.DeltaAngle(startEulerAngles.z, transform.eulerAngles.z));

        Debug.Log("Starting rotation...");
        float timer = 0.0f;
        while(timer < rotationDuration)
        {
            timer += Time.deltaTime;
            transform.eulerAngles = startEulerAngles + deltaEulerAngles * rotationCurve.Evaluate(timer / rotationDuration);
            yield return new WaitForEndOfFrame();
        }
        transform.eulerAngles = startEulerAngles + deltaEulerAngles;
        Debug.Log("Rotation done!");
        //----

        //MOVEMENT
        Vector3 startPosition = transform.position;

        Debug.Log("Starting movement...");
        timer = 0.0f;
        while(timer < movementDuration)
        {
            timer += Time.deltaTime;
            transform.position = Vector3.Lerp(startPosition, endObj.position, movementCurve.Evaluate(timer / movementDuration));
            transform.LookAt(endObjLookAt);
            yield return new WaitForEndOfFrame();
        }
        transform.position = endObj.position;
        transform.LookAt(endObjLookAt);
        Debug.Log("Movement done!");
        //----
    }
}

请注意以下几点:

  • 将您的GameObject变量更改为Transform变量,因为您总是使用它们来获取Transform组件,因此您可以直接使用它
  • 为旋转和移动添加了时间概念而不是速度概念(您也可以使用速度代替:只需将Time.deltaTime乘以您的速度系数)
  • 使用AnimationCurve允许您调整旋转/移动发生的方式:只需在 Inspector 中设置曲线(曲线必须从 (0, 0) 开始并在 (1, 1) 结束)

希望这可以帮助,

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM