UMiniGame/Assets/Scripts/TargetFlow.cs
2025-12-10 19:33:44 +08:00

234 lines
7.2 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 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);
//}
}