You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity Enemy Spawner While循环无法生成指定数量敌人

敌人生成脚本异常问题

我尝试在测试区域内自动生成指定数量的敌人,逻辑为当前敌人数量小于期望数量时,激活循环生成。但脚本存在问题:初始运行无法实例化正确数量的敌人,游戏中敌人被击杀后虽会补充,但始终达不到期望数量。

不同期望数量对应的实际生成结果:

期望敌人数量(enemiesDesired)实际生成数量
10
21
31
42
52
63
73
83
93
104
114
125
135
146

初始代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnEnemies : MonoBehaviour
{
        //Enemies array
        public GameObject[] Enemies;
        public int enemiesInArray;

        //Spawn enemy within these positions on the map
        private int xPos;
        private int zPos;
        private int yPos;

        private int randomEnemy;

        public static int enemiesCurrentCount; //Amount of enemies in game currently
        public int enemiesDesired; //Amount of enemies desired in game at the same time

        public bool keepSpawning;

        //Wait timers
        public float startWaitSeconds;
        public float spawnWaitSeconds;


    void Start()
    {
        enemiesCurrentCount = 0;
        keepSpawning = true;
    }

    void Update()
    {
        //Check if new enemies should be spawned
        if (enemiesCurrentCount <= enemiesDesired)
        {
            keepSpawning = true;
            StartCoroutine(RandomSpawnEnemies());
        }
        else
        {
            keepSpawning = false;
        }
    }

    //Spawn Enemies
    IEnumerator RandomSpawnEnemies()
    {
        yield return new WaitForSeconds(startWaitSeconds);

        while (keepSpawning)
        {
            randomEnemy = Random.Range(0, enemiesInArray);
            xPos = Random.Range(-10, 8);
            zPos = Random.Range(17, 30);
            Instantiate(Enemies[randomEnemy], new Vector3(xPos, yPos, zPos), Quaternion.identity);
            enemiesCurrentCount += 1;
            yield return new WaitForSeconds(spawnWaitSeconds);
        }
    }

}

测试用修改代码

为定位问题,我将生成逻辑移至Start阶段,但设置enemiesDesired=5时仍仅生成2只敌人:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnEnemies : MonoBehaviour
{
        //Enemies array
        public GameObject[] Enemies;
        public int enemiesInArray;

        //Spawn enemy within these positions on the map
        private int xPos;
        private int zPos;
        private int yPos;

        private int randomEnemy;

        public int enemiesCurrentCount = 0; //Amount of enemies in game currently
        public int enemiesDesired = 5; //Amount of enemies desired in game at the same time

        //Wait timers
        public float spawnWaitSeconds;


    void Start()
    {
        StartCoroutine(SpawnRandomEnemies());
    }

    void Update()
    {

    }

    //Spawn Enemies
    IEnumerator SpawnRandomEnemies()
    {
        while (enemiesCurrentCount < enemiesDesired)
        {
            randomEnemy = Random.Range(0, enemiesInArray);
            xPos = Random.Range(-10, 8);
            zPos = Random.Range(17, 30);
            Instantiate(Enemies[randomEnemy], new Vector3(xPos, 1, zPos), Quaternion.identity);
            enemiesCurrentCount += 1;
            yield return new WaitForSeconds(0.1f);
        }
    }
}

问题根源与修复方案

核心问题

  1. 初始代码重复启动协程:Update每帧检测到需要生成就启动一次协程,导致多个协程并行运行,同时修改enemiesCurrentCount,计数逻辑完全混乱,最终生成数量失控。
  2. 测试代码的潜在漏洞:
    • enemiesInArray为手动赋值,若与Enemies数组实际长度不符,比如设为0或小于数组长度,Random.Range(0, enemiesInArray)会触发错误,协程直接中断,停止生成。
    • 生成的敌人可能因碰撞或自身脚本被立刻销毁,导致场景中看不到敌人,但计数已增加。

修复代码

修正后的持续生成脚本

解决重复启动协程的问题,同时增加数组有效性检查:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnEnemies : MonoBehaviour
{
    public GameObject[] Enemies;
    public int enemiesDesired;
    public static int enemiesCurrentCount;

    public float startWaitSeconds;
    public float spawnWaitSeconds;

    private bool _isSpawning; // 标记协程是否在运行,避免重复启动

    void Start()
    {
        enemiesCurrentCount = 0;
        _isSpawning = false;
    }

    void Update()
    {
        // 仅在需要生成且无协程运行时启动
        if (enemiesCurrentCount < enemiesDesired && !_isSpawning)
        {
            StartCoroutine(SpawnEnemiesCoroutine());
        }
    }

    IEnumerator SpawnEnemiesCoroutine()
    {
        _isSpawning = true;
        yield return new WaitForSeconds(startWaitSeconds);

        while (enemiesCurrentCount < enemiesDesired)
        {
            // 先检查数组是否有效
            if (Enemies.Length == 0)
            {
                Debug.LogError("敌人预制体数组未赋值!");
                break;
            }

            int randomIndex = Random.Range(0, Enemies.Length);
            Vector3 spawnPos = new Vector3(Random.Range(-10, 8), 0, Random.Range(17, 30));
            Instantiate(Enemies[randomIndex], spawnPos, Quaternion.identity);
            enemiesCurrentCount++;

            yield return new WaitForSeconds(spawnWaitSeconds);
        }

        _isSpawning = false;
    }
}

修正后的测试脚本

移除手动设置的enemiesInArray,直接使用数组长度,添加日志排查生成情况:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpawnEnemies : MonoBehaviour
{
    public GameObject[] Enemies;
    public int enemiesCurrentCount = 0;
    public int enemiesDesired = 5;

    void Start()
    {
        StartCoroutine(SpawnTestCoroutine());
    }

    IEnumerator SpawnTestCoroutine()
    {
        if (Enemies.Length == 0)
        {
            Debug.LogError("敌人预制体数组为空!");
            yield break;
        }

        while (enemiesCurrentCount < enemiesDesired)
        {
            int randomIndex = Random.Range(0, Enemies.Length);
            Vector3 spawnPos = new Vector3(Random.Range(-10, 8), 1, Random.Range(17, 30));
            GameObject enemy = Instantiate(Enemies[randomIndex], spawnPos, Quaternion.identity);
            
            Debug.Log($"生成第{enemiesCurrentCount + 1}只敌人,当前计数:{enemiesCurrentCount + 1}");
            enemiesCurrentCount++;

            // 可选:检查敌人是否被立刻销毁
            if (!enemy)
            {
                Debug.LogWarning("生成的敌人已被销毁");
                enemiesCurrentCount--;
            }

            yield return new WaitForSeconds(0.1f);
        }
        Debug.Log($"生成完成,最终计数:{enemiesCurrentCount}");
    }
}

额外排查点

  • 检查敌人预制体:是否有脚本在Awake/Start中自动销毁敌人?
  • 检查生成位置:是否生成在碰撞体内部(比如地面以下),导致敌人被挤开或销毁?可将y轴数值调高测试。
  • 确认计数逻辑:敌人被击杀时是否正确执行enemiesCurrentCount--,且没有其他代码错误修改该数值。

内容的提问来源于stack exchange,提问作者WolfPG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 16:15:34