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

Unity实现随机房间生成时崩溃及房间嵌套问题咨询

Unity 简单房间放置功能异常修复方案

问题现象

  • 开发功能:Simple Room Placement(简单房间放置)
  • 初始故障:点击Play按钮运行后Unity直接崩溃,当前使用地图参数为宽172、高80
  • 初始版本GenerateRoom实现代码:
void GenerateRoom() {
    int paddingX = 14;
    int paddingY = 14;
    roomX1 = Random.Range(0, width - paddingX);
    roomY1 = Random.Range(0, height - paddingY);

    roomX2 = Random.Range(roomX1 + 6, roomX1 + paddingX);
    roomY2 = Random.Range(roomY1 + 6, roomY1 + paddingY);

    for (int x = roomX1; x < roomX2; x++) {
        for (int y = roomY1; y < roomY2; y ++) {
            if (map[x, y] == 0) {
                GenerateRoom();
            } else {
                map[x, y] = 0; 
            }
        }
    }
}
  • 初步排查调整:移除双层循环内对GenerateRoom()的递归调用,仅保留map[x,y]不为0时赋值为0的逻辑,修改后循环片段:
for (int x = roomX1; x < roomX2; x++) {
        for (int y = roomY1; y < roomY2; y ++) {
            if (map[x, y] != 0) {
                map[x,y] = 0
            }
        }
    }
  • 调整后效果:Unity崩溃问题消失,确认崩溃原因为无限制递归触发栈溢出,但出现新问题:生成的房间存在重叠、嵌套情况,无法实现无重叠房间生成。

根因分析

原实现存在两个核心逻辑错误:

  1. 递归逻辑无终止条件:遍历到已标记为房间的格子(值为0)就立刻触发新的GenerateRoom调用,递归深度完全不可控,地图尺寸越大越容易触发栈溢出导致编辑器崩溃
  2. 无放置合法性校验:移除递归后直接写入地图的逻辑,完全没有检查待生成区域是否已被其他房间占用,必然出现重叠、嵌套问题

无重叠房间生成实现方案

核心思路是前置校验替代递归回溯,从根源上规避栈溢出和重叠问题,实现步骤如下:

  • 抽离可配置参数:定义单房间最小/最大尺寸、房间间距、目标房间总数、单房间最大重试次数,避免随机逻辑失控
  • 改用外层循环控制生成流程:完全移除遍历格子过程中的递归调用,通过循环逐个生成房间,单个房间多次随机坐标校验不通过时直接终止生成,避免死循环
  • 放置前做全区域校验:随机出房间边界后,先检查房间覆盖范围+预留边距内的所有格子是否存在已占用内容,校验通过才允许写入地图
  • 存储已生成房间数据:用列表记录所有已生成房间的边界坐标,方便后续生成走廊、设置玩家出生点等逻辑调用

参考实现代码:

public int width = 172;
public int height = 80;
public int roomMinSize = 6;
public int roomMaxSize = 14;
public int roomGap = 1; // 房间之间的预留间距,设为0则房间可贴边生成
public int targetRoomCount = 20;
public int maxRetryPerRoom = 50; // 单个房间最多重试随机坐标次数
private int[,] map;
private List<(int x1, int y1, int x2, int y2)> placedRooms = new();

void Start()
{
    // 初始化地图:1代表未占用/墙体,0代表房间地面
    map = new int[width, height];
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            map[x, y] = 1;
        }
    }
    GenerateNonOverlapRooms();
}

void GenerateNonOverlapRooms()
{
    int generatedCount = 0;
    while (generatedCount < targetRoomCount)
    {
        bool placed = false;
        int retry = 0;
        while (retry < maxRetryPerRoom && !placed)
        {
            // 随机当前房间的尺寸和坐标
            int roomW = Random.Range(roomMinSize, roomMaxSize + 1);
            int roomH = Random.Range(roomMinSize, roomMaxSize + 1);
            int x1 = Random.Range(0, width - roomW - roomGap);
            int y1 = Random.Range(0, height - roomH - roomGap);
            int x2 = x1 + roomW;
            int y2 = y1 + roomH;

            // 校验待放置区域是否合法
            bool canPlace = true;
            for (int x = x1 - roomGap; x < x2 + roomGap; x++)
            {
                for (int y = y1 - roomGap; y < y2 + roomGap; y++)
                {
                    // 超出地图边界直接判定不可放置
                    if (x < 0 || x >= width || y < 0 || y >= height)
                    {
                        canPlace = false;
                        break;
                    }
                    // 区域内已有已占用格子则不可放置
                    if (map[x, y] == 0)
                    {
                        canPlace = false;
                        break;
                    }
                }
                if (!canPlace) break;
            }

            // 校验通过则写入地图
            if (canPlace)
            {
                for (int x = x1; x < x2; x++)
                {
                    for (int y = y1; y < y2; y++)
                    {
                        map[x, y] = 0;
                    }
                }
                placedRooms.Add((x1, y1, x2, y2));
                placed = true;
                generatedCount++;
            }
            retry++;
        }
        // 剩余空间不足以放置新房间时直接终止生成
        if (!placed) break;
    }
}
  • 上述实现完全规避递归带来的栈溢出风险,前置校验逻辑可以100%避免房间重叠、嵌套问题
  • 可根据实际需求调整参数:比如增大roomGap留出走廊空间,调整roomMinSize/roomMaxSize控制房间大小区间
  • 后续需要生成房间连通路径时,直接遍历placedRooms列表取房间中心点连接即可,不需要额外遍历全地图找房间位置

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:30:45