通过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();
}
}
}
结构目录如下