Files
Cielonos/Assets/Scripts/MainGame/Managers/CombatManager/EnemySubmodule/EnemySubmodule.cs
SoulliesOfficial 39b43680a9 爆更
2026-07-18 03:16:20 -04:00

177 lines
6.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Cielonos.MainGame.Characters;
using Sirenix.OdinInspector;
using SLSUtilities.FunctionalAnimation;
using UnityEngine;
namespace Cielonos.MainGame
{
public partial class CombatManager
{
public partial class EnemySubmodule : SubmoduleBase<CombatManager>
{
public enum SortingType
{
Nearest,
Farthest
}
private readonly List<Enemy> _activeEnemiesList;
private readonly ReadOnlyCollection<Enemy> _activeEnemies;
public IReadOnlyList<Enemy> ActiveEnemies => _activeEnemies;
public int ActiveEnemyCount => _activeEnemiesList.Count;
private int TargetingVersion { get; set; }
/// <summary>
/// 敌人从活跃列表中移除时触发(即敌人死亡/离场)。
/// 参数为被移除的敌人实例。
/// </summary>
public event Action<Enemy> OnEnemyRemoved;
public EnemySubmodule(CombatManager owner) : base(owner)
{
_activeEnemiesList = new List<Enemy>();
_activeEnemies = _activeEnemiesList.AsReadOnly();
}
/// <summary>
/// 将敌人加入活跃列表。所有敌人注册都应经过这里,避免外部直接修改索敌源。
/// </summary>
public void RegisterEnemy(Enemy enemy)
{
if (enemy == null || _activeEnemiesList.Contains(enemy)) return;
_activeEnemiesList.Add(enemy);
TargetingVersion++;
}
/// <summary>
/// 将敌人从活跃列表中移除并触发 OnEnemyRemoved 事件。
/// 由 Automata.Die() 调用,替代直接操作活跃敌人列表。
/// </summary>
public void RemoveEnemy(Enemy enemy)
{
if (!_activeEnemiesList.Remove(enemy)) return;
TargetingVersion++;
OnEnemyRemoved?.Invoke(enemy);
}
/// <summary>
/// 清空活跃敌人列表(房间重置时调用)。不触发逐条 OnEnemyRemoved 事件。
/// </summary>
public void Reset()
{
if (_activeEnemiesList.Count == 0) return;
_activeEnemiesList.Clear();
TargetingVersion++;
}
private List<Enemy> CollectEnemiesInRadius(Vector3 origin, float radius, SortingType sortingType = SortingType.Nearest)
{
List<Enemy> enemiesInRadius = new List<Enemy>();
foreach (Enemy enemy in _activeEnemiesList)
{
if (IsEnemyInRadius(enemy, origin, radius))
{
enemiesInRadius.Add(enemy);
}
}
if (sortingType == SortingType.Nearest)
{
enemiesInRadius.Sort((a, b) =>
GetSurfaceDistance(origin, a).CompareTo(GetSurfaceDistance(origin, b)));
}
else if (sortingType == SortingType.Farthest)
{
enemiesInRadius.Sort((a, b) =>
GetSurfaceDistance(origin, b).CompareTo(GetSurfaceDistance(origin, a)));
}
return enemiesInRadius;
}
public bool IsEnemyInRadius(Enemy enemy, Vector3 origin, float radius)
{
if (enemy == null || enemy.statusSm.isDead) return false;
return GetSurfaceDistance(origin, enemy) <= radius;
}
[Button("Debug: Force GetHit All Enemies", ButtonSizes.Medium)]
[GUIColor(1f, 0.55f, 0.35f)]
private void DebugForceGetHitAllEnemies()
{
for (int i = 0; i < _activeEnemiesList.Count; i++)
{
Enemy enemy = _activeEnemiesList[i];
if (enemy == null || enemy.statusSm.isDead) continue;
Vector3 direction = Vector3.zero;
Player player = MainGameManager.Player;
if (player != null)
{
direction = enemy.transform.position - player.transform.position;
}
enemy.GetHit(
Breakthrough.Type.Forced,
out _,
DisruptionType.ForcedExternal,
direction);
}
}
[Button("Debug: Force Deplete All Enemies", ButtonSizes.Medium)]
[GUIColor(1f, 0.55f, 0.35f)]
private void DebugForceDepleteAllEnemies()
{
for (int i = 0; i < _activeEnemiesList.Count; i++)
{
Enemy enemy = _activeEnemiesList[i];
if (enemy == null || enemy.statusSm.isDead) continue;
Player player = MainGameManager.Player;
enemy.TakeDepletion(player, 999999, false);
}
}
private float GetSurfaceDistance(Vector3 origin, Enemy enemy)
{
if (enemy == null) return float.MaxValue;
float colliderRadius = enemy.collisionSc != null ? enemy.collisionSc.colliderRadius : 0f;
return Mathf.Max(0f, Vector3.Distance(origin, enemy.transform.position) - colliderRadius);
}
/// <summary>
/// 获取所有可见敌人
/// </summary>
public List<Enemy> GetVisibleEnemies(float radius = 50f)
{
return Query(radius).OnlyVisible().Candidates();
}
/// <summary>
/// 获取按屏幕X坐标从左到右排序的可见敌人列表
/// </summary>
public List<Enemy> GetVisibleEnemiesSortedByScreenX(float radius = 50f)
{
List<Enemy> visibleEnemies = GetVisibleEnemies(radius);
visibleEnemies.Sort((a, b) =>
{
Vector3 screenA = MainGameManager.Player.viewSc.playerCamera.WorldToScreenPoint(a.CenterPoint.position);
Vector3 screenB = MainGameManager.Player.viewSc.playerCamera.WorldToScreenPoint(b.CenterPoint.position);
return screenA.x.CompareTo(screenB.x);
});
return visibleEnemies;
}
}
}
}