From cc8982b131ab343a9277b87f4f2ecb9f7214ff47 Mon Sep 17 00:00:00 2001 From: basil <2428390463@qq.com> Date: Tue, 23 Jun 2026 20:42:24 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A8=E8=BF=9B=E8=AE=A1=E6=97=B6=E5=99=A8?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E7=9A=84=E9=9B=86=E4=B8=AD=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将敌人的攻击计时任务放到基类中进行创建 - 将 EnemySpawnScheduler 敌人生成调度器的刷怪计时任务迁移到 TimerComponent --- .../EnemyManager/EnemyManagerComponent.cs | 16 ++-- .../EnemyManager/EnemySpawnScheduler.cs | 96 ++++++------------- .../Entity/EntityLogic/Enemy/EnemyBase.cs | 24 +++++ .../Entity/EntityLogic/Enemy/MeleeEnemy.cs | 12 +-- .../Entity/EntityLogic/Enemy/RemoteEnemy.cs | 12 +-- .../TimerModule/Runtime/TimerComponent.cs | 2 +- 6 files changed, 69 insertions(+), 93 deletions(-) diff --git a/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemyManagerComponent.cs b/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemyManagerComponent.cs index a454ba7..3db84ad 100644 --- a/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemyManagerComponent.cs +++ b/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemyManagerComponent.cs @@ -58,6 +58,7 @@ namespace SepCore.EnemyManager _spawnCts?.Dispose(); _spawnCts = null; _enemyRegistry = null; + _spawnScheduler?.Reset(); _spawnScheduler = null; _entity = null; } @@ -71,7 +72,7 @@ namespace SepCore.EnemyManager _duration = _baseDuration; _currentLevel = level.Id; - _spawnScheduler.Init(level); + _spawnScheduler.Init(level, OnWaveSpawn); _enemyRegistry.Clear(); _currentSpawnEnemyId = 0; } @@ -79,13 +80,14 @@ namespace SepCore.EnemyManager public void OnUpdate(float elapseSeconds, float realElapseSeconds) { _enemyRegistry.PruneInvalidEntries(); - var spawnRequests = _spawnScheduler.Tick(elapseSeconds); - foreach (var request in spawnRequests) + _spawnScheduler.Tick(elapseSeconds); + } + + private void OnWaveSpawn(EnemyType enemyType, int count) + { + for (int j = 0; j < count; j++) { - for (int j = 0; j < request.Count; j++) - { - SpawnEnemyAsync(request.EnemyType).Forget(); - } + SpawnEnemyAsync(enemyType).Forget(); } } diff --git a/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemySpawnScheduler.cs b/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemySpawnScheduler.cs index 4961edc..912aaa4 100644 --- a/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemySpawnScheduler.cs +++ b/Assets/GameMain/Scripts/Runtime/CustomComponent/EnemyManager/EnemySpawnScheduler.cs @@ -1,7 +1,7 @@ using System; -using System.Collections.Generic; using SepCore.DataTable; using SepCore.Definition; +using SepCore.Timer; using UnityEngine; namespace SepCore.EnemyManager @@ -12,98 +12,67 @@ namespace SepCore.EnemyManager private float _elapsedTime; private float[] _baseIntervals; - private float[] _currentIntervals; private EnemyType[] _enemyTypes; private int[] _spawnCounts; - private float[] _nextSpawnTimes; + private TimerHandle[] _waveHandles; private float _spawnRateScale = 1f; + private Action _onSpawn; public float SpawnRateScale => _spawnRateScale; public float ElapsedTime => _elapsedTime; public int WaveCount => _enemyTypes?.Length ?? 0; - public void Init(DRLevel level) + public void Init(DRLevel level, Action onSpawn) { + GameEntry.Timer.CancelByOwner(this); + + _onSpawn = onSpawn; _baseIntervals = (float[])level.Intervals.Clone(); - _currentIntervals = (float[])_baseIntervals.Clone(); _enemyTypes = level.EntityTypes; _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 Tick(float deltaTime) + public void Tick(float deltaTime) { _elapsedTime += deltaTime; - var requests = new List(); - - 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) { - float newScale = Mathf.Max(MinSpawnRateScale, scale); - if (_baseIntervals == null || _baseIntervals.Length == 0) + _spawnRateScale = Mathf.Max(MinSpawnRateScale, scale); + 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 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; + GameEntry.Timer.SetInterval(_waveHandles[i], newInterval, adjustRemainingTime: true); } } public void Reset() { + GameEntry.Timer.CancelByOwner(this); _elapsedTime = 0; _baseIntervals = null; - _currentIntervals = null; _enemyTypes = null; _spawnCounts = null; - _nextSpawnTimes = null; + _waveHandles = null; _spawnRateScale = 1f; + _onSpawn = null; + } + + private void OnWaveTick(int waveIndex) + { + _onSpawn?.Invoke(_enemyTypes[waveIndex], _spawnCounts[waveIndex]); } private static float GetScaledInterval(float baseInterval, float scale) @@ -112,11 +81,4 @@ namespace SepCore.EnemyManager return baseInterval / safeScale; } } - - public struct SpawnRequest - { - public EnemyType EnemyType; - public int Count; - public int WaveIndex; - } } diff --git a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/EnemyBase.cs b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/EnemyBase.cs index 5509f92..850a7a8 100644 --- a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/EnemyBase.cs +++ b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/EnemyBase.cs @@ -2,6 +2,7 @@ using SepCore.AsyncTask; using SepCore.Definition; using SepCore.Entity; +using SepCore.Timer; using UnityEngine; public abstract class EnemyBase : TargetableObject @@ -15,6 +16,29 @@ public abstract class EnemyBase : TargetableObject 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) { base.OnShow(userData); diff --git a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/MeleeEnemy.cs b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/MeleeEnemy.cs index 19c77c1..304d4ef 100644 --- a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/MeleeEnemy.cs +++ b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/MeleeEnemy.cs @@ -1,7 +1,6 @@ using SepCore.Components; using SepCore.CustomUtility; using SepCore.Definition; -using SepCore.Timer; using UnityEngine; using UnityGameFramework.Runtime; @@ -24,8 +23,6 @@ namespace SepCore.Entity private int _attackDamage = 1; private float _sqrAttackRange; - private TimerHandle _attackTimerHandle; - private bool _canAttack; private AttackStateType _attackState = AttackStateType.Idle; @@ -71,8 +68,7 @@ namespace SepCore.Entity _attackDamage = Mathf.Max(1, _meleeEnemyData.AttackDamage); _sqrAttackRange = _attackRange * _attackRange; - _canAttack = false; - _attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this); + StartAttackCooldown(_attackCooldown); _attackState = AttackStateType.Idle; _targetableTarget = null; @@ -96,8 +92,7 @@ namespace SepCore.Entity _movementComponent.OnReset(); _healthComponent.OnReset(); _targetableTarget = null; - GameEntry.Timer.Cancel(_attackTimerHandle); - _attackTimerHandle = TimerHandle.Invalid; + CancelAttackCooldown(); _attackState = AttackStateType.Idle; base.OnHide(isShutdown, userData); @@ -155,8 +150,7 @@ namespace SepCore.Entity if (_canAttack) { - _canAttack = false; - _attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this); + ResetAttackCooldown(_attackCooldown); TransitionTo(AttackStateType.Attack); } diff --git a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/RemoteEnemy.cs b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/RemoteEnemy.cs index 5efdb52..6b72e8a 100644 --- a/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/RemoteEnemy.cs +++ b/Assets/GameMain/Scripts/Runtime/Entity/EntityLogic/Enemy/RemoteEnemy.cs @@ -3,7 +3,6 @@ using SepCore.AsyncTask; using SepCore.CustomUtility; using SepCore.Definition; using Cysharp.Threading.Tasks; -using SepCore.Timer; using UnityEngine; using UnityGameFramework.Runtime; @@ -28,8 +27,6 @@ namespace SepCore.Entity private float _attackRangeSquared; private float _attackCooldown = 1f; private int _attackDamage = 1; - private TimerHandle _attackTimerHandle; - private bool _canAttack; [SerializeField] private float _projectileSpeed = 12f; [SerializeField] private float _projectileLifeTime = 3f; @@ -83,8 +80,7 @@ namespace SepCore.Entity _projectileSpawnHeightOffset); _projectileAssetName = ReadStringParam(ProjectileAssetNameParamKey, _projectileAssetName); - _canAttack = false; - _attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this); + StartAttackCooldown(_attackCooldown); this.CachedTransform.position = enemyData.Position; } else @@ -112,8 +108,7 @@ namespace SepCore.Entity if (_canAttack) { TryFireProjectile(); - _canAttack = false; - _attackTimerHandle = GameEntry.Timer.ScheduleOnce(_attackCooldown, () => _canAttack = true, this); + ResetAttackCooldown(_attackCooldown); } } else @@ -127,8 +122,7 @@ namespace SepCore.Entity { _movementComponent.OnReset(); _healthComponent.OnReset(); - GameEntry.Timer.Cancel(_attackTimerHandle); - _attackTimerHandle = TimerHandle.Invalid; + CancelAttackCooldown(); base.OnHide(isShutdown, userData); } diff --git a/Assets/Plugins/TimerModule/Runtime/TimerComponent.cs b/Assets/Plugins/TimerModule/Runtime/TimerComponent.cs index 234ad4c..2cf1318 100644 --- a/Assets/Plugins/TimerModule/Runtime/TimerComponent.cs +++ b/Assets/Plugins/TimerModule/Runtime/TimerComponent.cs @@ -492,7 +492,7 @@ namespace SepCore.Timer return; } - taskInfo.RemainingTime = taskInfo.Interval; + taskInfo.RemainingTime += taskInfo.Interval; } private void InvokeCallback(TimerTaskInfo taskInfo)