如何解决 Unity3d 编辑器因视差脚本池大小增加而滞后的问题?

How to resolve Unity3d Editor lags with increased pool size for parallaxer script?

我正在制作一款 2d 平台游戏。

当附加到我的预制件的视差脚本的池大小增加时,Unity3D 应用程序滞后并冻结在更大的池大小。此事件以前没有出现在其他池大小大得多的项目中。无论游戏方面如何,该事件似乎都会持续存在。

附带预制件的视差脚本
池大小:10(开始滞后)
换挡速度:-1
产卵率:1

Y 生成范围:
最小 Y:0
最大 Y:2.72
默认重生位置
X: 12.81 Y:-0.03Z:0
立即生成:未选中
立即重生位置
X: 0 Y: 0 Z: 0
目标纵横比:
X: 10 Y: 16

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Parallaxer : MonoBehaviour {

    class PoolObject {
        public Transform transform;
        public bool inUse;
        public PoolObject(Transform t) { transform = t; }
        public void Use() { inUse = true; }
        public void Dispose() { inUse = false; }
    }

    [System.Serializable]
    public struct YSpawnRange {
        public float minY;
        public float maxY;
    }

    public GameObject Prefab;
    public int poolSize;
    public float shiftSpeed;
    public float spawnRate;

    public YSpawnRange ySpawnRange;
    public Vector3 defaultSpawnPos;
    public bool spawnImmediate;
    public Vector3 immediateSpawnPos;
    public Vector2 targetAspectRatio;

    float spawnTimer;
    PoolObject[] poolObjects;
    float targetAspect;
    GameManager game;

    void Awake() {
        Configure();
    }

    void Start() {
        game = GameManager.Instance;
    }

    void OnEnable() {
        GameManager.OnGameOverConfirmed += OnGameOverConfirmed;
    }

    void OnDisable() {
        GameManager.OnGameOverConfirmed -= OnGameOverConfirmed;
    }

    void OnGameOverConfirmed() {
        for (int i = 0; i < poolObjects.Length; i++) {
            poolObjects[i].Dispose();
            poolObjects[i].transform.position = Vector3.one * 1000;
        }
        Configure();
    }

    void Update() {
        if (game.GameOver) return;

        Shift();
        spawnTimer += Time.deltaTime;
        if (spawnTimer > spawnRate) {
            Spawn();
            spawnTimer = 0;
        }
    }

    void Configure() {
        //spawning pool objects
        targetAspect = targetAspectRatio.x / targetAspectRatio.y;
        poolObjects = new PoolObject[poolSize];
        for (int i = 0; i < poolObjects.Length; i++) {
            GameObject go = Instantiate(Prefab) as GameObject;
            Transform t = go.transform;
            t.SetParent(transform);
            t.position = Vector3.one * 1000;
            poolObjects[i] = new PoolObject(t);
        }

        if (spawnImmediate) {
            SpawnImmediate();
        }
    }

    void Spawn() {
        //moving pool objects into place
        Transform t = GetPoolObject();
        if (t == null) return;
        Vector3 pos = Vector3.zero;
        pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
        pos.x = (defaultSpawnPos.x * Camera.main.aspect) / targetAspect;
        t.position = pos;
    }

    void SpawnImmediate() {
        Transform t = GetPoolObject();
        if (t==null) return;
        Vector3 pos = Vector3.zero;
        pos.y = Random.Range(ySpawnRange.minY, ySpawnRange.maxY);
        pos.x = (immediateSpawnPos.x * Camera.main.aspect) / targetAspect;
        t.position = pos; 
        Spawn();
    }

    void Shift() {
        //loop through pool objects 
        //moving them
        //discarding them as they go off screen
        for (int i = 0; i < poolObjects.Length; i++) {
            poolObjects[i].transform.position += Vector3.right * shiftSpeed * Time.deltaTime;
            CheckDisposeObject(poolObjects[i]);
        }
    }

    void CheckDisposeObject(PoolObject poolObject) {
        //place objects off screen
        if (poolObject.transform.position.x < (-defaultSpawnPos.x * Camera.main.aspect) / targetAspect) {
            poolObject.Dispose();
            poolObject.transform.position = Vector3.one * 1000;
        }
    }

    Transform GetPoolObject() {
        //retrieving first available pool object
        for (int i = 0; i < poolObjects.Length; i++) {
            if (!poolObjects[i].inUse) {
                poolObjects[i].Use();
                return poolObjects[i].transform;
            }
        }
        return null;
    }

}

当您更改对象的 transform.position 时,如果该对象嵌套在游戏层次结构中的其他对象中,这可能是一个昂贵的过程。与其更改对象的变换,不如考虑在不使用时将 GameObject 设置为非活动状态。此外,与其每次需要 GetPoolObject() 时都遍历 PoolObjects 列表,不如考虑创建一个未使用对象的队列。这有两个目的:

  1. 您不再需要通过 属性
  2. 跟踪对象是否正在使用
  3. 您无需遍历所有对象即可找到可用对象。

队列示例:

Queue<PoolObject> availableObjects = new Queue<PoolObject>();

class PoolObject 
{
    public Transform transform;
    public bool inUse;
    public PoolObject(Transform t) { transform = t; }
    public void Use() { inUse = true; }
    public void Dispose() { inUse = false; }
}

void CheckDisposeObject(PoolObject poolObject) 
{
    //place objects off screen
    if (poolObject.transform.position.x < (-defaultSpawnPos.x * Camera.main.aspect) / targetAspect) 
    {
        availableObjects.Enqueue(poolObject);
        poolObject.transform.gameObject.SetActive(false);
    }
}

Transform GetPooledObject()
{
    if(availableObjects.Count > 0)
        Transform poolObj = availableObjects.Dequeue();
        poolObj.gameObject.SetActive(true);
        return poolObj;
    else
        return null;
}