Files
Gen_Hack-and-Slash-Roguelite/Client/Assets/Scripts/Entity/VisionRangeDetector.cs
2025-08-25 18:24:12 +08:00

188 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.Collections.Generic;
using System.Linq;
using Data;
using Managers;
using UnityEngine;
namespace Entity
{
/// <summary>
/// 视野范围检测器组件。
/// 挂载到包含触发器碰撞体的GameObject上用于检测视野范围内的Entity。
/// </summary>
public class VisionRangeDetector : MonoBehaviour
{
// 允许在Inspector中手动指定Collider或在Awake时自动获取。
[SerializeField] [Tooltip("用于检测视野范围的触发器碰撞体。如果未指定将在Awake时自动获取。")]
private Collider2D _collider;
// 缓存所属的Entity组件用于获取派系信息。
private Entity _ownerEntity;
// 将List改为HashSet优化添加和移除的性能。
private HashSet<Entity> _entitiesInRange = new HashSet<Entity>(); // 维护在视野范围内的Entity集合
private Transform _myTransform; // 缓存Transform组件以提高性能
// 【逻辑修改】用于记录上次清理的帧数,避免在同一帧内重复清理。
private int _lastCleanupFrame = -1;
private void Awake()
{
_myTransform = transform; // 缓存自身Transform
// 1. 检查并确保GameObject上存在触发器碰撞体
if (_collider == null)
{
_collider = GetComponent<Collider2D>();
}
if (_collider == null)
{
Debug.LogError(
$"VisionRangeDetector on {gameObject.name} requires a Collider component. Please add one or assign it in the Inspector.",
this);
enabled = false; // 如果没有碰撞体,禁用此组件
return;
}
if (!_collider.isTrigger)
{
Debug.LogWarning(
$"VisionRangeDetector on {gameObject.name} works best with a Trigger Collider. Setting isTrigger to true.",
this);
_collider.isTrigger = true;
}
// 2. 检查AffiliationManager是否存在
if (AffiliationManager.Instance == null)
{
Debug.LogError(
"AffiliationManager.Instance is null. Please ensure an AffiliationManager exists in the scene.",
this);
enabled = false; // 如果没有派系管理器,禁用此组件
return; // 提前返回避免后续操作依赖于AffiliationManager
}
// 3. 获取所属的Entity组件并使用其affiliation。
_ownerEntity = GetComponentInParent<Entity>();
if (_ownerEntity == null)
{
_ownerEntity = GetComponent<Entity>();
}
if (_ownerEntity == null)
{
Debug.LogError(
$"VisionRangeDetector on {gameObject.name}: No Entity component found in parent or self. This component cannot determine its affiliation and will be disabled.",
this);
enabled = false;
return;
}
}
// 【逻辑修改】移除LateUpdate清理逻辑移至获取方法中。
// private void LateUpdate()
// {
// _entitiesInRange.RemoveWhere(e => e == null);
// }
/// <summary>
/// 【逻辑修改】在获取实体列表前,执行一次清理操作(每帧最多一次)。
/// </summary>
private void CleanEntitiesInRange()
{
// 只有当当前帧与上次清理的帧不同时才执行清理
if (Time.frameCount != _lastCleanupFrame)
{
_entitiesInRange.RemoveWhere(e => e == null);
_lastCleanupFrame = Time.frameCount; // 更新上次清理的帧数
// Debug.Log($"Cleaned _entitiesInRange in frame {Time.frameCount}. Current count: {_entitiesInRange.Count}");
}
}
/// <summary>
/// 当有其他碰撞体进入触发器范围时调用。
/// </summary>
/// <param name="other">进入触发器的碰撞体。</param>
private void OnTriggerEnter(Collider other)
{
Entity entity = other.GetComponent<Entity>();
if (entity != null)
{
if (entity.gameObject == _ownerEntity.gameObject || entity.transform.IsChildOf(_ownerEntity.transform))
{
return;
}
if (_entitiesInRange.Add(entity))
{
// Debug.Log($"Entity '{entity.name}' (Affiliation: {entity.affiliation}) entered range. Total: {_entitiesInRange.Count}");
}
}
}
/// <summary>
/// 当有其他碰撞体离开触发器范围时调用。
/// </summary>
/// <param name="other">离开触发器的碰撞体。</param>
private void OnTriggerExit(Collider other)
{
Entity entity = other.GetComponent<Entity>();
if (entity != null)
{
if (_entitiesInRange.Remove(entity))
{
// Debug.Log($"Entity '{entity.name}' (Affiliation: {entity.affiliation}) exited range. Total: {_entitiesInRange.Count}");
}
}
}
/// <summary>
/// 获取视野范围内最近的N个实体。
/// </summary>
/// <param name="n">要获取的实体数量。</param>
/// <returns>最近的N个实体列表。</returns>
public List<Entity> GetNearestNEntities(int n)
{
if (n <= 0) return new List<Entity>();
// 【逻辑修改】在获取前清理一次集合
CleanEntitiesInRange();
return _entitiesInRange
.OrderBy(e => Vector3.Distance(_myTransform.position, e.transform.position))
.Take(n)
.ToList();
}
/// <summary>
/// 获取视野范围内最近的N个指定关系的实体敌对、友好、中立
/// </summary>
/// <param name="n">要获取的实体数量。</param>
/// <param name="targetRelation">目标派系关系。</param>
/// <returns>最近的N个指定关系的实体列表。</returns>
public List<Entity> GetNearestNEntitiesByRelation(int n, Relation targetRelation)
{
if (AffiliationManager.Instance == null)
{
Debug.LogError(
"AffiliationManager.Instance is null. Cannot get entities by relation. VisionRangeDetector should have been disabled if this was an issue.",
this);
return new List<Entity>();
}
if (n <= 0) return new List<Entity>();
// 【逻辑修改】在获取前清理一次集合
CleanEntitiesInRange();
return _entitiesInRange
.Where(e => AffiliationManager.Instance.GetRelation(_ownerEntity.affiliation, e.affiliation) ==
targetRelation)
.OrderBy(e => Vector3.Distance(_myTransform.position, e.transform.position))
.Take(n)
.ToList();
}
}
}