相机控制脚本

该代码实现了一个Unity3D中的摄像机控制脚本,支持两种模式:自由模式(使用WASD和鼠标右键旋转视角)和鼠标模式(鼠标转动视角,左键移动)。脚本还包括聚焦功能,与RuntimeGizmo插件配合使用,允许用户通过F键聚焦目标。
摘要由CSDN通过智能技术生成

相机控制脚本(两种模式)

代码如下:

/*****************************************************************
*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
    {,
        自由模式,
        鼠标模式,
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值