Unity 2D敌人生成异常:移动玩家时位置错误且无视水域规则
问题分析与修复方案
核心问题点
- 玩家位置获取时机错误:协程里先拿玩家位置再等待随机间隔,期间玩家移动后,生成逻辑仍用旧位置计算,导致敌人偏移当前玩家范围。
- 二维数组Y维度判断失误:判断Y坐标是否在地图范围内时,误用了
map.GetLength(0)(X方向长度),应该用map.GetLength(1)(Y方向长度),导致Y坐标越界时仍错误读取地图数据,出现敌人刷在水域的情况。 - Tile索引与世界坐标未对齐:若你的Tile为1x1单位且中心坐标是
(索引+0.5, 索引+0.5),直接用索引当世界坐标会让敌人刷在Tile边缘,看起来像在Tile之间。
修复后的代码
using System.Collections; using System.Collections.Generic; using UnityEngine; public class EnemySpawner : MonoBehaviour { public GameObject[] enemyPrefabArray; public GameObject player; [SerializeField] MapGenerator mapGeneratorScript; void OnEnable() => mapGeneratorScript.OnGeneratedMap += SpawnMobs; void OnDisable() => mapGeneratorScript.OnGeneratedMap -= SpawnMobs; void SpawnMobs() { StartCoroutine(SpawnEnemies(enemyPrefabArray[0], 0.1f, 0.2f, 20, 6)); } IEnumerator SpawnEnemies(GameObject enemyPrefab, float minInterval, float maxInterval, int maxEnemyCount, int withinRangeOfPlayer) { int numOfEnemies = 0; while (numOfEnemies < maxEnemyCount) { // 先等待间隔,再获取当前玩家最新位置 yield return new WaitForSeconds(Random.Range(minInterval, maxInterval)); Vector3 playerPos = player.transform.position; // 用FloorToInt确保玩家在Tile任意位置都能正确获取对应Tile索引 int playerTileX = Mathf.FloorToInt(playerPos.x); int playerTileY = Mathf.FloorToInt(playerPos.y); int randomXCoord = playerTileX + Random.Range(-withinRangeOfPlayer, withinRangeOfPlayer + 1); int randomYCoord = playerTileY + Random.Range(-withinRangeOfPlayer, withinRangeOfPlayer + 1); // 修正Y维度的地图范围判断 if (randomXCoord >= 0 && randomXCoord < mapGeneratorScript.map.GetLength(0) && randomYCoord >= 0 && randomYCoord < mapGeneratorScript.map.GetLength(1)) { bool isWaterTile = mapGeneratorScript.map[randomXCoord, randomYCoord] == 1; if (!isWaterTile) { // 若Tile中心是(索引+0.5, 索引+0.5)则用此坐标;若Tile直接用索引当中心,保留原Vector3(randomXCoord, randomYCoord, 0) Vector3 spawnPos = new Vector3(randomXCoord + 0.5f, randomYCoord + 0.5f, 0); Instantiate(enemyPrefab, spawnPos, Quaternion.identity); numOfEnemies++; Debug.Log($"Player X: {playerPos.x} Player Y: {playerPos.y}, Tile X: {randomXCoord} Tile Y: {randomYCoord}, Spawn Pos: {spawnPos}"); } else { Debug.Log($"Avoided Spawn on Water at Tile ({randomXCoord}, {randomYCoord})"); } } } } }
关键修改说明
- 调整玩家位置获取顺序:先等待间隔再获取玩家当前位置,确保生成逻辑基于最新玩家位置。
- 修正地图范围判断:将Y维度的
map.GetLength(0)改为map.GetLength(1),避免越界读取错误的地图数据。 - 优化Tile索引计算:用
Mathf.FloorToInt替代RoundToInt,玩家在Tile边缘时也能正确获取对应Tile的索引。 - 对齐Tile中心与生成坐标:添加+0.5让敌人直接生成在Tile中心,解决偏移到Tile之间的问题;若你的Tile本身以索引为中心,可去掉该偏移。
内容的提问来源于stack exchange,提问作者Uboy
相关产品推荐
相关产品推荐

