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

Unity(C#)中如何从中心原点瓦片实现单瓦片转多瓦片房间

Unity Tilemap 从中心原点瓦片生成指定规格房间实现方案

核心逻辑:全程以初始状态的中心单瓦片作为坐标原点做对齐,不需要额外做坐标偏移,先计算目标规格房间的格子覆盖范围,清空范围内拆分残留的零散瓦片后统一填充房间瓦片即可,支持任意宽高的矩形(含正方形)房间生成,比如提到的5x7规格可以直接适配。

实现步骤

  • 记录原点坐标
    初始场景仅存在1个中心瓦片时,直接遍历Tilemap的已占用格子,拿到这个瓦片的格子坐标存为全局原点_originCellPos,后续所有房间生成操作都以这个坐标为中心基准。
  • 计算目标房间的格子覆盖范围
    传入目标房间的列数(X方向长度)、行数(Y方向长度)后,先计算半幅尺寸:
    int halfW = Mathf.FloorToInt(roomWidth / 2f);
    int halfH = Mathf.FloorToInt(roomHeight / 2f);
    再算出区域四个边界的格子坐标:
    • X轴左边界:原点x坐标 - halfW
    • X轴右边界:原点x坐标 + (roomWidth - halfW - 1)
    • Y轴下边界:原点y坐标 - halfH
    • Y轴上边界:原点y坐标 + (roomHeight - halfH - 1)
      这套计算逻辑兼容奇偶尺寸:比如5x7规格,halfW=2、halfH=3,X方向覆盖从原点x-2到x+2共5格,Y方向覆盖从原点y-3到y+3共7格,中心刚好落在初始原点瓦片上,不会出现偏移。
  • 清理旧瓦片并填充房间
    双重遍历覆盖范围内的所有格子坐标,先清空格子上原有的拆分后零散瓦片,再根据需求放置对应类型的瓦片:如果需要做带墙的房间,判断当前格子是否在区域边缘,边缘放墙体瓦片、内部放地面瓦片即可;如果是纯实心区域直接全放同一种瓦片就行。
  • 绑定房间数据
    填充完瓦片后,把房间的中心坐标、尺寸、边界范围存到自定义的Room数据结构里,方便后续做碰撞生成、房间交互、怪物刷出之类的逻辑。

核心实现代码

using UnityEngine;
using UnityEngine.Tilemaps;

public class RoomGenerator : MonoBehaviour
{
    [Header("目标瓦片地图引用")]
    [SerializeField] private Tilemap targetTilemap;
    [Header("房间地面瓦片")]
    [SerializeField] private TileBase floorTile;
    [Header("房间墙体瓦片")]
    [SerializeField] private TileBase wallTile;
    
    // 初始中心原点的格子坐标
    private Vector3Int _originCellPos;

    private void Awake()
    {
        // 初始状态仅存在中心瓦片,遍历拿到原点坐标
        foreach (Vector3Int cellPos in targetTilemap.cellBounds.allPositionsWithin)
        {
            if (targetTilemap.HasTile(cellPos))
            {
                _originCellPos = cellPos;
                break;
            }
        }
    }

    /// <summary>
    /// 以中心初始瓦片为原点生成指定尺寸的房间
    /// </summary>
    /// <param name="roomWidth">X方向格子数(列数)</param>
    /// <param name="roomHeight">Y方向格子数(行数)</param>
    public void GenerateRoom(int roomWidth, int roomHeight)
    {
        // 计算边界范围
        int halfW = Mathf.FloorToInt(roomWidth / 2f);
        int halfH = Mathf.FloorToInt(roomHeight / 2f);
        int minX = _originCellPos.x - halfW;
        int maxX = _originCellPos.x + (roomWidth - halfW - 1);
        int minY = _originCellPos.y - halfH;
        int maxY = _originCellPos.y + (roomHeight - halfH - 1);

        // 遍历范围填充瓦片
        for (int x = minX; x <= maxX; x++)
        {
            for (int y = minY; y <= maxY; y++)
            {
                Vector3Int currentCell = new Vector3Int(x, y, _originCellPos.z);
                // 先清空原有瓦片(拆分后的残留瓦片会被直接覆盖)
                targetTilemap.SetTile(currentCell, null);
                
                // 边缘格放墙体,内部放地面,不需要墙体直接全放floorTile即可
                bool isEdgeCell = x == minX || x == maxX || y == minY || y == maxY;
                targetTilemap.SetTile(currentCell, isEdgeCell ? wallTile : floorTile);
            }
        }

        // 生成房间数据实例,后续可根据需求扩展属性
        Room newRoom = new Room
        {
            centerCellPos = _originCellPos,
            width = roomWidth,
            height = roomHeight,
            xMin = minX,
            xMax = maxX,
            yMin = minY,
            yMax = maxY
        };
        // 这里可以把newRoom加入全局房间管理列表,供其他逻辑调用
    }
}

/// <summary>
/// 房间数据结构
/// </summary>
public class Room
{
    public Vector3Int centerCellPos;
    public int width;
    public int height;
    public int xMin, xMax, yMin, yMax;
}

适配说明

  • 这套逻辑支持任意正整数尺寸的房间生成,1x1就是初始单瓦片状态,5x7、4*6这类奇偶组合的尺寸都能自动对齐中心,不需要手动调整偏移参数。
  • 如果拆分逻辑给瓦片挂了自定义组件或者数据,在清空瓦片的时候记得同步销毁对应关联数据,避免残留引用导致空报错。
  • 如果需要生成非矩形的特殊形状房间,只要修改遍历时候的瓦片放置规则即可,中心对齐的基准逻辑不需要改动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:30:45