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
相关产品推荐
相关产品推荐

