推进计时器逻辑的集中管理
- 将敌人的攻击计时任务放到基类中进行创建 - 将 EnemySpawnScheduler 敌人生成调度器的刷怪计时任务迁移到 TimerComponent
This commit is contained in:
parent
846e4d6f44
commit
cc8982b131
|
|
@ -58,6 +58,7 @@ namespace SepCore.EnemyManager
|
||||||
_spawnCts?.Dispose();
|
_spawnCts?.Dispose();
|
||||||
_spawnCts = null;
|
_spawnCts = null;
|
||||||
_enemyRegistry = null;
|
_enemyRegistry = null;
|
||||||
|
_spawnScheduler?.Reset();
|
||||||
_spawnScheduler = null;
|
_spawnScheduler = null;
|
||||||
_entity = null;
|
_entity = null;
|
||||||
}
|
}
|
||||||
|
|
@ -71,7 +72,7 @@ namespace SepCore.EnemyManager
|
||||||
_duration = _baseDuration;
|
_duration = _baseDuration;
|
||||||
_currentLevel = level.Id;
|
_currentLevel = level.Id;
|
||||||
|
|
||||||
_spawnScheduler.Init(level);
|
_spawnScheduler.Init(level, OnWaveSpawn);
|
||||||
_enemyRegistry.Clear();
|
_enemyRegistry.Clear();
|
||||||
_currentSpawnEnemyId = 0;
|
_currentSpawnEnemyId = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -79,13 +80,14 @@ namespace SepCore.EnemyManager
|
||||||
public void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
public void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||||
{
|
{
|
||||||
_enemyRegistry.PruneInvalidEntries();
|
_enemyRegistry.PruneInvalidEntries();
|
||||||
var spawnRequests = _spawnScheduler.Tick(elapseSeconds);
|
_spawnScheduler.Tick(elapseSeconds);
|
||||||
foreach (var request in spawnRequests)
|
}
|
||||||
|
|
||||||
|
private void OnWaveSpawn(EnemyType enemyType, int count)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < count; j++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < request.Count; j++)
|
SpawnEnemyAsync(enemyType).Forget();
|
||||||
{
|
|
||||||
SpawnEnemyAsync(request.EnemyType).Forget();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using SepCore.DataTable;
|
using SepCore.DataTable;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
|
using SepCore.Timer;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace SepCore.EnemyManager
|
namespace SepCore.EnemyManager
|
||||||
|
|
@ -12,98 +12,67 @@ namespace SepCore.EnemyManager
|
||||||
|
|
||||||
private float _elapsedTime;
|
private float _elapsedTime;
|
||||||
private float[] _baseIntervals;
|
private float[] _baseIntervals;
|
||||||
private float[] _currentIntervals;
|
|
||||||
private EnemyType[] _enemyTypes;
|
private EnemyType[] _enemyTypes;
|
||||||
private int[] _spawnCounts;
|
private int[] _spawnCounts;
|
||||||
private float[] _nextSpawnTimes;
|
private TimerHandle[] _waveHandles;
|
||||||
private float _spawnRateScale = 1f;
|
private float _spawnRateScale = 1f;
|
||||||
|
private Action<EnemyType, int> _onSpawn;
|
||||||
|
|
||||||
public float SpawnRateScale => _spawnRateScale;
|
public float SpawnRateScale => _spawnRateScale;
|
||||||
public float ElapsedTime => _elapsedTime;
|
public float ElapsedTime => _elapsedTime;
|
||||||
public int WaveCount => _enemyTypes?.Length ?? 0;
|
public int WaveCount => _enemyTypes?.Length ?? 0;
|
||||||
|
|
||||||
public void Init(DRLevel level)
|
public void Init(DRLevel level, Action<EnemyType, int> onSpawn)
|
||||||
{
|
{
|
||||||
|
GameEntry.Timer.CancelByOwner(this);
|
||||||
|
|
||||||
|
_onSpawn = onSpawn;
|
||||||
_baseIntervals = (float[])level.Intervals.Clone();
|
_baseIntervals = (float[])level.Intervals.Clone();
|
||||||
_currentIntervals = (float[])_baseIntervals.Clone();
|
|
||||||
_enemyTypes = level.EntityTypes;
|
_enemyTypes = level.EntityTypes;
|
||||||
_spawnCounts = level.EntityCounts;
|
_spawnCounts = level.EntityCounts;
|
||||||
|
_elapsedTime = 0f;
|
||||||
|
|
||||||
SetSpawnRateScale(_spawnRateScale);
|
_waveHandles = new TimerHandle[_baseIntervals.Length];
|
||||||
|
for (int i = 0; i < _baseIntervals.Length; i++)
|
||||||
|
{
|
||||||
|
int waveIndex = i;
|
||||||
|
float interval = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
||||||
|
_waveHandles[i] = GameEntry.Timer.ScheduleRepeat(interval, () => OnWaveTick(waveIndex), -1, this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SpawnRequest> Tick(float deltaTime)
|
public void Tick(float deltaTime)
|
||||||
{
|
{
|
||||||
_elapsedTime += deltaTime;
|
_elapsedTime += deltaTime;
|
||||||
var requests = new List<SpawnRequest>();
|
|
||||||
|
|
||||||
if (_nextSpawnTimes == null) return requests;
|
|
||||||
|
|
||||||
for (int i = 0; i < _nextSpawnTimes.Length; i++)
|
|
||||||
{
|
|
||||||
if (_elapsedTime < _nextSpawnTimes[i]) continue;
|
|
||||||
|
|
||||||
requests.Add(new SpawnRequest
|
|
||||||
{
|
|
||||||
EnemyType = _enemyTypes[i],
|
|
||||||
Count = _spawnCounts[i],
|
|
||||||
WaveIndex = i
|
|
||||||
});
|
|
||||||
|
|
||||||
_nextSpawnTimes[i] += _currentIntervals[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return requests;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSpawnRateScale(float scale)
|
public void SetSpawnRateScale(float scale)
|
||||||
{
|
{
|
||||||
float newScale = Mathf.Max(MinSpawnRateScale, scale);
|
_spawnRateScale = Mathf.Max(MinSpawnRateScale, scale);
|
||||||
if (_baseIntervals == null || _baseIntervals.Length == 0)
|
if (_waveHandles == null) return;
|
||||||
|
|
||||||
|
for (int i = 0; i < _waveHandles.Length; i++)
|
||||||
{
|
{
|
||||||
_spawnRateScale = newScale;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasRuntimeState = _nextSpawnTimes != null && _currentIntervals != null &&
|
|
||||||
_nextSpawnTimes.Length == _baseIntervals.Length &&
|
|
||||||
_currentIntervals.Length == _baseIntervals.Length;
|
|
||||||
float oldScale = _spawnRateScale;
|
|
||||||
_spawnRateScale = newScale;
|
|
||||||
|
|
||||||
if (!hasRuntimeState)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < _baseIntervals.Length; i++)
|
|
||||||
{
|
|
||||||
_currentIntervals[i] = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
|
||||||
}
|
|
||||||
|
|
||||||
_nextSpawnTimes = (float[])_currentIntervals.Clone();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _baseIntervals.Length; i++)
|
|
||||||
{
|
|
||||||
float oldInterval = GetScaledInterval(_baseIntervals[i], oldScale);
|
|
||||||
float newInterval = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
float newInterval = GetScaledInterval(_baseIntervals[i], _spawnRateScale);
|
||||||
|
GameEntry.Timer.SetInterval(_waveHandles[i], newInterval, adjustRemainingTime: true);
|
||||||
float remainTime = Mathf.Max(0f, _nextSpawnTimes[i] - _elapsedTime);
|
|
||||||
float remainRatio = oldInterval > Mathf.Epsilon ? Mathf.Clamp01(remainTime / oldInterval) : 0f;
|
|
||||||
|
|
||||||
_currentIntervals[i] = newInterval;
|
|
||||||
_nextSpawnTimes[i] = _elapsedTime + newInterval * remainRatio;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
|
GameEntry.Timer.CancelByOwner(this);
|
||||||
_elapsedTime = 0;
|
_elapsedTime = 0;
|
||||||
_baseIntervals = null;
|
_baseIntervals = null;
|
||||||
_currentIntervals = null;
|
|
||||||
_enemyTypes = null;
|
_enemyTypes = null;
|
||||||
_spawnCounts = null;
|
_spawnCounts = null;
|
||||||
_nextSpawnTimes = null;
|
_waveHandles = null;
|
||||||
_spawnRateScale = 1f;
|
_spawnRateScale = 1f;
|
||||||
|
_onSpawn = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWaveTick(int waveIndex)
|
||||||
|
{
|
||||||
|
_onSpawn?.Invoke(_enemyTypes[waveIndex], _spawnCounts[waveIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float GetScaledInterval(float baseInterval, float scale)
|
private static float GetScaledInterval(float baseInterval, float scale)
|
||||||
|
|
@ -112,11 +81,4 @@ namespace SepCore.EnemyManager
|
||||||
return baseInterval / safeScale;
|
return baseInterval / safeScale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct SpawnRequest
|
|
||||||
{
|
|
||||||
public EnemyType EnemyType;
|
|
||||||
public int Count;
|
|
||||||
public int WaveIndex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using SepCore.AsyncTask;
|
using SepCore.AsyncTask;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using SepCore.Entity;
|
using SepCore.Entity;
|
||||||
|
using SepCore.Timer;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
public abstract class EnemyBase : TargetableObject
|
public abstract class EnemyBase : TargetableObject
|
||||||
|
|
@ -15,6 +16,29 @@ public abstract class EnemyBase : TargetableObject
|
||||||
|
|
||||||
protected EnemyData _enemyData;
|
protected EnemyData _enemyData;
|
||||||
|
|
||||||
|
protected bool _canAttack;
|
||||||
|
protected TimerHandle _attackTimerHandle;
|
||||||
|
|
||||||
|
protected void StartAttackCooldown(float cooldown)
|
||||||
|
{
|
||||||
|
_canAttack = false;
|
||||||
|
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ResetAttackCooldown(float cooldown)
|
||||||
|
{
|
||||||
|
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||||
|
_canAttack = false;
|
||||||
|
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(cooldown, () => _canAttack = true, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void CancelAttackCooldown()
|
||||||
|
{
|
||||||
|
GameEntry.Timer.Cancel(_attackTimerHandle);
|
||||||
|
_attackTimerHandle = TimerHandle.Invalid;
|
||||||
|
_canAttack = false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnShow(object userData)
|
protected override void OnShow(object userData)
|
||||||
{
|
{
|
||||||
base.OnShow(userData);
|
base.OnShow(userData);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using SepCore.Components;
|
using SepCore.Components;
|
||||||
using SepCore.CustomUtility;
|
using SepCore.CustomUtility;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using SepCore.Timer;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
|
|
@ -24,8 +23,6 @@ namespace SepCore.Entity
|
||||||
private int _attackDamage = 1;
|
private int _attackDamage = 1;
|
||||||
|
|
||||||
private float _sqrAttackRange;
|
private float _sqrAttackRange;
|
||||||
private TimerHandle _attackTimerHandle;
|
|
||||||
private bool _canAttack;
|
|
||||||
|
|
||||||
private AttackStateType _attackState = AttackStateType.Idle;
|
private AttackStateType _attackState = AttackStateType.Idle;
|
||||||
|
|
||||||
|
|
@ -71,8 +68,7 @@ namespace SepCore.Entity
|
||||||
_attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage);
|
_attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage);
|
||||||
_sqrAttackRange = _attackRange * _attackRange;
|
_sqrAttackRange = _attackRange * _attackRange;
|
||||||
|
|
||||||
_canAttack = false;
|
StartAttackCooldown(_attackCooldown);
|
||||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
|
||||||
_attackState = AttackStateType.Idle;
|
_attackState = AttackStateType.Idle;
|
||||||
_targetableTarget = null;
|
_targetableTarget = null;
|
||||||
|
|
||||||
|
|
@ -96,8 +92,7 @@ namespace SepCore.Entity
|
||||||
_movementComponent.OnReset();
|
_movementComponent.OnReset();
|
||||||
_healthComponent.OnReset();
|
_healthComponent.OnReset();
|
||||||
_targetableTarget = null;
|
_targetableTarget = null;
|
||||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
CancelAttackCooldown();
|
||||||
_attackTimerHandle = TimerHandle.Invalid;
|
|
||||||
_attackState = AttackStateType.Idle;
|
_attackState = AttackStateType.Idle;
|
||||||
|
|
||||||
base.OnHide(isShutdown, userData);
|
base.OnHide(isShutdown, userData);
|
||||||
|
|
@ -155,8 +150,7 @@ namespace SepCore.Entity
|
||||||
|
|
||||||
if (_canAttack)
|
if (_canAttack)
|
||||||
{
|
{
|
||||||
_canAttack = false;
|
ResetAttackCooldown(_attackCooldown);
|
||||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
|
||||||
TransitionTo(AttackStateType.Attack);
|
TransitionTo(AttackStateType.Attack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ using SepCore.AsyncTask;
|
||||||
using SepCore.CustomUtility;
|
using SepCore.CustomUtility;
|
||||||
using SepCore.Definition;
|
using SepCore.Definition;
|
||||||
using Cysharp.Threading.Tasks;
|
using Cysharp.Threading.Tasks;
|
||||||
using SepCore.Timer;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityGameFramework.Runtime;
|
using UnityGameFramework.Runtime;
|
||||||
|
|
||||||
|
|
@ -28,8 +27,6 @@ namespace SepCore.Entity
|
||||||
private float _attackRangeSquared;
|
private float _attackRangeSquared;
|
||||||
private float _attackCooldown = 1f;
|
private float _attackCooldown = 1f;
|
||||||
private int _attackDamage = 1;
|
private int _attackDamage = 1;
|
||||||
private TimerHandle _attackTimerHandle;
|
|
||||||
private bool _canAttack;
|
|
||||||
|
|
||||||
[SerializeField] private float _projectileSpeed = 12f;
|
[SerializeField] private float _projectileSpeed = 12f;
|
||||||
[SerializeField] private float _projectileLifeTime = 3f;
|
[SerializeField] private float _projectileLifeTime = 3f;
|
||||||
|
|
@ -83,8 +80,7 @@ namespace SepCore.Entity
|
||||||
_projectileSpawnHeightOffset);
|
_projectileSpawnHeightOffset);
|
||||||
_projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName);
|
_projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName);
|
||||||
|
|
||||||
_canAttack = false;
|
StartAttackCooldown(_attackCooldown);
|
||||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
|
||||||
this.CachedTransform.position = enemyData.Position;
|
this.CachedTransform.position = enemyData.Position;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -112,8 +108,7 @@ namespace SepCore.Entity
|
||||||
if (_canAttack)
|
if (_canAttack)
|
||||||
{
|
{
|
||||||
TryFireProjectile();
|
TryFireProjectile();
|
||||||
_canAttack = false;
|
ResetAttackCooldown(_attackCooldown);
|
||||||
_attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -127,8 +122,7 @@ namespace SepCore.Entity
|
||||||
{
|
{
|
||||||
_movementComponent.OnReset();
|
_movementComponent.OnReset();
|
||||||
_healthComponent.OnReset();
|
_healthComponent.OnReset();
|
||||||
GameEntry.Timer.Cancel(_attackTimerHandle);
|
CancelAttackCooldown();
|
||||||
_attackTimerHandle = TimerHandle.Invalid;
|
|
||||||
|
|
||||||
base.OnHide(isShutdown, userData);
|
base.OnHide(isShutdown, userData);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ namespace SepCore.Timer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
taskInfo.RemainingTime = taskInfo.Interval;
|
taskInfo.RemainingTime += taskInfo.Interval;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InvokeCallback(TimerTaskInfo taskInfo)
|
private void InvokeCallback(TimerTaskInfo taskInfo)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue