カメラ制御スクリプト

カメラ制御スクリプト(2つのモード)

コードは以下のように表示されます。

/*****************************************************************
*Copyright(C) 2021 by DefaultCompany 
 *All rights reserved. 
 *FileName:CameraControlScript.cs 
 *Author:#小菜鸟#
 *Version:1.0 
 *UnityVersion:#2020.3.1#
 *Date:2023-03-24 
 *Description:    摄像机常用,两种模式,
 *自由模式(鼠标右键旋转视角,WASD前后左右)
 *鼠标模式(鼠标右键转动视角,鼠标左键按住移动位置),默认是无模式
 *包括聚焦功能,需要配合RuntimeGizmo插件使用,不需要可以注释掉
 *History:
*******************************************************************/
using System.Collections.Generic;
using UnityEngine;
using Zhen;

namespace Common
{
    
    
    public class CameraControlScript : MonoBehaviour
    {
    
    
        public CameraMode cameraMode;
        public float freedomSpeed = 50f;//自由模式移动速度
        public float mouseSpeed = 5f; //鼠标模式移动速度
        public float wheelSpeed = 5f;//鼠标滚轮缩放速度
        public float rotateSpeed = 90.0f;//摄像机旋转速度
        public float yMinLimit = -30;//摄像机上下最小角度
        public float yMaxLimit = 30;//摄像机上下最大角度
        private float x = 0.0f;
        private float y = 0.0f;

        private void Start()
        {
    
    
            var angles = transform.eulerAngles;
            x = angles.y;
            y = angles.x;
        }

        void Update()
        {
    
    
            Viewpoint();
            //F按键聚焦
            if (Input.GetKeyDown(KeyCode.F) && target)
            {
    
    
                Focus(target.gameObject);
            }
        }

        private void LateUpdate()
        {
    
    
            Wheel();
            switch (cameraMode)
            {
    
    
                case CameraMode.自由模式:
                    Freedom();
                    break;
                case CameraMode.鼠标模式:
                    MouseControl();
                    break;
                default:
                    break;
            }
            if (isAligning)//表示是否处于聚焦过程
            {
    
    
                AutoAlignView();
            }
        }

        /// <summary>
        /// 摄像机模式设置方法
        /// </summary>
        /// <param name="mode"></param>
        public void SetCameraModeType(CameraMode mode)
        {
    
    
            cameraMode = mode;
        }

        #region ###全局使用鼠标右键转动,鼠标中键缩放
        Vector2 inputAxis = new Vector2(); //鼠标输入
        /// <summary>
        /// 鼠标右键控制视角转动
        /// </summary>
        public void Viewpoint()
        {
    
    
            if (Input.GetMouseButton(1))
            {
    
    
                var angles = transform.eulerAngles;
                x = angles.y;
                y = angles.x;
                inputAxis = new Vector2(Input.GetAxis("Mouse X"), Input.GetAxis("Mouse Y"));
                x += inputAxis.x * rotateSpeed * 0.02f;
                y -= inputAxis.y * rotateSpeed * 0.02f;
                y = ClampAngle(y, yMinLimit, yMaxLimit);
                var rotation = Quaternion.Euler(y, x, 0);
                transform.rotation = rotation;
            }
        }

        /// <summary>
        /// 限制视角
        /// </summary>
        /// <param name="angle"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <returns></returns>
        private float ClampAngle(float angle, float min, float max)
        {
    
    
            if (angle < -360)
            {
    
    
                angle += 360;
            }
            if (angle > 360)
            {
    
    
                angle -= 360;
            }
            return Mathf.Clamp(angle, min, max);
        }

        /// <summary>
        /// 鼠标滚轮控制摄像机缩放
        /// </summary>
        void Wheel()
        {
    
    
            //如果先接触的是UI就return 不执行额外点击事件
            if (CommonFuncScript.Instance.CheckGuiRaycastObjects())
                return;
            //获取鼠标滚轮的滑动量
            float wheel = Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * 1000;
            //改变相机的位置
            transform.Translate(Vector3.forward * wheel * wheelSpeed);
        }
        #endregion

        #region ###摄像机自由模式
        private void Freedom()
        {
    
    
            //w键前进  
            if (Input.GetKey(KeyCode.W))
            {
    
    
                transform.Translate(new Vector3(0, 0, freedomSpeed * Time.deltaTime), transform);
            }
            //s键后退  
            if (Input.GetKey(KeyCode.S))
            {
    
    
                transform.Translate(new Vector3(0, 0, -1 * freedomSpeed * Time.deltaTime), transform);
            }
            //a键后退  
            if (Input.GetKey(KeyCode.A))
            {
    
    
                transform.Translate(new Vector3(-1 * freedomSpeed * Time.deltaTime, 0, 0), transform);
            }
            //d键后退  
            if (Input.GetKey(KeyCode.D))
            {
    
    
                transform.Translate(new Vector3(Time.deltaTime * freedomSpeed, 0, 0), transform);
            }
            if (Input.GetKey(KeyCode.Q))
            {
    
    
                transform.Translate(new Vector3(0, Time.deltaTime * freedomSpeed, 0), transform);
            }
            if (Input.GetKey(KeyCode.E))
            {
    
    
                transform.Translate(new Vector3(0, -1 * Time.deltaTime * freedomSpeed, 0), transform);
            }
            Limit();
        }
        float limity = 2;
        /// <summary>
        /// 限制移动
        /// </summary>
        private void Limit()
        {
    
    
            if (transform.position.y < limity)
            {
    
    
                transform.position = new Vector3(transform.position.x, limity, transform.position.z);
            }
        }
        #endregion

        #region ###摄像机鼠标模式
        void MouseControl()
        {
    
    
            if (Input.GetMouseButton(2))
            {
    
    
                float _mouseX = Input.GetAxis("Mouse X");
                float _mouseY = Input.GetAxis("Mouse Y");
                //鼠标图标换成自定义小手
                //RsCursorMgr.Instance.SetCursorDrag();
                //相机位置的偏移量(Vector3类型,实现原理是:向量的加法)
                Vector3 moveDir = (_mouseX * -transform.right + _mouseY * -transform.forward);
                //限制y轴的偏移量
                moveDir.y = 0;
                transform.position += moveDir * mouseSpeed;
            }
            else
            {
    
    
                //鼠标恢复默认图标,置null即可
                //RsCursorMgr.Instance.CursorReSet();
            }
        }
        #endregion

        #region ###摄像机聚焦功能
        [Header("聚焦")]
        public float distance = 150;//摄像机聚焦的距离
        public Transform target
        {
    
    
            get
            {
    
    
                return GetComponent<RuntimeGizmos.TransformGizmo>().targetRootsOrdered[0];
            }
        }
        public Vector2 angles;
        Vector2 currentAngles;
        Vector2 lastAngles;
        Vector2 targetAngles;
        Vector3 currentDirection, targetDirection, lastDirection;
        float anglesSpeed, directionSpeed, distanceSpeed;
        float currentDistance;
        float targetDistance;
        float anglesOffset, directionOffset, distanceOffset;
        float lastDistance;
        [Range(0, 5)]
        public float alignDamper = 2.5f;
        [Range(0, 1)]
        public float threshold = 0.1f;
        public bool isAligning;//表示摄像机是否处于聚焦过程中
        bool linearAdsorbent;

        /// <summary>
        /// 聚焦的方法
        /// </summary>
        /// <param name="go"></param>
        public void Focus(GameObject go)
        {
    
    
            currentAngles = Camera.main.transform.eulerAngles;
            AlignVeiwToTarget(go.transform, new Vector2(angles.x, currentAngles.y), distance);
        }

        /// <summary>
        /// 聚焦移动的方法
        /// </summary>
        /// <param name="center"></param>
        /// <param name="angles"></param>
        /// <param name="distance"></param>
        public void AlignVeiwToTarget(Transform center, Vector2 angles, float distance)
        {
    
    
            target.position = center.position;
            targetAngles = angles;
            targetDistance = distance;
            //Optimal angles.
            while (targetAngles.y - currentAngles.y > 180)
                targetAngles.y -= 360;
            while (targetAngles.y - currentAngles.y < -180)
                targetAngles.y += 360;

            //Calculate lerp parameter.
            currentDistance = Vector3.Distance(transform.position, target.position);
            currentDirection = (transform.position - target.position).normalized;
            targetDirection = (Quaternion.Euler(targetAngles) * Vector3.back).normalized;

            //Calculate offset.
            anglesOffset = (targetAngles - currentAngles).magnitude;
            directionOffset = (targetDirection - currentDirection).magnitude;
            distanceOffset = Mathf.Abs(targetDistance - currentDistance);

            //Check zero value of offset.
            anglesOffset = anglesOffset > Vector3.kEpsilon ? anglesOffset : 1;
            directionOffset = directionOffset > Vector3.kEpsilon ? directionOffset : 1;
            distanceOffset = distanceOffset > Vector3.kEpsilon ? distanceOffset : 1;

            //Start align.
            linearAdsorbent = false;
            isAligning = true;
        }

        /// <summary>
        /// 聚焦过程执行的方法
        /// </summary>
        private void AutoAlignView()
        {
    
    
            var currentAnglesOffset = (targetAngles - currentAngles).magnitude;
            var currentDirectionOffset = (targetDirection - currentDirection).magnitude;
            var currentDistanceOffset = Mathf.Abs(targetDistance - currentDistance);

            if (currentAnglesOffset < 0.1f && currentDirectionOffset < 0.1f && currentDistanceOffset < 0.1f)
            {
    
    
                isAligning = false;
            }
            else
            {
    
    
                if (linearAdsorbent)
                {
    
    
                    //MoveTowards to linear adsorbent align.
                    currentAngles = Vector2.MoveTowards(currentAngles, targetAngles, anglesSpeed * Time.deltaTime);
                    currentDirection = Vector3.MoveTowards(currentDirection, targetDirection, directionSpeed * Time.deltaTime);
                    currentDistance = Mathf.MoveTowards(currentDistance, targetDistance, distanceSpeed * Time.deltaTime);
                }
                else
                {
    
    
                    //Record last.
                    lastAngles = currentAngles;
                    lastDirection = currentDirection;
                    lastDistance = currentDistance;

                    //Lerp to align.
                    currentAngles = Vector2.Lerp(currentAngles, targetAngles, alignDamper * Time.deltaTime);
                    currentDirection = Vector3.Lerp(currentDirection, targetDirection, alignDamper * Time.deltaTime);
                    currentDistance = Mathf.Lerp(currentDistance, targetDistance, alignDamper * Time.deltaTime);

                    //Check into linear adsorbent.
                    if (currentAnglesOffset / anglesOffset < threshold && currentDirectionOffset / directionOffset < threshold && currentDistanceOffset / distanceOffset < threshold)
                    {
    
    
                        anglesSpeed = (currentAngles - lastAngles).magnitude / Time.deltaTime;
                        directionSpeed = (currentDirection - lastDirection).magnitude / Time.deltaTime;
                        distanceSpeed = Mathf.Abs(currentDistance - lastDistance) / Time.deltaTime;
                        linearAdsorbent = true;
                    }
                }

                transform.position = target.position + currentDirection.normalized * currentDistance;
                transform.rotation = Quaternion.Euler(currentAngles);
                
 				//解决摄像机死锁的问题
                var angles = transform.eulerAngles;
                x = angles.y;
                y = angles.x;
            }
        }
        #endregion
    }

    /// <summary>
    /// 摄像机模式类型,可继续添加
    /// </summary>
    public enum CameraMode
    {
    
    ,
        自由模式,
        鼠标模式,
    }
}

おすすめ

転載: blog.csdn.net/qq_37179591/article/details/129811225