234 lines
7.2 KiB
C#
234 lines
7.2 KiB
C#
using System;
|
||
using System.Collections;
|
||
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
using UnityEngine.InputSystem;
|
||
using UnityEngine.InputSystem.EnhancedTouch;
|
||
using UnityEngine.UI;
|
||
using UnityEngine.UIElements;
|
||
|
||
public class TargetFlow : MonoBehaviour
|
||
{
|
||
// 输入配置
|
||
[Header("输入绑定")]
|
||
[Tooltip("按下的输入绑定事件")]
|
||
[SerializeField] private InputActionReference pressAction;
|
||
[SerializeField] private InputActionReference moveAction;
|
||
|
||
// 移动参数
|
||
[Header("移动设置")]
|
||
[Tooltip("缓动移动速度")]
|
||
[SerializeField] private float moveSpeed = 10f;
|
||
[Tooltip("缓动距离乘积")]
|
||
[SerializeField] private float moveMul = 1f;
|
||
public GraphicRaycaster uiRaycaster;
|
||
|
||
// 运行时状态
|
||
private Camera _cam;
|
||
private bool _isPressDown = false;
|
||
|
||
// 惯性参数
|
||
private Vector3 _currPosition;
|
||
private Vector3? _controlPosition;
|
||
private Vector3 _targetWorldPos;
|
||
private Vector3? _beforeTargetWorldPos;
|
||
private Vector3 _position = Vector3.zero;
|
||
private int _backgroundLayer = 0;
|
||
private float _radius = 0;
|
||
|
||
private Vector3 offsetLimitPos1;
|
||
private Vector3 offsetLimitPos2;
|
||
private float beforeNearClipPlane = -1;
|
||
|
||
private void Awake()
|
||
{
|
||
_cam = Camera.main;
|
||
_backgroundLayer = LayerMask.NameToLayer("Background");
|
||
}
|
||
|
||
private void Start()
|
||
{
|
||
var bounds = GetComponentInChildren<Collider>().bounds;
|
||
_radius = Mathf.Max(bounds.extents.x, bounds.extents.y, bounds.extents.z);
|
||
}
|
||
|
||
private void ResetLimitPos()
|
||
{
|
||
if (_cam.nearClipPlane != beforeNearClipPlane)
|
||
{
|
||
beforeNearClipPlane = _cam.nearClipPlane;
|
||
var limitRectPos1 = _cam.ScreenToWorldPoint(new Vector3(0, 0, _cam.nearClipPlane));
|
||
var limitRectPos2 = _cam.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, _cam.nearClipPlane));
|
||
offsetLimitPos1 = _cam.WorldToScreenPoint(new Vector3(limitRectPos1.x + _radius, limitRectPos1.y, limitRectPos1.z + _radius));
|
||
offsetLimitPos2 = _cam.WorldToScreenPoint(new Vector3(limitRectPos2.x - _radius, limitRectPos2.y, limitRectPos2.z - _radius));
|
||
}
|
||
}
|
||
|
||
private void OnEnable()
|
||
{
|
||
pressAction.action.performed += PressAction_performed;
|
||
pressAction.action.canceled += PressAction_canceled;
|
||
|
||
|
||
moveAction.action.performed += OnMovePerformed;
|
||
//moveAction.action.canceled += OnMoveCanceled;
|
||
|
||
//uiPointerAction.action.performed += OnUIPointerPerformed;
|
||
|
||
pressAction.action.Enable();
|
||
moveAction.action.Enable();
|
||
|
||
_currPosition = transform.position;
|
||
}
|
||
|
||
private void PressAction_performed(InputAction.CallbackContext ctx)
|
||
{
|
||
_isPressDown = true;
|
||
_controlPosition = null;
|
||
}
|
||
private void PressAction_canceled(InputAction.CallbackContext ctx)
|
||
{
|
||
_isPressDown = false;
|
||
}
|
||
|
||
|
||
private void OnDisable()
|
||
{
|
||
pressAction.action.performed -= PressAction_performed;
|
||
pressAction.action.canceled -= PressAction_canceled;
|
||
moveAction.action.performed -= OnMovePerformed;
|
||
//moveAction.action.canceled -= OnMoveCanceled;
|
||
|
||
//uiPointerAction.action.performed -= OnUIPointerPerformed;
|
||
|
||
pressAction.action.Disable();
|
||
moveAction.action.Disable();
|
||
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (HandleUIBlocking())
|
||
{
|
||
return;
|
||
}
|
||
HandleMovement();
|
||
}
|
||
|
||
// 新增UI阻塞处理
|
||
private bool HandleUIBlocking()
|
||
{
|
||
// 新输入系统:读取鼠标位置(返回Vector2,与Input.mousePosition的x、y值一致)
|
||
//Vector2 mousePos = moveAction.action.ReadValue<Vector2>();
|
||
|
||
// 创建射线(ScreenPointToRay支持Vector2,内部会自动处理z轴为0)
|
||
|
||
if (_controlPosition == null)
|
||
{
|
||
return false;
|
||
}
|
||
|
||
if (uiRaycaster != null)
|
||
{
|
||
// 第一步:先检测UI
|
||
PointerEventData pointerData = new PointerEventData(EventSystem.current);
|
||
pointerData.position = _controlPosition.Value;
|
||
List<RaycastResult> uiResults = new List<RaycastResult>();
|
||
uiRaycaster.Raycast(pointerData, uiResults);
|
||
|
||
if (uiResults.Count > 0)
|
||
{
|
||
return true; // 有UI则不检测3D
|
||
}
|
||
}
|
||
|
||
|
||
Ray ray = _cam.ScreenPointToRay(_controlPosition.Value);
|
||
if (Physics.Raycast(ray, out RaycastHit hit, 100f))
|
||
{
|
||
if (hit.collider.gameObject.layer == _backgroundLayer)
|
||
{
|
||
//enabled = false;
|
||
//StartCoroutine(EnableAfterDelay(0.1f));
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// 移动处理
|
||
private void HandleMovement()
|
||
{
|
||
if (_isPressDown && _controlPosition != null)
|
||
{
|
||
// 获取目标位置
|
||
if (Touchscreen.current != null && Touchscreen.current.touches.Count > 0)
|
||
{
|
||
_position = Touchscreen.current.touches[0].position.ReadValue();
|
||
}
|
||
else if (Mouse.current != null)
|
||
{
|
||
_position = Mouse.current.position.ReadValue();
|
||
}
|
||
|
||
// 转换为世界坐标并平滑移动
|
||
_targetWorldPos += _cam.ScreenToWorldPoint(new Vector3(_position.x, _position.y, _cam.nearClipPlane)) - _cam.ScreenToWorldPoint(new Vector3(_controlPosition.Value.x, _controlPosition.Value.y, _cam.nearClipPlane));
|
||
_controlPosition = _position;
|
||
_targetWorldPos.y = transform.position.y;
|
||
//_targetWorldPos.z = transform.position.z;
|
||
if (_beforeTargetWorldPos == null)
|
||
{
|
||
_beforeTargetWorldPos = _targetWorldPos;
|
||
}
|
||
|
||
ResetLimitPos();
|
||
var pos = _currPosition + (_targetWorldPos - _beforeTargetWorldPos.Value) * moveMul;
|
||
var screenPos = _cam.WorldToScreenPoint(pos);
|
||
//Debug.Log(offsetLimitPos1 + ":" + offsetLimitPos2);
|
||
//限制对象移动范围在屏幕范围之内
|
||
if (screenPos.x > offsetLimitPos1.x && screenPos.x < offsetLimitPos2.x && screenPos.y > offsetLimitPos1.y && screenPos.y < offsetLimitPos2.y)
|
||
{
|
||
_currPosition = pos;
|
||
}
|
||
_beforeTargetWorldPos = _targetWorldPos;
|
||
}
|
||
|
||
transform.position = Vector3.Lerp(transform.position, _currPosition, moveSpeed * Time.deltaTime);
|
||
}
|
||
|
||
// 回调方法实现
|
||
private void OnMovePerformed(InputAction.CallbackContext ctx)
|
||
{
|
||
if (_controlPosition == null)
|
||
{
|
||
_controlPosition = ctx.ReadValue<Vector2>();
|
||
}
|
||
}
|
||
|
||
//private void OnMoveCanceled(InputAction.CallbackContext ctx)
|
||
//{
|
||
//}
|
||
|
||
//// 场景视图绘制移动范围边界(方便调试)
|
||
//private void OnDrawGizmos()
|
||
//{
|
||
// Gizmos.color = gizmoColor;
|
||
|
||
// // 绘制范围立方体(中心点为原点,大小为范围差值)
|
||
// Vector3 center = new Vector3(
|
||
// (minX + maxX) / 2,
|
||
// (minY + maxY) / 2,
|
||
// transform.position.z
|
||
// );
|
||
// Vector3 size = new Vector3(
|
||
// maxX - minX,
|
||
// maxY - minY,
|
||
// 1f // Y轴高度(可视化用,不影响实际限制)
|
||
// );
|
||
|
||
// Gizmos.DrawCube(center, size);
|
||
//}
|
||
}
|