using UnityEngine; using TMPro; using AibisDream.Framework; namespace AibisDream { 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(); 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(); // 更新当前目标 // 处理鼠标点击事件 - 只有在交互可用且不在对话冷却期时才处理 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(); if (boxCollider != null) { Vector3 boxCenter = boxCollider.bounds.center; Vector3 boxSize = boxCollider.bounds.size; // 转换为世界空间坐标 Vector3 worldCenter = boxCenter; Vector3 worldSize = boxSize; // 设置目标框的位置 RectTransform indicatorRectTransform = targetIndicator.GetComponent(); 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 对话冷却处理 /// /// 注册对话事件 /// private void RegisterDialogEvents() { // 监听对话结束事件 EnumEventSystem.Global.Register(InteractionEventEnum.DialogEnd, OnDialogueComplete); } /// /// 对话结束时的处理 /// private void OnDialogueComplete() { _lastDialogEndTime = Time.time; _isDialogCooldownActive = true; Debug.Log($"[交互冷却] 对话结束,开始 {_dialogEndCooldown} 秒冷却期"); } /// /// 更新对话冷却状态 /// private void UpdateDialogCooldown() { if (_isDialogCooldownActive && Time.time - _lastDialogEndTime >= _dialogEndCooldown) { _isDialogCooldownActive = false; Debug.Log("[交互冷却] 冷却期结束,交互恢复正常"); } } /// /// 销毁时取消事件注册 /// private void OnDestroy() { EnumEventSystem.Global.UnRegister(InteractionEventEnum.DialogEnd, OnDialogueComplete); } #endregion #region IInteraction 接口实现 /// /// 判断是否激活,激活就正常显示鼠标,否则就显示禁用标志 /// public bool IsActive => _isInteractionActive && !_isDialogCooldownActive; /// /// 判断是否可用,可用就正常显示鼠标,否则就保持原有标志不变 /// public bool IsAvailable => _isInteractionAvailable && !_isDialogCooldownActive; /// /// 返回GameObject /// public GameObject GetGameObject() { return gameObject; } #endregion } }