188 lines
7.2 KiB
C#
188 lines
7.2 KiB
C#
![]() |
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();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|