Unity3D流畅的相机运动和外观

时间:2017-01-25 08:39:38

标签: c# unity3d camera

在我的Unity3D C#项目中卡住了相机移动。

我有什么:

  • 现场的一些物品
  • 一台相机,可以从任何物体的位置或从它自己的当前位置飞出来

我需要什么:

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

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

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

我的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);
    }
}

1 个答案:

答案 0 :(得分:1)

因为你想要实现的目标意味着一个接一个地采取行动,我建议使用 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 变量更改为转换变量,因为您始终使用它们来转到转换组件,以便您可以直接使用它< / LI>
  • 为旋转和移动添加了时间概念而不是速度概念(您也可以使用速度:只需将Time.deltaTime乘以速度因子)
  • 使用 AnimationCurve 可以调整旋转/移动的方式:只需在Inspector中设置曲线(曲线必须从(0,0)开始,到(1,1)结束)

希望这有帮助,