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

Unity程序化地牢生成异常:重复调用CreateRoom无法生成多房间

程序化地牢多房间生成问题修复

我已经成功实现程序化地牢的单个房间生成,但重复调用CreateRoom函数生成多个房间时遇到问题:更换起始位置再次调用函数,新房间会和初始房间重叠,且墙壁始终出现在初始Spawn点,完全不符合预期。我是编程新手,搞不懂问题出在哪,求帮忙。

原代码

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

public class ProcGen : MonoBehaviour
{
    public GameObject[] floorTiles;
    public GameObject[] wallTiles;
    public float ceilingHeight;
    public Vector3 roomSpawn = new Vector2(0, 0);

    // Start is called before the first frame update
    void Start()
    {
        //Instantiate(floorTiles[0]);
        CreateRoom(Random.Range(2,7), Random.Range(2,9), roomSpawn);
        //CreateRoom(2,2, new Vector2(50, 50));
    }

    // Update is called once per frame
    void Update()
    {
    
    }

    void CreateRoom(int width, int length, Vector2 position)
    {
        // FLOOR and Roof GENERATION
        int tileWidth = (int)floorTiles[0].GetComponent<MeshRenderer>().bounds.size.x;
        // truncate the position that was passed in
        Vector2 firstPos = new Vector2(Mathf.Floor(position.x), Mathf.Floor(position.y));
        Vector2 tilePos = firstPos;
        
        for(int i = 0; i < width; i++)
        {
            for(int j = 0; j < length; j++)
            {
                Instantiate(floorTiles[Random.Range(0, floorTiles.Length)], new Vector3(tilePos.x, 0, tilePos.y), Quaternion.identity);
                Instantiate(floorTiles[0], new Vector3(tilePos.x, ceilingHeight, tilePos.y), Quaternion.Euler (0f, 0f, 180f));
                tilePos += new Vector2(tileWidth, 0);
            }
            tilePos = new Vector2(firstPos.x, tilePos.y);
            tilePos += new Vector2(0, tileWidth);
        }


        // WALL GENERATION
        float rotation = 90;
        
        Vector2 wallPos = firstPos;
        for(int i = 0; i < length; i++)
        {
            Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(wallPos.x, 0, 0), Quaternion.Euler(new Vector3(0, rotation, 0)));
            wallPos += new Vector2(tileWidth, 0);
        }

        rotation += 90;
        for(int i = 0; i < width; i++)
        {
            Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(0, 0, wallPos.y), Quaternion.Euler(new Vector3(0, rotation, 0)));
            wallPos += new Vector2(0, tileWidth);
        }

        rotation += 90;
        for(int i = 0; i < length; i++)
        {
            Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(i * tileWidth, 0, firstPos.y + ((width - 1) * tileWidth)), Quaternion.Euler(new Vector3(0, rotation, 0)));
            wallPos += new Vector2(tileWidth, 0);
        }

        rotation += 90;
        for(int i = 0; i < width; i++)
        {
            Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3((length - 1) * tileWidth, 0, i * tileWidth), Quaternion.Euler(new Vector3(0, rotation, 0)));
            wallPos += new Vector2(0, tileWidth);
        }
    }

    int CalculateAddition(int left, int right)
    {
        return left + right;
    }
}

问题根源

地板/屋顶生成逻辑是对的,但墙壁生成时完全忽略了传入的position起始坐标,硬编码了部分轴为0,或者没有加上起始位置的偏移,导致所有房间的墙壁都生成在初始Spawn点附近,自然会重叠。

修复后的CreateRoom函数(仅修改墙壁部分)

void CreateRoom(int width, int length, Vector2 position)
{
    // FLOOR and Roof GENERATION —— 这部分逻辑没问题,保留
    int tileWidth = (int)floorTiles[0].GetComponent<MeshRenderer>().bounds.size.x;
    Vector2 firstPos = new Vector2(Mathf.Floor(position.x), Mathf.Floor(position.y));
    Vector2 tilePos = firstPos;
    
    for(int i = 0; i < width; i++)
    {
        for(int j = 0; j < length; j++)
        {
            Instantiate(floorTiles[Random.Range(0, floorTiles.Length)], new Vector3(tilePos.x, 0, tilePos.y), Quaternion.identity);
            Instantiate(floorTiles[0], new Vector3(tilePos.x, ceilingHeight, tilePos.y), Quaternion.Euler (0f, 0f, 180f));
            tilePos += new Vector2(tileWidth, 0);
        }
        tilePos = new Vector2(firstPos.x, tilePos.y);
        tilePos += new Vector2(0, tileWidth);
    }


    // WALL GENERATION —— 修复后的墙壁逻辑
    float rotation = 90;
    
    Vector2 wallPos = firstPos;
    // 生成房间的"前边"(z=firstPos.y,x从firstPos.x到firstPos.x + (length-1)*tileWidth)
    for(int i = 0; i < length; i++)
    {
        // 修正:z轴用firstPos.y,而不是0
        Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(wallPos.x, 0, firstPos.y), Quaternion.Euler(new Vector3(0, rotation, 0)));
        wallPos += new Vector2(tileWidth, 0);
    }

    rotation += 90;
    // 生成房间的"右边"(x=firstPos.x + (length-1)*tileWidth,z从firstPos.y到firstPos.y + (width-1)*tileWidth)
    wallPos = new Vector2(firstPos.x + (length-1)*tileWidth, firstPos.y);
    for(int i = 0; i < width; i++)
    {
        // 修正:x轴用wallPos.x,而不是0
        Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(wallPos.x, 0, wallPos.y), Quaternion.Euler(new Vector3(0, rotation, 0)));
        wallPos += new Vector2(0, tileWidth);
    }

    rotation += 90;
    // 生成房间的"后边"(z=firstPos.y + (width-1)*tileWidth,x从firstPos.x到firstPos.x + (length-1)*tileWidth)
    wallPos = firstPos;
    for(int i = 0; i < length; i++)
    {
        // 修正:x轴加上firstPos.x的偏移
        Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(firstPos.x + i * tileWidth, 0, firstPos.y + ((width - 1) * tileWidth)), Quaternion.Euler(new Vector3(0, rotation, 0)));
        wallPos += new Vector2(tileWidth, 0);
    }

    rotation += 90;
    // 生成房间的"左边"(x=firstPos.x,z从firstPos.y到firstPos.y + (width-1)*tileWidth)
    wallPos = firstPos;
    for(int i = 0; i < width; i++)
    {
        // 修正:x轴用firstPos.x,z轴加上firstPos.y的偏移
        Instantiate(wallTiles[Random.Range(0, wallTiles.Length)], new Vector3(firstPos.x, 0, firstPos.y + i * tileWidth), Quaternion.Euler(new Vector3(0, rotation, 0)));
        wallPos += new Vector2(0, tileWidth);
    }
}

关键修改点说明

  • 第一个墙壁循环:把z轴的0改成firstPos.y,确保墙壁生成在房间的起始z位置,而不是世界原点。
  • 第二个墙壁循环:重置wallPos到房间的右上角起点(x=起始x+长度* tile宽度),同时把x轴的0改成wallPos.x,让墙壁沿房间右侧生成。
  • 第三个墙壁循环:x轴坐标加上firstPos.x的偏移,确保墙壁从房间的起始x位置开始,而不是世界原点的x=0。
  • 第四个墙壁循环:x轴用firstPos.x(房间左侧),z轴坐标加上firstPos.y,让墙壁沿房间左侧生成。

现在你可以取消Start函数里第二个CreateRoom的注释,比如调用CreateRoom(2,2, new Vector2(50, 50)),就能看到两个不重叠的房间了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 15:51:07