Как устранить лаги Unity3d Editor с увеличенным размером пула для скрипта параллакса? - PullRequest
0 голосов
/ 27 сентября 2019

Я создаю 2d Platformer игру.

Когда размер пула для скрипта параллакса, прикрепленного к моему префабу, увеличивается, приложение Unity3D отстает и зависает в пулах большего размера.Это событие ранее не присутствовало в других проектах с существенно большими размерами пула.Событие, похоже, продолжается независимо от игрового аспекта.

Скрипт параллакса с прикрепленным префабом
Размер пула: 10 (там, где начинается отставание)
Скорость смены: -1
Скорость появления: 1

Y Диапазон появления:
Мин. Y: 0
Макс. Y: 2,72
Поз. Spawn Поз.
X: 12,81 Y: -0,03 Z: 0
Spawn Immediate: Не проверено
ImmediateПоз. Spawn
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;
    }

}

1 Ответ

0 голосов
/ 27 сентября 2019

Когда вы изменяете transform.position объекта, это может быть дорогостоящим процессом, если объект вложен в другие объекты в вашей игровой иерархии.Вместо того, чтобы изменять трансформацию объекта, рассмотрите возможность установки GameObject в неактивное состояние, когда он не используется.Кроме того, вместо того, чтобы перебирать свой список PoolObjects каждый раз, когда вам нужно GetPoolObject (), рассмотрите возможность создания очереди неиспользуемых объектов.Это служит двум целям:

  1. Вам больше не нужно отслеживать, если объект используется через свойство
  2. Вам не нужно перебирать все ваши объекты, чтобы найти доступный.

Пример очереди:

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;
}
...