Unity第三人称跟随相机

可旋转缩放,检测碰撞时位移以尽量保持对象不被遮挡,话不多说,直接上代码

using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

[AddComponentMenu("Zetan/Third Person Camera Follow")]
public class CameraFollow : MonoBehaviour {

    public Transform target;
    public Vector3 headOffset = Vector3.zero;
    public bool smooth;
    public float smoothLevel = 0.5f;
    Vector3 direction;
    public float rotateSpeed = 10.0f;
    public float zoomSpeed = 5f;
    public float minDistance = 3.0f;
    public float maxDistance = 15.0f;
    public float maxLookUpAngle = 80.0f;
    public float maxLookDownAngle = 30.0f;

    [SerializeField]
    float OriginDistance;
    [SerializeField]
    float currentDistance;

    Vector3 visibleEuler;

    // Use this for initialization
    void Start() {
        ResetView();
    }

    // Update is called once per frame
    void Update() {
        visibleEuler = ConvertEulerAngle(transform.rotation.eulerAngles);
    }

    private void LateUpdate()
    {
        float h = CrossPlatformInputManager.GetAxis("Mouse X");
        float v = CrossPlatformInputManager.GetAxis("Mouse Y");
        float zoom = CrossPlatformInputManager.GetAxis("Mouse ScrollWheel");
        Translate(zoom);
        Rotate(h, v);
    }

    void Translate(float zoom)
    {
        OriginDistance -= zoom * zoomSpeed;
        OriginDistance = Mathf.Clamp(OriginDistance, minDistance, maxDistance);
        RaycastHit hit;
        if (Physics.Raycast(target.position + headOffset, transform.position - target.position - headOffset, out hit, OriginDistance,
            ~(1 << LayerMask.NameToLayer("Water") | 1 << LayerMask.NameToLayer("Player")), QueryTriggerInteraction.Ignore))//检测层依据需求更改
        {
            currentDistance = hit.distance;
        }
        else
        {
            currentDistance = OriginDistance;
        }
        Vector3 disOffset = direction.normalized * currentDistance;
        if(smooth)transform.position = Vector3.Lerp(transform.position, target.position + headOffset + disOffset, smoothLevel);//平滑移动,但累计差会导致相机逐渐回到某个特定视角,且伴随有轻微抖动
        else transform.position = target.position + headOffset + disOffset;//旋转时伴随轻微卡顿
        transform.LookAt(target);
    }

    void Rotate(float h, float v)
    {
        float finallyRotateV = v * rotateSpeed;
        if (finallyRotateV + visibleEuler.x >= maxLookUpAngle)
        {
            finallyRotateV = visibleEuler.x + finallyRotateV - maxLookUpAngle;
        }
        else if (finallyRotateV + visibleEuler.x <= -maxLookDownAngle)
        {
            finallyRotateV = visibleEuler.x + finallyRotateV + maxLookDownAngle;
        }
        //左右旋转
        transform.RotateAround(target.position + headOffset, transform.up, h * rotateSpeed);
        //上下旋转
        transform.RotateAround(target.position + headOffset, transform.right, -finallyRotateV);
        transform.LookAt(target.position + headOffset);
        direction = (transform.position - target.position - headOffset).normalized;
    }

    public float ConvertAngle(float value)
    {
        float angle = value - 180;

        if (angle > 0)
            return angle - 180;

        return angle + 180;
    }

    public Vector3 ConvertEulerAngle(Vector3 euler)
    {
        return new Vector3(ConvertAngle(euler.x), ConvertAngle(euler.y), ConvertAngle(euler.z));
    }

    public void ResetView()
    {
        if(minDistance > maxDistance)
        {
            maxDistance += minDistance;
            minDistance = maxDistance - minDistance;
            maxDistance -= minDistance;
        }
        direction = -target.forward;
        Vector3 disOffset = direction * (minDistance + maxDistance) / 2;
        transform.position = target.position + headOffset + disOffset;
        OriginDistance = disOffset.magnitude;
    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawLine(target.position + headOffset, transform.position);
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(target.position + headOffset, minDistance);
        Gizmos.DrawLine(target.position + headOffset + target.forward * minDistance, target.position + headOffset + target.forward * maxDistance);
        Gizmos.DrawLine(target.position + headOffset - target.forward * minDistance, target.position + headOffset - target.forward * maxDistance);
        Gizmos.DrawLine(target.position + headOffset + target.up * minDistance, target.position + headOffset + target.up * maxDistance);
        Gizmos.DrawLine(target.position + headOffset - target.up * minDistance, target.position + headOffset - target.up * maxDistance);
        Gizmos.DrawLine(target.position + headOffset + target.right * minDistance, target.position + headOffset + target.right * maxDistance);
        Gizmos.DrawLine(target.position + headOffset - target.right * minDistance, target.position + headOffset - target.right * maxDistance);
        Gizmos.DrawWireSphere(target.position + headOffset, maxDistance);
    }
}

猜你喜欢

转载自blog.csdn.net/hzt9565/article/details/80022368
今日推荐