游戏波次系统:如何实现间隔指定时间生成敌人?
你的波次系统延迟逻辑问题解析与修复方案
嘿,我看了你这段用来实现敌人波次生成的代码,一眼就发现了核心问题:你在普通函数里用for循环累加Time.deltaTime的方式,根本没法实现“生成下一个敌人前等待指定时长”的效果。
为啥你的代码不工作?
先给你拆解下逻辑问题:Unity的Time.deltaTime是当前帧和上一帧的时间差,而ExecuteWaveAction如果是在Update或者普通调用里执行,整个for循环会在一帧内就跑完——也就是说,timeLeftToSpawnEnemy会瞬间累加到超过action.spawnRate的值,然后一次性生成所有敌人,完全没有等待的过程。
你的原代码(片段):
void ExecuteWaveAction(WaveAction action) { int numberOfSpawns = spawnLocations.Length; int currentSpawnToInstantiate = 0; float timeLeftToSpawnEnemy = 0f; for (int i = 0; i < action.quantityOfEnemysToSpawn; i++) { if (timeLeftToSpawnEnemy < action.spawnRate) { timeLeftToSpawnEnemy += Time.deltaTime; i--; } else { // 实例化敌人的逻辑... } } }
这段代码本质上是在一帧里死循环,直到timeLeftToSpawnEnemy达标,然后批量生成敌人,和你想要的“逐个间隔生成”完全不是一回事。
正确的实现方式:用Unity协程(Coroutine)
协程是Unity专门用来处理异步、延迟逻辑的工具,它能让函数暂停执行,等指定时间到了再继续跑,完美适配你的波次生成需求。下面是修改后的完整实现:
1. 把函数改成协程
// 注意返回值是IEnumerator,这是协程的标志 IEnumerator ExecuteWaveAction(WaveAction action) { int numberOfSpawns = spawnLocations.Length; int currentSpawnIndex = 0; // 循环生成指定数量的敌人 for (int i = 0; i < action.quantityOfEnemysToSpawn; i++) { // 循环选择出生点(你也可以改成随机选,看需求) Transform spawnPoint = spawnLocations[currentSpawnIndex]; currentSpawnIndex = (currentSpawnIndex + 1) % numberOfSpawns; // 实例化敌人(这里替换成你的敌人预制体逻辑) GameObject newEnemy = Instantiate(action.enemyPrefab, spawnPoint.position, spawnPoint.rotation); // 这里可以加敌人的初始化代码,比如设置血量、攻击值之类的 // 如果不是最后一个敌人,就等待指定的间隔时间 if (i != action.quantityOfEnemysToSpawn - 1) { yield return new WaitForSeconds(action.spawnRate); } } // 波次结束后可以加一些逻辑,比如通知玩家波次完成、解锁奖励等 Debug.Log("当前波次敌人已全部生成!"); }
2. 如何启动这个协程?
不能像调用普通函数那样直接调用,得用StartCoroutine:
// 比如在波次开始的触发逻辑里调用 public void StartNextWave(WaveAction waveAction) { StartCoroutine(ExecuteWaveAction(waveAction)); }
额外的实用优化
- 如果需要不受游戏时间缩放影响的精确等待(比如暂停游戏时不想继续生成敌人),可以把
WaitForSeconds换成WaitForSecondsRealtime。 - 要是需要支持中途取消波次,可以保存协程的引用,然后用
StopCoroutine终止:
private Coroutine _currentWaveCoroutine; public void StartNextWave(WaveAction waveAction) { // 如果有正在运行的波次,先取消 if (_currentWaveCoroutine != null) { StopCoroutine(_currentWaveCoroutine); } _currentWaveCoroutine = StartCoroutine(ExecuteWaveAction(waveAction)); } public void CancelCurrentWave() { if (_currentWaveCoroutine != null) { StopCoroutine(_currentWaveCoroutine); _currentWaveCoroutine = null; Debug.Log("当前波次已取消"); } }
内容的提问来源于stack exchange,提问作者Nícolas
相关产品推荐
相关产品推荐

