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

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})");
                }
            }
        }
    }
}

关键修改说明

  1. 调整玩家位置获取顺序:先等待间隔再获取玩家当前位置,确保生成逻辑基于最新玩家位置。
  2. 修正地图范围判断:将Y维度的map.GetLength(0)改为map.GetLength(1),避免越界读取错误的地图数据。
  3. 优化Tile索引计算:用Mathf.FloorToInt替代RoundToInt,玩家在Tile边缘时也能正确获取对应Tile的索引。
  4. 对齐Tile中心与生成坐标:添加+0.5让敌人直接生成在Tile中心,解决偏移到Tile之间的问题;若你的Tile本身以索引为中心,可去掉该偏移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 23:02:41