更新变量后实例化对象未达预期的Unity技术问题
问题分析与解决
问题背景
我有两个Unity脚本:SpawnManager和Enemy。需求是在SpawnManager的SpawnEnemyWave函数中生成3个敌人:当随机数小于5时,生成1个高移动速度的tough enemy,其余为无移动速度的weak enemy。
SpawnManager 代码
bool toughEnemy = true; int waveNumber = 3; float randomNumber = Random.Range(0, 10); void Start() { SpawnEnemyWave(waveNumber); } void SpawnEnemyWave(int enemiesToSpawn) { float randomNumber = Random.Range(0, 10); print(randomNumber); for (int i = 0; i < enemiesToSpawn; i++) { if ((randomNumber < 5) && toughEnemy) { print("Tough"); Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation); toughEnemy = false; //确保每波仅1个tough enemy } else { print("Weak"); Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation); } } }
Enemy 代码
void Start() { spawnManager = GameObject.Find("Spawn Manager").GetComponent<SpawnManager>(); if (spawnManager.toughEnemy) { speed = 1; print("Speed " + speed); } else { speed = 0; print("Speed " + speed); } }
问题现象
当随机数为0时,日志显示有1个Tough敌人,但所有敌人的speed均为0;预期应为第一个敌人speed=1,其余为0。
问题根源
核心是Unity脚本的执行时机不匹配:
Instantiate创建Enemy对象后,该对象的Start方法不会立即执行,而是延迟到当前帧所有同步逻辑执行完毕后才触发。- SpawnManager生成第一个Tough敌人后,立刻将
toughEnemy设为false。等所有Enemy的Start方法执行时,读取到的toughEnemy已经是false,导致所有敌人的speed都被设为0。
解决方案
方案1:实例化时直接设置敌人属性(推荐)
不需要让Enemy读取SpawnManager的状态,而是在生成时直接给Enemy赋值,逻辑更清晰且避免时机问题:
修改SpawnManager的循环逻辑:
void SpawnEnemyWave(int enemiesToSpawn) { float randomNumber = Random.Range(0, 10); print(randomNumber); bool hasSpawnedTough = false; for (int i = 0; i < enemiesToSpawn; i++) { bool isTough = (randomNumber < 5) && !hasSpawnedTough; GameObject enemy = Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation); Enemy enemyComp = enemy.GetComponent<Enemy>(); if (isTough) { print("Tough"); enemyComp.speed = 1; hasSpawnedTough = true; } else { print("Weak"); enemyComp.speed = 0; } } }
简化Enemy脚本:
public float speed; void Start() { print("Speed " + speed); }
方案2:传递敌人类型标记
给Enemy添加一个公共标记变量,生成时直接赋值:
SpawnManager修改:
void SpawnEnemyWave(int enemiesToSpawn) { float randomNumber = Random.Range(0, 10); print(randomNumber); bool shouldSpawnTough = randomNumber < 5; bool spawnedTough = false; for (int i = 0; i < enemiesToSpawn; i++) { bool isCurrentTough = shouldSpawnTough && !spawnedTough; GameObject enemy = Instantiate(enemyPrefab, GenerateSpawnPosition(), enemyPrefab.transform.rotation); enemy.GetComponent<Enemy>().isTough = isCurrentTough; if (isCurrentTough) { print("Tough"); spawnedTough = true; } else { print("Weak"); } } }
Enemy脚本修改:
public bool isTough; public float speed; void Start() { speed = isTough ? 1 : 0; print("Speed " + speed); }
方案3:调整脚本执行顺序(不推荐)
在Unity编辑器的Project Settings -> Script Execution Order中,将Enemy的Start执行顺序设为早于SpawnManager。但这种方式依赖Unity的执行顺序规则,后续维护容易出问题,不建议使用。
内容的提问来源于stack exchange,提问作者Heijs7
相关产品推荐
相关产品推荐

