vampire-like/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemyManagerComponent.cs

158 lines
4.7 KiB
C#

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<EntityBase> 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;
_currentLevel = level.Id;
_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();
ClearEnemies();
_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;
}
if (_player != null)
{
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
}
}