Unity使用SetTile方法随机填充Tilemap无报错不生效问题求解
问题原因与修复方案
核心错误点
- 坐标转换逻辑错误:
Tilemap.SetTile()要求传入的是瓦片网格的本地单元格坐标(Vector3Int),你当前的代码存储的是CellToWorld转换后的世界坐标,再用Vector3Int.FloorToInt转世界坐标得到的结果和原始单元格坐标完全不匹配,尤其是当Tilemap存在缩放、位置偏移的时候,必然会定位到错误的单元格甚至完全定位不到。 - 随机逻辑不符合预期:你设置的随机数范围是
0.1f ~ 1.0f,天然缺失了0~0.1的区间,而且大于0.6f的区间(占总概率的40%)会直接把瓦片设为null,会导致你预先绘制的tileNull区域有近一半被清空,看起来就像没生效一样。 - 冗余的坐标转换开销:不需要额外把单元格坐标转成世界坐标存储,直接存原始的
Vector3Int单元格坐标即可,避免后续转换误差。
修复后代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Tilemaps; public class PopulateMap : MonoBehaviour { public Tilemap map; //需要填充的Tilemap public Tile tile1; //用于填充的瓦片 public Tile tile2; public Tile tile3; public Tile tile4; public Tile tile5; public Tile tileNull; //预先绘制的空白瓦片,标记需要生效的区域 List<Vector3Int> tileLocations; //直接存储单元格坐标,避免转换误差 // Start is called before the first frame update void Start() { tileLocations = new List<Vector3Int>(); //遍历所有单元格,记录有瓦片的位置(也就是你预先绘制tileNull的区域) foreach (var pos in map.cellBounds.allPositionsWithin) { Vector3Int localPlace = new Vector3Int(pos.x, pos.y, pos.z); if (map.HasTile(localPlace)) { tileLocations.Add(localPlace); //直接存单元格坐标 } } FillMap(); } void FillMap() { foreach (Vector3Int cellPos in tileLocations) { //随机范围改为0~1,覆盖全部概率区间 float f = Random.Range(0f, 1.0f); if (f < 0.2f) { map.SetTile(cellPos, tile1); } else if (f < 0.3f) { map.SetTile(cellPos, tile2); } else if (f < 0.4f) { map.SetTile(cellPos, tile3); } else if (f < 0.5f) { map.SetTile(cellPos, tile4); } else if (f < 0.6f) { map.SetTile(cellPos, tile5); } else { //如果不需要清空区域,这里保留tileNull即可维持原始空白效果 map.SetTile(cellPos, tileNull); } } } }
额外注意点
- 检查Inspector面板中
map、tile1~tile5、tileNull的引用是否都已经正确赋值,空引用也会导致设置不生效 - 如果需要调整各瓦片的生成概率,直接修改if判断的阈值即可
内容的提问来源于stack exchange,提问作者Aironas
相关产品推荐
相关产品推荐

