Unity相机环绕,移动,缩放脚本

Unity相机环绕,移动,缩放脚本

环绕限制高低
缩放限制大小

unity结构示意图请添加图片描述

using DG.Tweening;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;

public class FXCameraControl : MonoBehaviour
{
    private const string MOUSESCROLLWHEEL = "Mouse ScrollWheel"; // 鼠标滚轮.
    private const string MOUSEX = "Mouse X";
    private const string MOUSEY = "Mouse Y";

    [Header("---------------基础---------------")]
    public bool isDrawGizmos = true;
    public Transform operatingTrn;  //操作点
    public Transform cameraTrn;     //相机
    public CamModel camModel = CamModel.WorldRoaming;
    [Header("-----世界漫游-----")]
    public float SJ_Zoom_Min = 2f;
    public float SJ_Zoom_Max = 30f;
    [Header("-----作业面视角-----")]
    public float ZYM_Zoom_Min = 6f;
    public float ZYM_Zoom_Max = 18f;
    public float ZYM_Radius = 5f; //作业面半径

    [Header("---------------缩放---------------")]
    public float currentZoomDistance;   //初始距离||移动时距离
    public float minZoomDistance = 2f;       //最小缩放距离
    public float maxZoomDistance = 3f;       //最大缩放距离
    public float zoomSpeed = 5f;             //缩放速度    

    [Header("---------------移动---------------")]
    public float moveSpeed = 0.3f;             //移动速度    

    [Header("---------------旋转---------------")]
    public float rotateSpeed = 1f;           //旋转速度
    public float minCamHeight = 0.1f;          //最小相机高度
    public float maxCamHeight = 25f;          //最大相机高度
    public float currentCamHeight;      //当前相机高度

    [Header("---------------private---------------")]
    [SerializeField]
    private int segments = 32;       //圆的线段数
    [SerializeField]
    private float angle;        //当前角度
    [SerializeField]
    private float camRadius;       //圆半径
    [SerializeField]
    private Vector3 operatingResetPos;   //操作点重置位置
    [SerializeField]
    private Vector3 cameraResetPos;   //相机重置位置
    [SerializeField]
    private bool isResetPosEnd = true; //是否重置结束

    private void Start()
    {
        Init();
    }

    private void LateUpdate()
    {
        //实时更新用到的参数,同步操作
        UpdateParameter();

        if (isResetPosEnd)
        {
            UpdateZoom();
            UpdateMove();
            UpdateRotate();
        }

        LookAtOperatingTrn();
        DebugDrawLine();
    }

    private void OnDrawGizmos()
    {
        if (!isDrawGizmos) return;
        DebugDrawCircle(segments, operatingTrn.position, camRadius, currentCamHeight);
        DebugDrawCircle(segments, operatingTrn.position, ZYM_Radius, operatingTrn.position.y);
    }

    private void Init()
    {
        ModelInit();
        //初始距离
        currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
        //初始半径
        camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
        //初始高度
        currentCamHeight = cameraTrn.position.y;
        //重置角度
        AngleRefersh();
        //获取相机和操作点重置位置
        operatingResetPos = operatingTrn.position;
        cameraResetPos = cameraTrn.position;
    }

    private void ModelInit()
    {
        switch (camModel)
        {
            case CamModel.WorldRoaming:
                //世界漫游
                minZoomDistance = SJ_Zoom_Min;
                maxZoomDistance = SJ_Zoom_Max;
                break;
            case CamModel.WorkingSurface:
                //作业面
                operatingTrn.position = Vector3.zero;
                minZoomDistance = ZYM_Zoom_Min;
                maxZoomDistance = ZYM_Zoom_Max;
                break;
            default:
                break;
        }
    }

    private void AngleRefersh()
    {
        // 计算当前相机位置在物体的水平面上的投影点
        Vector3 projectPos = new Vector3(cameraTrn.position.x, operatingTrn.position.y, cameraTrn.position.z);

        Vector3 v1 = new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z) - new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z);
        // 计算当前相机位置相对于物体中心的水平旋转角度
        float horizontalAngle = Vector3.Angle(Vector3.right, projectPos - operatingTrn.position);

        if (cameraTrn.position.z <= 0)
        {
            angle = 360 - horizontalAngle;
        }
        else
        {
            angle = horizontalAngle;
        }
    }

    public void ChangeCamModel(CamModel _camModel)
    {
        camModel = _camModel;
        Debug.Log("当前相机模式:" + camModel);
        ModelInit();
        UpdateParameter();
        Rotate();
        Zoom();
    }

    private void UpdateParameter()
    {
        camRadius = Vector2.Distance(new Vector2(operatingTrn.position.x, operatingTrn.position.z), new Vector2(cameraTrn.position.x, cameraTrn.position.z));
        currentCamHeight = Mathf.Clamp(cameraTrn.position.y, minCamHeight, maxCamHeight);
        currentZoomDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position);
    }

    private void UpdateZoom()
    {
        if (Input.mouseScrollDelta.y != 0)
        {
            Zoom();
        }
    }

    private void UpdateMove()
    {
        if (camModel == CamModel.WorkingSurface) return;

        if (Input.GetMouseButton(0))
        {
            Move();
        }
    }

    private void UpdateRotate()
    {
        if (Input.GetMouseButton(1))
        {
            Rotate();
            //防止在旋转视角时候,使得相机缩放超出最大最小距离
            Zoom();
        }
    }

    private void Zoom()
    {
        //鼠标滑轮值
        float scrollWheelValue = Input.GetAxis(MOUSESCROLLWHEEL);

        //更新当前距离
        currentZoomDistance = currentZoomDistance - (scrollWheelValue * zoomSpeed);

        // 计算A点到B点的向量
        Vector3 vectorAB = cameraTrn.position - operatingTrn.position;

        // 将向量AB归一化
        Vector3 normalizedVectorAB = vectorAB.normalized;

        //限制距离
        currentZoomDistance = Mathf.Clamp(currentZoomDistance, minZoomDistance, maxZoomDistance);

        // 计算新的A点到B点的距离
        float newDistance = Vector3.Distance(operatingTrn.position, cameraTrn.position) - currentZoomDistance;

        // 计算新的A点的位置
        Vector3 newpointA = cameraTrn.position - normalizedVectorAB * newDistance;

        //限制高度
        currentCamHeight = Mathf.Clamp(newpointA.y, minCamHeight, maxCamHeight);

        //更新位置
        cameraTrn.transform.position = new Vector3(newpointA.x, currentCamHeight, newpointA.z);
    }

    private void Move()
    {
        float deltaX = Input.GetAxis(MOUSEX) * moveSpeed;
        float deltaY = Input.GetAxis(MOUSEY) * moveSpeed;
        Vector3 newPosX = -deltaX * cameraTrn.right;
        Vector3 newPosY = -deltaY * cameraTrn.forward;
        operatingTrn.position += new Vector3(newPosX.x, 0, newPosX.z);
        operatingTrn.position += new Vector3(newPosY.x, 0, newPosY.z);
    }

    private void Rotate()
    {
        float deltaX = Input.GetAxis(MOUSEX) * rotateSpeed;
        float deltaY = Input.GetAxis(MOUSEY) * rotateSpeed;

        currentCamHeight = Mathf.Clamp(cameraTrn.position.y - deltaY, minCamHeight, maxCamHeight);

        angle -= deltaX;
        while (angle > 360.0f)
        {
            angle -= 360.0f;
        }

        float x = operatingTrn.position.x + camRadius * Mathf.Cos(angle * Mathf.Deg2Rad);
        float z = operatingTrn.position.z + camRadius * Mathf.Sin(angle * Mathf.Deg2Rad);
        float y = currentCamHeight;
        cameraTrn.position = new Vector3(x, y, z);
    }

    private void LookAtOperatingTrn()
    {
        switch (camModel)
        {
            case CamModel.WorldRoaming:

                cameraTrn.LookAt(operatingTrn);

                break;
            case CamModel.WorkingSurface:

                Vector3 targetPos = GetWorkingSurfaceLookArPos();
                cameraTrn.LookAt(targetPos);

                break;
            default:
                break;
        }

    }

    public void CameraResetPos()
    {
        isResetPosEnd = false;
        operatingTrn.DOMove(operatingResetPos, 1f);
        cameraTrn.DOMove(cameraResetPos, 1f).onComplete += () =>
        {
            isResetPosEnd = true;
            AngleRefersh();
        };
    }

    private Vector3 GetWorkingSurfaceLookArPos()
    {
        float distance = 60;

        Vector2 center = new Vector2(operatingTrn.position.x, operatingTrn.position.z);

        Vector2 pointA = new Vector2(cameraTrn.position.x, cameraTrn.position.z);

        Vector3 pointB_V3 = (new Vector3(operatingTrn.position.x, 0, operatingTrn.position.z) - new Vector3(cameraTrn.position.x, 0, cameraTrn.position.z)).normalized * distance;

        Vector2 pointB = new Vector2(pointB_V3.x, pointB_V3.z); 

        Vector3 intersectionPos = GetIntersectionPos(pointA, pointB, center, ZYM_Radius);

        if (isDrawGizmos)
        {
            Debug.DrawLine(new Vector3(pointA.x, 0, pointA.y), pointB_V3, Color.red);
            Debug.DrawLine(cameraTrn.position, intersectionPos, Color.blue);
            Debug.DrawLine(cameraTrn.position, new Vector3(pointA.x, 0, pointA.y), Color.red);
        }

        return intersectionPos;
    }

    private Vector3 GetIntersectionPos(Vector2 pointA, Vector2 pointB, Vector2 center, float radius)
    {
        Vector2 direction = pointB - pointA;
        float a = Vector2.Dot(direction, direction);
        float b = 2 * Vector2.Dot(direction, pointA - center);
        float c = Vector2.Dot(pointA - center, pointA - center) - radius * radius;
        float discriminant = b * b - 4 * a * c;
        Vector2 intersection1;
        Vector2 intersection2;
        if (discriminant >= 0)
        {
            float t1 = (-b + Mathf.Sqrt(discriminant)) / (2 * a);
            float t2 = (-b - Mathf.Sqrt(discriminant)) / (2 * a);
            intersection1 = pointA + t1 * direction;
            intersection2 = pointA + t2 * direction;
            //Debug.Log("Intersection 1: " + intersection1);
            //Debug.Log("Intersection 2: " + intersection2);
            return new Vector3(intersection1.x, 0, intersection1.y);
        }
        else
        {
            Debug.Log("没有交点");
        }
        return Vector3.zero;
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(10, 600, 200, 60), "切换相机模式"))
        {
            ChangeCamModel(camModel == CamModel.WorkingSurface ? CamModel.WorldRoaming : CamModel.WorkingSurface);
        }
        //if (GUI.Button(new Rect(10, 100, 200, 60), "重置位置"))
        //{
        //    CameraResetPos();
        //}
    }

    private void DebugDrawLine()
    {
        Debug.DrawLine(operatingTrn.position, cameraTrn.position, Color.green);

        //Debug.DrawLine(Vector3.zero, Vector3.right * 30, Color.blue);
    }

    public void DebugDrawCircle(int _segments, Vector3 _center, float _radius, float _height = 0)
    {
        _center = new Vector3(_center.x, _height, _center.z);
        Gizmos.color = Color.yellow;
        float anglePerSegment = 360.0f / _segments;
        Vector3 start = _center + _radius * Vector3.right;
        Vector3 end = start;
        for (int i = 0; i < _segments; i++)
        {
            end = _center + Quaternion.Euler(0.0f, anglePerSegment, 0.0f) * (end - _center).normalized * _radius;
            Gizmos.DrawLine(start, end);
            start = end;
        }
        Gizmos.DrawLine(end, _center + _radius * Vector3.right);
    }

}
public enum CamModel
{
    /// <summary> 世界漫游 </summary>
    WorldRoaming,
    /// <summary> 作业面 </summary>
    WorkingSurface,
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值