Comments 10
Следующий класс PoolManager управляет пулами различных объектов. Класс статический для упрощения доступа к объектам, т.е. не нужно создавать синглтоны, инстансы и прочее.
Как решается то, что статик класс содержит линки на мертвые GameObject-ы при смене сцены? Нужно или чистить или просто применять локальный для сцены пул (который может быть как синглтоном, так и просто отдельным компонентом со ссылкой на него), который будет умирать самостоятельно.
0
Да, резонное замечание, надо дописать. Просто в моем проекте сцена, где нужен пул, всего одна и очистка не требуется. Вообще при смене сцены и переинициализации от PoolSetup в objects запишется новое значение. Но необходимости очистки при смене сцен это не отменяет, согласен.
0
Ну и если хочется универсальности, то можно прикрутить загрузку префабов из ресурсов:
Вот и весь пулинг. В сцене делается ГО с пул-контейнером + настройкой, а в компоненте, где требуется инстанцировать объекты, делается паблик свойство с типом PoolContainer, в которое потом перетаскивается созданный ГО в инспекторе визуально (дизайнер оценит).
Можно делать всякие защитные меры или специальное поведение:
public sealed class PoolObject : MonoBehaviour {
public PoolContainer Pool { get; private set; }
public Transform CachedTransform { get; private set; }
void Awake () {
CachedTransform = transform;
}
public void SetPool (PoolContainer pool) {
Pool = pool;
}
public void Recycle () {
if (Pool != null) {
Pool.Recycle (this);
}
}
public void SetActive (bool state) {
gameObject.SetActive (state);
}
}
public sealed class PoolContainer : MonoBehaviour {
readonly Stack<PoolObject> _store = new Stack<PoolObject> (64);
GameObject _prefab;
public string PrefabPath = "UnknownPrefab";
bool LoadPrefab () {
_prefab = Resources.Load<GameObject> (PrefabPath);
if (_prefab == null) {
Debug.LogWarning ("Cant load asset " + PrefabPath);
return false;
}
#if UNITY_EDITOR
if (_prefab.GetComponent <PoolObject> () != null) {
Debug.LogWarning ("PoolObject cant be used on prefabs");
_prefab = null;
UnityEditor.EditorApplication.isPaused = true;
return false;
}
#endif
return true;
}
public PoolObject Get () {
if (_prefab == null) {
if (!LoadPrefab ()) {
return null;
}
}
PoolObject obj;
if (_store.Count > 0) {
obj = _store.Pop ();
} else {
var go = Instantiate<GameObject> (_prefab);
obj = go.AddComponent<PoolObject> ();
obj.SetPool (this);
}
obj.SetActive (false);
return obj;
}
public void Recycle (PoolObject obj) {
if (obj != null && obj.Pool == this) {
obj.SetActive (false);
if (!_store.Contains (obj)) {
_store.Push (obj);
}
} else {
#if UNITY_EDITOR
Debug.LogWarning ("Invalid obj to recycle", obj);
#endif
}
}
}
Вот и весь пулинг. В сцене делается ГО с пул-контейнером + настройкой, а в компоненте, где требуется инстанцировать объекты, делается паблик свойство с типом PoolContainer, в которое потом перетаскивается созданный ГО в инспекторе визуально (дизайнер оценит).
Можно делать всякие защитные меры или специальное поведение:
public sealed class RecycleAfterTime : MonoBehaviour {
public float Timeout = 1f;
float _endTime;
PoolObject _poolObject;
void OnEnable () {
_endTime = Time.time + Timeout;
}
void LateUpdate () {
if (Time.time >= _endTime) {
OnRecycle ();
}
}
void OnRecycle () {
var poolObj = GetComponent <PoolObject> ();
if (poolObj != null) {
poolObj.Recycle ();
} else {
gameObject.SetActive (false);
}
}
}
0
Вам стоит добавить кеширование получения компонентов.
0
Ну по сути тут только transform два раза подряд вызывается, потому и не заморачивался. Но да, надо исправить.
0
Я видел много вызовов getComponent
0
Скорее всего, вы про эти строки:
Тут можно закэшировать аниматор. А PoolObject кастуется лишь раз. AddObject для любого из объектов пула вызывается лишь при создании.
objects.Add(temp.GetComponent<PoolObject> ());
if (temp.GetComponent<Animator> ())
temp.GetComponent<Animator> ().StartPlayback ();
Тут можно закэшировать аниматор. А PoolObject кастуется лишь раз. AddObject для любого из объектов пула вызывается лишь при создании.
0
1. Как на счет того, чтобы сделать размер пула? В большинстве случаев объектов внутри этого размера должно хватать для сцены. Если иногда возникает ситуация, что нужно создать чуть больше объектов, то пул создает их и уничтожает при последующем освобождении, вновь оставляя в пуле только обычное количество объектов.
2. Может быть имеет смысл инициализировать все пулы с заданным количеством объектов перед загрузкой уровня, чтобы не возникало скачков FPS при создании объектов во время игрового цикла? Т.е. пул не досоздает объекты по мере необходимости, а перед стартом уровня создает их с запасом и потом выдает только готовые.
2. Может быть имеет смысл инициализировать все пулы с заданным количеством объектов перед загрузкой уровня, чтобы не возникало скачков FPS при создании объектов во время игрового цикла? Т.е. пул не досоздает объекты по мере необходимости, а перед стартом уровня создает их с запасом и потом выдает только готовые.
+1
1. Так и делается (переменная count в структуре PoolPart класса PoolManager), но я не вводил уничтожение объектов, т.к. если вам единожды понадобилось 300 пуль вместо 30, то есть вероятность, что понадобится снова, но они уже созданы.
2. Так все и происходит, досоздание объектов происходит только тогда, когда все объекты в пуле уже выданы «на руки».
2. Так все и происходит, досоздание объектов происходит только тогда, когда все объекты в пуле уже выданы «на руки».
+1
А что если это будут не пули, а тяжеловесные объекты? Предположим, у нас генерится случайный мир и вероятность такая, что обычно каждый вид объекта попадает на сцену в количестве 10 штук. Но иногда случайно все же может быть сгенерировано 20 одинаковых штук. В этом случае пул досоздаст 10 объектов. Если их не уничтожить, то так и будем их таскать всю игру, даже если больше никогда не сгенерится 20 штук. Опять же, такая ситуация может случится и с другими видами объектов. В итоге получим, что вместо 10 штук на каждый вид, будет храниться 20 — т.е. памяти потребуется вдвое больше. А еще один плохой момент, это что вначале игры памяти будет хватать, а в процессе она будет захватываться. Поэтому я бы может быть даже ввел счетчик и подстраивал размер пула под текущие нужды
0
Only those users with full accounts are able to leave comments. Log in, please.
Простой пул объектов в Unity3D