2025-02-19 16:33:28 +08:00

259 lines
7.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
public class Show3DCamera : MonoBehaviour
{
public Vector3 targetPos; // 围绕旋转的目标点
public float rotateSpeed = 10f; // 旋转速度
public float moveSpeed = 10f; // 移动速度
public float distance = 10f; // 相机与目标的距离
public float distanceMin = 0.2f;
public float distanceMax = 20f;
public Vector2 pitchMinMax = new Vector2(-20, 80); // 相机俯仰角范围
private Vector3 offset; // 相机与目标的偏移量
private float yaw = 0f; // 偏航角(左右旋转)
private float pitch = 0f; // 俯仰角(上下旋转)
public static Show3DCamera instance;
RectTransform inputRect;
Camera self;
private GameObject lastHitObject = null;
public RenderTexture texture;
public bool lockMove = false;
private Vector2 mouseDownPosition; // 记录鼠标按下时的位置
private void Awake()
{
instance = this;
self = transform.GetComponent<Camera>();
DontDestroyOnLoad(this);
gameObject.SetActive(false);
}
public void Set(Transform target, float rotateSpeed = 10, float moveSpeed = 0.1f, float distance = 0.1f, float pitchMin = -20, float pitchMax = 80, float distanceMin = 0.2f, float distanceMax = 20f, RectTransform inputRect = null, bool isRenderTexture = true, float moveTime = -1)
{
if (target == null)
{
Debug.LogError("Target is not assigned!");
return;
}
yaw = 0;
pitch = 0;
this.inputRect = inputRect;
this.targetPos = target.transform.position;
this.rotateSpeed = rotateSpeed;
this.moveSpeed = moveSpeed;
this.distance = distance;
this.distanceMin = distanceMin;
this.distanceMax = distanceMax;
this.pitchMinMax = new Vector2(pitchMin, pitchMax);
// 初始化相机位置
offset = new Vector3(0, 0, -distance);
if (isRenderTexture)
{
self.targetTexture = texture;
}
else
{
self.targetTexture = null;
}
UpdateCameraPosition(moveTime);
}
void Update()
{
if (targetPos != null && lockMove == false && EventSystem.current.IsPointerOverGameObject() == false)
{
if (Input.GetMouseButtonDown(0))
{
// 记录鼠标按下时的位置
mouseDownPosition = Input.mousePosition;
}
// 按住鼠标左键时旋转相机
if (Input.GetMouseButton(0))
{
// 计算鼠标按下和抬起位置之间的距离
float distance = Vector2.Distance(mouseDownPosition, Input.mousePosition);
if (distance > 1f)
{
RotateCamera();
}
}
// 鼠标滚轮缩放
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0)
{
ZoomCamera(scroll);
}
// 按住鼠标右键时移动目标点
if (Input.GetMouseButton(1))
{
MoveTarget();
}
DetectHoveredObject();
}
}
// 检测鼠标悬停的物体
public void DetectHoveredObject()
{
GameObject obj = null;
Vector2 mousePosition = Input.mousePosition;
if (inputRect != null)
{
var pos = (mousePosition - (Vector2)inputRect.position) / inputRect.lossyScale - inputRect.rect.position;
mousePosition = pos / inputRect.rect.size;
}
var ray = self.ViewportPointToRay(mousePosition);
RaycastHit raycastHit;
if (Physics.Raycast(ray, out raycastHit))
{
//Debug.Log(raycastHit.transform.name);
obj = raycastHit.transform.gameObject;
// 如果击中的物体与上一次击中的物体不同,表示射线进入了新物体
if (obj != lastHitObject)
{
// 触发进入事件
OnMouseEnterObj(obj);
// 如果上一次击中的物体不为空,触发离开事件
if (lastHitObject != null && lastHitObject != obj)
{
OnMouseExitObj(lastHitObject);
// 更新上一次击中的物体
lastHitObject = obj;
}
}
}
else
{
// 如果射线没有击中任何物体,且上一次击中的物体不为空,触发离开事件
if (lastHitObject != null)
{
OnMouseExitObj(lastHitObject);
lastHitObject = null;
}
}
}
/// <summary>
/// 聚焦某个物体
/// </summary>
public void FocusObj(Vector3 target, float distance = 1f, float moveTime = -1)
{
// 计算相机前方一定距离的位置作为Cube的目标位置
// 可以根据需要调整这个距离
Vector3 cameraPos = target - transform.forward * distance;
targetPos = target;
this.distance = distance;
offset = new Vector3(0, 0, -distance);
if (moveTime != -1)
{
transform.DOMove(cameraPos, moveTime);
}
else
{
transform.position = cameraPos;
}
}
public void OnMouseEnterObj(GameObject obj)
{
TipItem tip = obj.GetComponent<TipItem>();
if (tip != null)
{
tip.OnEnter();
}
}
public void OnMouseExitObj(GameObject obj)
{
TipItem tip = obj.GetComponent<TipItem>();
if (tip != null)
{
tip.OnExit();
}
}
// 移动目标点
private void MoveTarget()
{
float mouseX = Input.GetAxis("Mouse X") * moveSpeed;
float mouseY = Input.GetAxis("Mouse Y") * moveSpeed;
transform.Translate(new Vector3(-mouseX, -mouseY, 0));
targetPos += new Vector3(-mouseX, -mouseY, 0);
}
// 缩放相机
private void ZoomCamera(float scroll)
{
distance -= scroll * 5f; // 调整缩放速度
distance = Mathf.Clamp(distance, distanceMin, distanceMax); // 限制距离范围
offset = new Vector3(0, 0, -distance);
UpdateCameraPosition();
}
// 旋转相机
private void RotateCamera()
{
// 获取鼠标移动量
float mouseX = Input.GetAxis("Mouse X") * rotateSpeed;
float mouseY = Input.GetAxis("Mouse Y") * rotateSpeed;
// 更新偏航角和俯仰角
yaw += mouseX;
pitch -= mouseY; // 注意:鼠标 Y 轴移动方向与俯仰角相反
pitch = Mathf.Clamp(pitch, pitchMinMax.x, pitchMinMax.y); // 限制俯仰角范围
// 更新相机位置
UpdateCameraPosition();
}
// 更新相机位置和朝向
private void UpdateCameraPosition(float moveTime = -1)
{
// 计算旋转后的偏移量
Quaternion rotation = Quaternion.Euler(pitch, yaw, 0);
Vector3 rotatedOffset = rotation * offset;
// 更新相机位置
if (moveTime != -1)
{
transform.DOMove(targetPos + rotatedOffset, moveTime).onUpdate = () =>
// 相机始终朝向目标点
transform.LookAt(targetPos);
}
else
{
transform.position = targetPos + rotatedOffset;
// 相机始终朝向目标点
transform.LookAt(targetPos);
}
}
}