Unity 2D草预制体空白区域实例化性能优化问题咨询
Unity草预制体网格生成卡顿优化方案
我有一个草预制体,生长一段时间后会在自身周围8个位置中随机选一个实例化自身,最终形成预制体格网。最初我为每个预制体配置了8个触发碰撞体来检测对应位置是否存在其他草预制体,配置截图如下:
该方案运行后仅实例化少量预制体,Unity就会出现明显卡顿。
原有实现代码
using UnityEngine; public class GrassController : MonoBehaviour { [SerializeField] private float growthRate = 1.1f; [SerializeField] private float maxSize = 1f; [SerializeField] private float reproduceEffort = 0.1f; [SerializeField] private GameObject prefab; [SerializeField] private GameObject sprite; [SerializeField] private ReproduceHitBoxController[] reproduceHitBoxes; [SerializeField] private float size = 0f; private float initialSize = 0.1f; private void Awake() { size = initialSize; ApplyGrowth(); } private void FixedUpdate() { if (size < maxSize) Grow(); else Reproduce(); } private void Grow() { size *= growthRate; if (size >= maxSize) size = maxSize; ApplyGrowth(); } private void ApplyGrowth() { sprite.transform.localScale = new Vector3(size, size, sprite.transform.position.z); } private void Reproduce() { var reproduceHitBox = reproduceHitBoxes[Random.Range(0, reproduceHitBoxes.Length)]; if (reproduceHitBox.tagInCollider == true) return; Instantiate(prefab, reproduceHitBox.transform.position, Quaternion.identity); size -= reproduceEffort; } }
问题排查
经性能分析,卡顿主要来自大量物理碰撞检测带来的开销,需要找到性能更优的方案来检测指定区域内是否存在其他草对象,性能分析截图如下:
优化方案
最终采用Dictionary<Vector3,GrassController>按位置存储所有已生成的草对象,每次繁殖时仅需检测相邻位置是否存在于字典中即可,完全规避了物理检测开销。
注意:有开发者指出该方案存在潜在的浮点数精度问题,实际使用时建议将坐标转换为整数对作为字典键,避免因精度误差导致位置匹配错误。
优化后代码
using UnityEngine; public class GrassController : MonoBehaviour { [SerializeField] private float growthRate = 1.1f; [SerializeField] private float maxSize = 1f; [SerializeField] private float reproduceEffort = 0.1f; [SerializeField] private GameObject prefab; [SerializeField] private GameObject sprite; [SerializeField] private GameController gameController; [SerializeField] private float size = 0f; private Vector3[] growPoints; private float initialSize = 0.1f; private void Awake() { growPoints = new Vector3[] { new Vector3(transform.position.x + 1, transform.position.y + 1, transform.position.z), new Vector3(transform.position.x + 1, transform.position.y, transform.position.z), new Vector3(transform.position.x + 1, transform.position.y - 1, transform.position.z), new Vector3(transform.position.x, transform.position.y - 1, transform.position.z), new Vector3(transform.position.x - 1, transform.position.y - 1, transform.position.z), new Vector3(transform.position.x - 1, transform.position.y, transform.position.z), new Vector3(transform.position.x - 1, transform.position.y + 1, transform.position.z), new Vector3(transform.position.x, transform.position.y + 1, transform.position.z), }; size = initialSize; gameController.grassControllers.Add(transform.position, this); ApplyGrowth(); } private void FixedUpdate() { if (size < maxSize) Grow(); else Reproduce(); } private void Grow() { size *= growthRate; if (size >= maxSize) size = maxSize; ApplyGrowth(); } private void ApplyGrowth() { sprite.transform.localScale = new Vector3(size, size, sprite.transform.position.z); } private void Reproduce() { var growPoint = growPoints[Random.Range(0, growPoints.Length)]; if (gameController.grassControllers.ContainsKey(growPoint) == true) return; Instantiate(prefab, growPoint, Quaternion.identity); size -= reproduceEffort; } }
最终效果
优化后运行流畅,符合预期效果,截图如下:
内容的提问来源于stack exchange,提问作者Lucas Venturini
相关产品推荐
相关产品推荐

