Unity第三人称跟随相机

记得导入StandardAssets资源包中CrossPlatformInput相关的文件才能用。

不是很完善,有个视角快速从头顶看过时,旋转方向错乱的bug,但是基本上可旋转缩放,检测碰撞时位移以尽量保持对象不被遮挡,可选固定或单轴旋转,话不多说,直接上代码

using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

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

    public enum RotateType
    {
        UableRotate,
        HorizontalOnly,
        VerticalOnly,
        Both
    }

    public enum UpdateType
    {
        LateUpdate,
        FixedUpdate,
        Update
    }

    public Transform target;
    public Vector3 headOffset = new Vector3(0, 1.7f, 0);
    public LayerMask ignoreLayer;
    public UpdateType updateType;
    public bool smooth;
    [Range(0.1f, 1f)] public float smoothLevel = 0.5f;
    public RotateType rotateType;
    public float rotateSpeed = 10.0f;
    public float zoomSpeed = 5f;
    public float minDistance = 3.0f;
    public float maxDistance = 15.0f;
    public float maxLookUpAngle = 70.0f;
    public float maxLookDownAngle = 30.0f;

    float OriginDistance;
    float currentDistance;
    Vector3 direction;
    Vector3 disOffset;
    Vector3 visibleEuler;

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

    // Update is called once per frame
    void Update() {
        if(updateType==UpdateType.Update)
        {
            visibleEuler = ConvertEulerAngle(transform.rotation.eulerAngles);
            float h = CrossPlatformInputManager.GetAxis("Mouse X");
            float v = CrossPlatformInputManager.GetAxis("Mouse Y");
            float zoom = CrossPlatformInputManager.GetAxis("Mouse ScrollWheel");
            Translate(zoom);
            Rotate(h, v);
        }
    }

    private void LateUpdate()
    {
        if (updateType == UpdateType.LateUpdate)
        {
            visibleEuler = ConvertEulerAngle(transform.rotation.eulerAngles);
            float h = CrossPlatformInputManager.GetAxis("Mouse X");
            float v = CrossPlatformInputManager.GetAxis("Mouse Y");
            float zoom = CrossPlatformInputManager.GetAxis("Mouse ScrollWheel");
            Translate(zoom);
            Rotate(h, v);
        }
    }

    private void FixedUpdate()
    {
        if (updateType == UpdateType.FixedUpdate)
        {
            visibleEuler = ConvertEulerAngle(transform.rotation.eulerAngles);
            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,
            ~ignoreLayer, QueryTriggerInteraction.Ignore))//检测层依据需求更改
        {
            currentDistance = hit.distance;
        }
        else
        {
            currentDistance = OriginDistance;
        }
        disOffset = direction.normalized * currentDistance;
        if(smooth && rotateType==RotateType.Both) transform.position = Vector3.Lerp(transform.position, target.position + headOffset + disOffset, smoothLevel);//平滑移动,但累计差会导致相机逐渐回到某个特定视角,且伴随有轻微抖动
        else transform.position = target.position + headOffset + disOffset;//旋转时伴随轻微卡顿
        transform.LookAt(target.position + headOffset);
        disOffset = Vector3.zero;
    }

    void Rotate(float h, float v)
    {
        if (rotateType != RotateType.UableRotate)
        {
            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;
            }           
            if (rotateType == RotateType.Both)
            {
                //左右旋转
                transform.RotateAround(target.position + headOffset, transform.up, h * rotateSpeed);
                //上下旋转
                transform.RotateAround(target.position + headOffset, transform.right, -finallyRotateV);
            }
            else if (rotateType == RotateType.HorizontalOnly)
            {
                transform.RotateAround(target.position + headOffset, Vector3.up, h * rotateSpeed);
            }
            else if (rotateType == RotateType.VerticalOnly)
            {
                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;
        }
        if (rotateType == RotateType.VerticalOnly || rotateType == RotateType.Both) direction = -target.forward;
        else direction = new Vector3(1, 1, -1).normalized;
        disOffset = direction * (minDistance + maxDistance) / 2;
        transform.position = target.position + headOffset + disOffset;
        OriginDistance = disOffset.magnitude;
        disOffset = Vector3.zero;
    }

    public void SetTarget(Transform new_target)
    {
        target = new_target;
    }

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

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

莫需要

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值