Files
aibis-dream/Assets/Scripts/FixSystem/Effect/MouseFollowEffect.cs
T

281 lines
10 KiB
C#

using UnityEngine;
using TMPro;
using AibisDream.Framework;
namespace AibisDream
{
[RequireComponent(typeof(EventTriggerEx))]
public class MouseFollowAndZoom : MonoBehaviour, IInteraction
{
public GameObject targetIndicator; // UI 目标框
public TMP_Text targetNameText; // 显示目标名称的文本
public Vector2 sceneBoundsMin; // 场景边界的左下角
public Vector2 sceneBoundsMax; // 场景边界的右上角
private EyeSystem eyemanager;
private EyeTarget currentTarget; // 当前目标
private bool isActive = false;
private bool isLocked = false;
// 交互状态管理
[Header("交互状态")]
[SerializeField] private bool _isInteractionActive = true; // 是否激活交互
[SerializeField] private bool _isInteractionAvailable = true; // 是否可用交互
[SerializeField] private float _dialogEndCooldown = 0.1f; // 对话结束后的冷却时间
// 内部状态
private float _lastDialogEndTime = -1f; // 上次对话结束的时间
private bool _isDialogCooldownActive = false; // 是否在对话冷却期间
public Camera viewCamera;
public float parallaxEffectMultiplier = 0.1f;
public Vector2 maxOffset = new Vector2(2f, 2f);
private Vector3 initialPosition;
private float viewOffset = 0;
// 读写访问
public void SetIsActive(bool value)
{
isActive = value;
}
public void SetIsLock(bool value)
{
isLocked = value;
}
// 交互状态控制方法
public void SetInteractionActive(bool value)
{
_isInteractionActive = value;
}
public void SetInteractionAvailable(bool value)
{
_isInteractionAvailable = value;
}
void Start()
{
initialPosition = transform.position;
targetIndicator.SetActive(false); // 初始时隐藏目标框
eyemanager = FindObjectOfType<EyeSystem>();
if (eyemanager == null)
{
Debug.LogError("EyeManager instance not found in the scene.");
}
// 注册对话事件以处理对话结束后的冷却
RegisterDialogEvents();
}
void Update()
{
if (!isActive)
{
targetIndicator.SetActive(false);
return;
}
// 检查对话结束冷却
UpdateDialogCooldown();
HandleTargetIndicator(); // 显示指示器
if (isLocked) return;
HandleMouseMovement();
UpdateCurrentTarget(); // 更新当前目标
}
private Vector3 currentOffset; // 当前的偏移量
void HandleMouseMovement()
{
// 获取鼠标位置
Vector3 mousePosition = Input.mousePosition;
mousePosition.x -= 40f; // 为x坐标加上40.3
Vector3 worldMousePosition = viewCamera.ScreenToWorldPoint(mousePosition);
worldMousePosition.z = 0; // 确保 z 为 0
// 计算目标偏移量并反向
Vector3 targetOffset = (viewCamera.transform.position - worldMousePosition) * parallaxEffectMultiplier;
targetOffset.x = Mathf.Clamp(targetOffset.x, -maxOffset.x, maxOffset.x);
targetOffset.y = Mathf.Clamp(targetOffset.y, -maxOffset.y, maxOffset.y);
// 平滑处理偏移量
float smoothFactor = 0.01f; // 平滑系数,值越小平滑效果越强,响应越慢
currentOffset = Vector3.Lerp(currentOffset, targetOffset, smoothFactor);
// 计算目标位置
Vector3 targetPosition = initialPosition + currentOffset;
// 限制目标位置在场景边界范围内
targetPosition.x = Mathf.Clamp(targetPosition.x, sceneBoundsMin.x, sceneBoundsMax.x);
targetPosition.y = Mathf.Clamp(targetPosition.y, sceneBoundsMin.y, sceneBoundsMax.y);
// 使用插值(Lerp)平滑更新位置
float followSpeed = 0.1f; // 跟随速度,值越小延迟越大
Vector3 smoothedPosition = Vector3.Lerp(transform.position, targetPosition, followSpeed);
// 应用平滑后的位置
transform.position = smoothedPosition;
}
void UpdateCurrentTarget()
{
// 获取鼠标位置
Vector3 mousePosition = Input.mousePosition;
mousePosition.x -= 40f; // 为x坐标加上40.3
Vector3 worldPosition = Camera.main.ScreenToWorldPoint(mousePosition);
RaycastHit2D hit =
Physics2D.Raycast(worldPosition + viewCamera.transform.position - Camera.main.transform.position,
Vector2.zero);
// 检查是否有目标
if (hit.collider != null && hit.collider.CompareTag("EyeTarget"))
{
currentTarget = hit.collider.GetComponent<EyeTarget>(); // 更新当前目标
// 处理鼠标点击事件 - 只有在交互可用且不在对话冷却期时才处理
if (Input.GetMouseButtonDown(0) && _isInteractionActive && _isInteractionAvailable && !_isDialogCooldownActive)
{
Debug.Log("点击目标触发了");
if (currentTarget != null)
{
eyemanager.SetTarget(currentTarget); // 设置目标
}
else
{
Debug.LogWarning("The collider does not have an EyeTarget component.");
}
}
}
else
{
currentTarget = null; // 如果没有目标,设置为 null
}
}
void HandleTargetIndicator()
{
if (currentTarget == null || !_isInteractionActive)
{
targetIndicator.SetActive(false); // 隐藏指示器
return;
}
// 获取目标的 BoxCollider2D
BoxCollider2D boxCollider = currentTarget.GetComponent<BoxCollider2D>();
if (boxCollider != null)
{
Vector3 boxCenter = boxCollider.bounds.center;
Vector3 boxSize = boxCollider.bounds.size;
// 转换为世界空间坐标
Vector3 worldCenter = boxCenter;
Vector3 worldSize = boxSize;
// 设置目标框的位置
RectTransform indicatorRectTransform = targetIndicator.GetComponent<RectTransform>();
indicatorRectTransform.position = worldCenter;
indicatorRectTransform.sizeDelta = new Vector2(worldSize.x, worldSize.y);
// 设置目标名称
targetNameText.text = currentTarget.name + " " +
"R" + currentTarget._color.r.ToString("F1") +
" G" + currentTarget._color.g.ToString("F1") +
" B" + currentTarget._color.b.ToString("F1");
// 显示指示器
targetIndicator.SetActive(true);
}
}
public void SetIndicatorTarget(EyeTarget target)
{
currentTarget = target;
}
void OnDrawGizmos()
{
// 设置 Gizmos 颜色
Gizmos.color = Color.red;
// 绘制场景边界
Vector3 bottomLeft = new Vector3(sceneBoundsMin.x, sceneBoundsMin.y, 0);
Vector3 topRight = new Vector3(sceneBoundsMax.x, sceneBoundsMax.y, 0);
// 绘制边界框
Gizmos.DrawLine(bottomLeft, new Vector3(bottomLeft.x, topRight.y, 0));
Gizmos.DrawLine(bottomLeft, new Vector3(topRight.x, bottomLeft.y, 0));
Gizmos.DrawLine(topRight, new Vector3(bottomLeft.x, topRight.y, 0));
Gizmos.DrawLine(topRight, new Vector3(topRight.x, bottomLeft.y, 0));
}
#region 对话冷却处理
/// <summary>
/// 注册对话事件
/// </summary>
private void RegisterDialogEvents()
{
// 监听对话结束事件
EnumEventSystem.Global.Register(InteractionEventEnum.DialogStart, OnDialogueComplete);
}
/// <summary>
/// 对话结束时的处理
/// </summary>
private void OnDialogueComplete()
{
_lastDialogEndTime = Time.time;
_isDialogCooldownActive = true;
Debug.Log($"[交互冷却] 对话结束,开始 {_dialogEndCooldown} 秒冷却期");
}
/// <summary>
/// 更新对话冷却状态
/// </summary>
private void UpdateDialogCooldown()
{
if (_isDialogCooldownActive && Time.time - _lastDialogEndTime >= _dialogEndCooldown)
{
_isDialogCooldownActive = false;
Debug.Log("[交互冷却] 冷却期结束,交互恢复正常");
}
}
/// <summary>
/// 销毁时取消事件注册
/// </summary>
private void OnDestroy()
{
EnumEventSystem.Global.UnRegister(InteractionEventEnum.DialogStart, OnDialogueComplete);
}
#endregion
#region IInteraction 接口实现
/// <summary>
/// 判断是否激活,激活就正常显示鼠标,否则就显示禁用标志
/// </summary>
public bool IsActive => _isInteractionActive && !_isDialogCooldownActive;
/// <summary>
/// 判断是否可用,可用就正常显示鼠标,否则就保持原有标志不变
/// </summary>
public bool IsAvailable => _isInteractionAvailable && !_isDialogCooldownActive;
/// <summary>
/// 返回GameObject
/// </summary>
public GameObject GetGameObject()
{
return gameObject;
}
#endregion
}
}