Unity中多线程优化大网格瓦片生成卡顿问题求助
Unity瓦片网格生成卡顿优化方案
原脚本核心问题
- 循环内重复调用
Resources.Load,无缓存机制,每次加载都产生IO耗时 - 嵌套循环一次性实例化所有瓦片,单帧执行大量Unity API操作(
Instantiate、Transform.position赋值),直接阻塞主线程 - 协程未实现真正的分批处理,构造函数同步执行所有生成逻辑
优化步骤
1. 预加载资源并缓存
提前在主线程加载所有需要的瓦片预制体,彻底避免循环内重复加载:
using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class GridGenerationSprite : MonoBehaviour { private Sprite mySprite; private SpriteRenderer sr; [SerializeField] SettingGeneration settingGeneration; [SerializeField] float tileSize; [SerializeField] int size; private float xDir; private float yDir; private byte[,] cells; // 新增资源缓存字典 private Dictionary<byte, GameObject> tilePrefabCache = new Dictionary<byte, GameObject>(); private void Awake() { // 预加载所有可能用到的瓦片资源 PreloadTilePrefabs(); } private void PreloadTilePrefabs() { // 这里根据你的SettingGeneration逻辑,获取所有可能的瓦片类型标识 // 示例:假设瓦片类型是0-9的byte值,可根据实际情况调整 for (byte i = 0; i < 10; i++) { if (!tilePrefabCache.ContainsKey(i)) { var prefab = Resources.Load<GameObject>(i.ToString()); if (prefab != null) { tilePrefabCache.Add(i, prefab); } } } }
2. 协程分批实例化
将大循环拆分为小批次,每帧处理部分瓦片,避免单帧耗时过载:
private void Start() { StartCoroutine(GenerateGridInBatches()); } IEnumerator GenerateGridInBatches() { cells = settingGeneration.startSetting(size); int totalTiles = size * size; int batchSize = 50; // 每帧处理50个瓦片,可根据设备性能调整 int processed = 0; while (processed < totalTiles) { int endIndex = Mathf.Min(processed + batchSize, totalTiles); for (; processed < endIndex; processed++) { int x = processed / size; int y = processed % size; byte tileType = cells[x, y]; if (tilePrefabCache.TryGetValue(tileType, out var prefab)) { GameObject tile = Instantiate(prefab, transform); tile.name = $"X: {x} Y: {y}"; float posX = y * tileSize; float posY = -x * tileSize; tile.transform.position = new Vector2(posX, posY); } } yield return null; // 让出主线程,等待下一帧渲染 } } }
3. 多线程辅助数据预处理(可选)
如果瓦片的类型计算、位置逻辑复杂,可使用Task在子线程预处理数据,再回到主线程实例化:
private void Start() { StartCoroutine(GenerateGridWithMultithreading()); } IEnumerator GenerateGridWithMultithreading() { List<TileData> tileDatas = new List<TileData>(); // 子线程处理纯数据计算,不调用任何Unity API yield return Task.Run(() => { var cells = settingGeneration.startSetting(size); for (int x = 0; x < size; x++) { for (int y = 0; y < size; y++) { byte type = cells[x, y]; float posX = y * tileSize; float posY = -x * tileSize; tileDatas.Add(new TileData(x, y, type, posX, posY)); } } }).AsCoroutine(); // 主线程分批实例化 int batchSize = 50; int processed = 0; int total = tileDatas.Count; while (processed < total) { int endIndex = Mathf.Min(processed + batchSize, total); for (; processed < endIndex; processed++) { var data = tileDatas[processed]; if (tilePrefabCache.TryGetValue(data.Type, out var prefab)) { GameObject tile = Instantiate(prefab, transform); tile.name = $"X: {data.X} Y: {data.Y}"; tile.transform.position = new Vector2(data.PosX, data.PosY); } } yield return null; } } // 存储瓦片数据的结构体,子线程可安全处理 private struct TileData { public int X; public int Y; public byte Type; public float PosX; public float PosY; public TileData(int x, int y, byte type, float posX, float posY) { X = x; Y = y; Type = type; PosX = posX; PosY = posY; } } }
关键注意事项
- Unity多线程限制:子线程绝对不能调用任何Unity引擎API(如
Instantiate、Transform操作、Resources.Load),仅能处理纯数据计算 - 资源缓存优先级:预加载缓存是提升性能最直接的手段,避免重复IO操作
- 分批处理必要性:即使不用多线程,分批实例化也能大幅降低单帧耗时,解决卡顿问题
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

