using System.Collections.Generic; using Cysharp.Threading.Tasks; using SepCore.DataTable; using SepCore.Definition; using SepCore.Entity; using GameFramework.Event; using SepCore.AsyncTask; using SepCore.CustomUtility; using UnityEngine; using UnityGameFramework.Runtime; namespace SepCore.EnemyManager { public class EnemyManagerComponent : GameFrameworkComponent { private const string EnemyGroupName = "Enemy"; private EntityComponent _entity; private EnemyRegistry _enemyRegistry; private EnemySpawnScheduler _spawnScheduler; public List Enemies => _enemyRegistry?.Enemies; [SerializeField] private int _spawnEnemyMaxCount = 5000; [SerializeField] private int _spawnDistanceFromPlayer = 20; private int _currentSpawnEnemyId; private int _currentLevel; private float _duration; private float _baseDuration; private Transform _player; private ISpawnPositionStrategy _spawnPositionStrategy; public float SpawnRateScale => _spawnScheduler?.SpawnRateScale ?? 1f; public float BattleDuration => _duration; public float ElapsedBattleTime => _spawnScheduler?.ElapsedTime ?? 0f; public int CurrentEnemyCount => _enemyRegistry?.Count ?? 0; #region Lifecycle private void Start() { _entity = GameEntry.Entity; _enemyRegistry = new EnemyRegistry(); _spawnScheduler = new EnemySpawnScheduler(); GameEntry.Event.Subscribe(HideEntityCompleteEventArgs.EventId, OnHideEntityComplete); } private void OnDestroy() { GameEntry.Event.Unsubscribe(HideEntityCompleteEventArgs.EventId, OnHideEntityComplete); _enemyRegistry = null; _spawnScheduler = null; _entity = null; } public void OnInit(DRLevel level, Player player) { _player = player != null ? player.CachedTransform : null; _spawnPositionStrategy = new RandomCircleSpawnStrategy(_spawnDistanceFromPlayer); _baseDuration = level.Duration; _duration = _baseDuration; _spawnScheduler.Init(level); _enemyRegistry.Clear(); _currentSpawnEnemyId = 0; } public void OnUpdate(float elapseSeconds, float realElapseSeconds) { var spawnRequests = _spawnScheduler.Tick(elapseSeconds); foreach (var request in spawnRequests) { for (int j = 0; j < request.Count; j++) { SpawnEnemyAsync(request.EnemyType).Forget(); } } } public void OnReset() { _spawnScheduler.Reset(); _enemyRegistry.Clear(); _currentSpawnEnemyId = 0; _currentLevel = 0; _baseDuration = 0; _duration = 0; } #endregion private async UniTaskVoid SpawnEnemyAsync(EnemyType enemyType) { if (_player == null) return; if (_enemyRegistry.Count >= _spawnEnemyMaxCount) return; int entityPoolId = _currentSpawnEnemyId % _spawnEnemyMaxCount; var enemyData = EntityDataFactory.Create(entityPoolId, enemyType, _currentLevel); enemyData.Position = _spawnPositionStrategy.GetSpawnPosition(_player); _currentSpawnEnemyId++; EnemyBase enemy = await _entity.ShowEnemyAsync(enemyData); if (enemy == null) { return; } enemy.SetTarget(_player); _enemyRegistry.Register(enemy); } public void ClearEnemies() { foreach (var enemy in _enemyRegistry.Enemies) { if (enemy == null || !enemy.Available) continue; _entity.HideEntity(enemy); } _enemyRegistry.Clear(); } public bool TryGetEnemy(int entityId, out EntityBase enemy) { return _enemyRegistry.TryGet(entityId, out enemy); } public void SetSpawnRateScale(float scale) { _spawnScheduler.SetSpawnRateScale(scale); } #region Event Handler private void OnHideEntityComplete(object sender, GameEventArgs e) { if (e is not HideEntityCompleteEventArgs ne) return; string entityGroupName = ne.EntityGroup.Name; if (entityGroupName == EnemyGroupName) { _enemyRegistry.Remove(ne.EntityId); } } #endregion } }