unity 摄像机镜头跟随鼠标拖拽

通过update方法记录变化量然后通过坐标换算移动摄像机

一.获取上一帧到当前帧鼠标位移变化量,计算过相机从上一针位置到当前帧位置移动的距离

 /// <summary>
        /// 计算上一帧到当前帧移动距离
        /// </summary>
        /// <param name="moveDetla"></param>
        /// <returns></returns>
        bool isCameraMove(out Vector3 moveDetla)
        {
            moveDetla = Vector3.zero;
            if (Input.GetMouseButtonDown(0))
            {
                setBeginState();
            }
            else if (Input.GetMouseButton(0))
            {
                Debug.DrawLine(cameraRay.origin, cameraRay.origin + cameraRay.direction * 50, Color.red);
                Vector3 curMousePos = getMouseWorldPos();
                Vector3 detla = curMousePos - curTouchPos;
                if (detla.sqrMagnitude > 0)
                {
                    Vector3 temp = dragCamera.ScreenToWorldPoint(curMousePos);
                    onToutch(temp);
                    moveDetla = dragCamera.ScreenToWorldPoint(startTouchPos) - temp;

                     //计算过相机从上一针位置到当前帧位置移动的位置
                    cameraTargetPos = cameraOriginPos + moveDetla;
                    curDragComeraPos = dragCamera.transform.position;
                    LaunchCameraMove();
                    // moveDetla = temp - dragCamera.ScreenToWorldPoint(startTouchPos);
                    curTouchPos = curMousePos;
                    return true;
                }
            }

            return false;
        } 

二.实现摄像机移动阻尼和曲线移动派生类CameraDragSmoothDamp和CameraDragByCurve

重写CameraDragSmoothDamp的OnCameraMove()实现摄像机阻尼运动效果

 protected override void OnCameraMove()
    {
        base.OnCameraMove();
        if (!isLaunchMove)
        {
            return;
        }

        Vector3 result =
            Vector3.SmoothDamp(dragCamera.transform.position, cameraTargetPos, ref curVelocity, moveTime);
        if (curVelocity == Vector3.zero)
        {
            isLaunchMove = false;
        }

        SetCameraPos(result);
    }

重写CameraDragByCurve的OnCameraMove()实现摄像机曲线运动效果

 protected override void OnCameraMove()
    {
        base.OnCameraMove();
        if (Curve==null)
        {
            return;;
        }
        if (!isLaunchMove)
        {
            return;
        }

        value += Time.deltaTime * speed;
        if (value > 1)
        {
            value = 1;
            isLaunchMove = false;
        }

        float v = Curve.Evaluate(value);
        Vector3 result = Vector3.Lerp(curDragComeraPos, cameraTargetPos, v);
        SetCameraPos(result);
    }

三.编写编辑器脚本GameCameraDragEditor实现阻尼脚本CameraDragSmoothDamp和曲线脚本CameraDragByCurve不同类型间的切换

 public override void OnInspectorGUI()
   {
     // base.OnInspectorGUI();
      SerializedProperty _moveType = serializedObject.FindProperty("_moveType");  
      SerializedProperty _drag = serializedObject.FindProperty("_drag");
      EditorGUI.BeginChangeCheck();
      EditorGUILayout.PropertyField(_moveType);
      if (EditorGUI.EndChangeCheck())
      {
          if (_moveType.enumValueIndex== (int)GameCameraDrag.MoveType.SmoothDamp)
          {
              _drag.managedReferenceValue = new CameraDragSmoothDamp();
          }
          else
          {
              _drag.managedReferenceValue = new CameraDragByCurve();
          }
          serializedObject.ApplyModifiedProperties();
      }
      EditorGUI.BeginChangeCheck();
      EditorGUILayout.PropertyField(_drag,true);
      if (EditorGUI.EndChangeCheck())
      {
          serializedObject.ApplyModifiedProperties();

      }
   }

注意_drag.managedReferenceValue的managedReferenceValue属性2018没有,可以通过target强转成GameCameraDrag进行设置

脚本挂载流程

1.新建场景 ,创建空节点并将摄像机拖拽脚本GameCameraDrag挂载到节点下

2.将相机拖拽至GameCameraDrag脚本下的dragcamera变量下

3.添加quad面片至摄像机视窗内,设置quad面片layer为Ignore Raycast.目的为获取摄像机和场景间的距离

4.运行游戏即可

20221113-125227

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameCameraDrag : MonoBehaviour
{
    public enum MoveType
    {
        SmoothDamp,
        Curve,
    }

    [SerializeField] private MoveType _moveType =MoveType.SmoothDamp;
    [SerializeReference]  private CameraDrag _drag=new CameraDragSmoothDamp();
    //public Transform pointNode;

    private void Start()
    {
        _drag.Init();
    }

    void Update()
    {
        _drag.OnGrag();
    }

    private Vector3 target;

    private void LateUpdate()
    {
        _drag.UpdataDrag();
    }

   
}

摄像机移动脚本基类

    using System;
    using UnityEngine;

    [Serializable]
    public class CameraDrag
    {
        [SerializeField] protected Camera dragCamera;
        [SerializeField] private float distance;

        private Vector3 cameraOriginPos;
        private Vector3 startTouchPos;
        private Vector3 curTouchPos;

        protected Vector3 curDragComeraPos;
        protected Vector3 cameraTargetPos;
        protected bool isLaunchMove = false;

        private bool isMove;
        private Vector3 moveDetla;
        private int layerMask;

        private Ray cameraRay;
        //public Transform pointNode;

        public void Init()
        {
            getDistance();
        }
        
        /// <summary>
        /// 获取摄像机与拍照平面的距离,用于计算摄像机移动距离
        /// </summary>
        private void getDistance()
        {
            cameraRay = dragCamera.ViewportPointToRay(new Vector2(0.5f, 0.5f));
            layerMask = 1 << LayerMask.NameToLayer("Ignore Raycast");
            RaycastHit hit;
            RaycastHit2D raycastHit2D = Physics2D.Raycast(dragCamera.transform.position, cameraRay.direction,
                Mathf.Infinity,
                layerMask);
            if (raycastHit2D)
            {
                distance = (dragCamera.transform.position - raycastHit2D.transform.position).magnitude;
                Debug.LogError("获取距离" + distance);
            }
            else if (Physics.Raycast(cameraRay, out hit, Mathf.Infinity,
                layerMask))
            {
                distance = (dragCamera.transform.position - hit.transform.position).magnitude;
                Debug.LogError("获取距离" + distance);
            }
            else
            {
                Debug.LogError("获取距离失败");
                distance = 10;
            }
        }


        public void OnGrag()
        {
            moveDetla = Vector3.zero;
            isCameraMove(out moveDetla);
        }
        /// <summary>
        /// 计算上一帧到当前帧移动距离
        /// </summary>
        /// <param name="moveDetla"></param>
        /// <returns></returns>
        bool isCameraMove(out Vector3 moveDetla)
        {
            moveDetla = Vector3.zero;
            if (Input.GetMouseButtonDown(0))
            {
                setBeginState();
            }
            else if (Input.GetMouseButton(0))
            {
                Debug.DrawLine(cameraRay.origin, cameraRay.origin + cameraRay.direction * 50, Color.red);
                Vector3 curMousePos = getMouseWorldPos();
                Vector3 detla = curMousePos - curTouchPos;
                if (detla.sqrMagnitude > 0)
                {
                    Vector3 temp = dragCamera.ScreenToWorldPoint(curMousePos);
                    onToutch(temp);
                    moveDetla = dragCamera.ScreenToWorldPoint(startTouchPos) - temp;
                    cameraTargetPos = cameraOriginPos + moveDetla;
                    curDragComeraPos = dragCamera.transform.position;
                    LaunchCameraMove();
                    // moveDetla = temp - dragCamera.ScreenToWorldPoint(startTouchPos);
                    curTouchPos = curMousePos;
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// 初始化当前帧变换状态
        /// </summary>
        private void setBeginState()
        {
            Debug.DrawLine(cameraRay.origin, cameraRay.origin + cameraRay.direction * 50, Color.red);
            startTouchPos = getMouseWorldPos();
            curTouchPos = startTouchPos;
            cameraOriginPos = dragCamera.transform.position;
        }


        protected virtual void LaunchCameraMove()
        {
            isLaunchMove = true;
        }


        public void SetCameraPos(Vector3 result)
        {
            dragCamera.transform.position = result;
        }

        public void UpdataDrag()
        {
            OnCameraMove();
        }

        protected virtual void OnCameraMove()
        {
        }
        /// <summary>
        /// 获取屏幕点击位置
        /// </summary>
        /// <returns></returns>
        private Vector3 getMouseWorldPos()
        {
            Vector3 temp = Input.mousePosition;
            temp.z = distance;
            return temp;
        }

        private void onToutch(Vector3 pos)
        {
            // pointNode.transform.position = pos;
        }
    }

摄像机移动阻尼脚本

using System;
using UnityEngine;

[Serializable]
public class CameraDragSmoothDamp : CameraDrag
{
    [SerializeField] private float moveTime = 0.3f;
    Vector3 curVelocity = Vector3.zero;
    protected override void OnCameraMove()
    {
        base.OnCameraMove();
        if (!isLaunchMove)
        {
            return;
        }

        Vector3 result =
            Vector3.SmoothDamp(dragCamera.transform.position, cameraTargetPos, ref curVelocity, moveTime);
        if (curVelocity == Vector3.zero)
        {
            isLaunchMove = false;
        }

        SetCameraPos(result);
    }
}

摄像机移动曲线脚本

using System;
using UnityEngine;

[Serializable]
public class CameraDragByCurve : CameraDrag
{
    [SerializeField] private float speed = 1;
    [Space(20)]
    [SerializeField] private AnimationCurve[] m_Curves;
    [Tooltip("曲线列表默认索引")]
    [SerializeField] int AnimationCurveIndex =0;
    [Space(20)]
    private float value;

    private AnimationCurve Curve
    {
        get
        {
            if (AnimationCurveIndex>-1&&AnimationCurveIndex<m_Curves.Length)
            {
                return m_Curves[AnimationCurveIndex];
            }

            return null;
        }
    }

    protected override void LaunchCameraMove()
    {
        base.LaunchCameraMove();
        value = 0;
    }

    protected override void OnCameraMove()
    {
        base.OnCameraMove();
        if (Curve==null)
        {
            return;;
        }
        if (!isLaunchMove)
        {
            return;
        }

        value += Time.deltaTime * speed;
        if (value > 1)
        {
            value = 1;
            isLaunchMove = false;
        }

        float v = Curve.Evaluate(value);
        Vector3 result = Vector3.Lerp(curDragComeraPos, cameraTargetPos, v);
        SetCameraPos(result);
    }
}

创建编辑器Editor文件夹

在Editor文件夹下添加以下脚本

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(GameCameraDrag))]
public class GameCameraDragEditor : Editor
{
   private void OnEnable()
   {
      
   }

   public override void OnInspectorGUI()
   {
     // base.OnInspectorGUI();
      SerializedProperty _moveType = serializedObject.FindProperty("_moveType");  
      SerializedProperty _drag = serializedObject.FindProperty("_drag");
      EditorGUI.BeginChangeCheck();
      EditorGUILayout.PropertyField(_moveType);
      if (EditorGUI.EndChangeCheck())
      {
          if (_moveType.enumValueIndex== (int)GameCameraDrag.MoveType.SmoothDamp)
          {
              _drag.managedReferenceValue = new CameraDragSmoothDamp();
          }
          else
          {
              _drag.managedReferenceValue = new CameraDragByCurve();
          }
          serializedObject.ApplyModifiedProperties();
      }
      EditorGUI.BeginChangeCheck();
      EditorGUILayout.PropertyField(_drag,true);
      if (EditorGUI.EndChangeCheck())
      {
          serializedObject.ApplyModifiedProperties();

      }
   }
}

结构目录如下

 项目下载链接

猜你喜欢

转载自blog.csdn.net/fengya1/article/details/127831044