摄像机区域的架构改动
This commit is contained in:
86
Assets/_Game/Scripts/World/InteractableDetector.cs
Normal file
86
Assets/_Game/Scripts/World/InteractableDetector.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using BaseGames.Core.Events;
|
||||
using BaseGames.Input;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BaseGames.World
|
||||
{
|
||||
/// <summary>
|
||||
/// 挂在 Player 上,检测附近可交互物,驱动 UI 提示显示/隐藏。
|
||||
/// 通过 InputReaderSO.InteractEvent 绑定交互输入。
|
||||
/// </summary>
|
||||
public class InteractableDetector : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private float _detectRadius = 1.5f;
|
||||
[SerializeField] private LayerMask _interactableLayer;
|
||||
[SerializeField] private InputReaderSO _inputReader;
|
||||
[SerializeField] private StringEventChannelSO _onShowInteractPrompt;
|
||||
[SerializeField] private VoidEventChannelSO _onHideInteractPrompt;
|
||||
|
||||
private IInteractable _nearest;
|
||||
private IInteractable _previousNearest;
|
||||
|
||||
// 预分配检测缓冲区,避免 OverlapCircleAll 每帧 GC 分配
|
||||
private readonly Collider2D[] _overlapBuffer = new Collider2D[16];
|
||||
|
||||
private void OnEnable() => _inputReader.InteractEvent += TryInteract;
|
||||
private void OnDisable() => _inputReader.InteractEvent -= TryInteract;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
int count = Physics2D.OverlapCircleNonAlloc(
|
||||
transform.position, _detectRadius, _overlapBuffer, _interactableLayer);
|
||||
_nearest = FindNearest(_overlapBuffer, count);
|
||||
|
||||
if (_nearest != _previousNearest)
|
||||
{
|
||||
if (_previousNearest != null)
|
||||
{
|
||||
_previousNearest.OnPlayerExitRange();
|
||||
_onHideInteractPrompt?.Raise();
|
||||
}
|
||||
|
||||
if (_nearest != null)
|
||||
{
|
||||
_nearest.OnPlayerEnterRange(transform);
|
||||
_onShowInteractPrompt?.Raise(_nearest.InteractPrompt);
|
||||
}
|
||||
|
||||
_previousNearest = _nearest;
|
||||
}
|
||||
}
|
||||
|
||||
private void TryInteract()
|
||||
{
|
||||
if (_nearest != null && _nearest.CanInteract)
|
||||
_nearest.Interact(transform);
|
||||
}
|
||||
|
||||
private IInteractable FindNearest(Collider2D[] hits, int count)
|
||||
{
|
||||
IInteractable best = null;
|
||||
float bestDist = float.MaxValue;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var col = hits[i];
|
||||
var interactable = col.GetComponentInParent<IInteractable>();
|
||||
if (interactable == null || !interactable.CanInteract) continue;
|
||||
|
||||
float dist = Vector2.Distance(transform.position, col.transform.position);
|
||||
if (dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
best = interactable;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
private void OnDrawGizmosSelected()
|
||||
{
|
||||
Gizmos.color = Color.cyan;
|
||||
Gizmos.DrawWireSphere(transform.position, _detectRadius);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user