pass
Класс Pool для игровых объектов
Пул нужен для оптимизации создания и удаления игровых объектов (существа, снаряды, предметы и т.д.)
using System;
using System.Collections.Generic;
using Godot;
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
public class Pool<T> where T : class, new()
{
public Pool(Func<T> factory = null, int size = 0)
{
// если передали метод то выполняем его для создания экземпляра, иначе создаем с помощью new()
_factory = factory ?? (() => new T()); _maxSize = size;
// если есть ограничение на размер пула, то подключаемся к глобальному сигналу таймера чтобы удалять лишние экземляры
// Global должен быть инициализирован до создания Pool, чтобы работала подписка
if (_maxSize > 0 && Global.Instance != null) Global.Instance.TimerSec1 += TrimExcess;
}
// берем экземпляр из пула, если пул пуст, то создаем экземпляр
// если объект подкласс ноды, то включаем его процесс и если передали ноду родителя, то добавляем его в дерево сцены
public T Get(Node parent = null)
{
T obj = _pool.Count > 0 ? _pool.Dequeue() : _factory();
if (obj is Node node)
{
if (node.ProcessMode != Node.ProcessModeEnum.Inherit) node.ProcessMode = Node.ProcessModeEnum.Inherit;
parent?.AddChild(node);
}
return obj;
}
// возвращаем объект в пул, если подкласс ноды, то выключаем процесс и удаляем из дерева
// перед удалением желательно вызвать метод сброса/очистки объекта, чтобы избежать утечки
public void Return(T obj)
{
if (obj is Node node)
{
node.GetParent()?.RemoveChild(node);
node.ProcessMode = Node.ProcessModeEnum.Disabled;
}
_pool.Enqueue(obj);
}
// метод удаление лишнего, подключаем к какому нибудь сигналу, например сигналу таймера
public void TrimExcess()
{
int excess = _pool.Count - _maxSize;
if (excess <= 0) return;
for (int i = 0; i < excess; i++)
{
T obj = _pool.Dequeue();
if (obj is Node node) node.QueueFree();
}
}
// отписка от сигнала, если нужно удалить пул
public void Unsubscribe()
{
if (Global.Instance != null) Global.Instance.TimerSec1 -= TrimExcess;
}
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
private Queue<T> _pool = new();
private Func<T> _factory = null;
private int _maxSize = 0;
}Пример использования
Статический класс, который хранит все пулы.
Первый блок пример создания экземпляра из сцены, второй создание через new().
Для классов, которые могут хранить ссылки на другие объекты, обязательно очищать ссылки перед возвратом в пул.
using System;
using Godot;
using static Constants;
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
public static partial class Pools
{
public static Creature NewCreature(String name, Node parent)
{
Creature creature = _creaturePool.Get(parent);
creature.Init(name);
return creature;
}
public static void RemoveCreature(Creature creature)
{
creature.Clear();
_creaturePool.Return(creature);
}
private static readonly PackedScene _creatureScene = GD.Load<PackedScene>(CREATURE_PATH);
private static Pool<Creature> _creaturePool = new(() => _creatureScene.Instantiate<Creature>());
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
public static Effect NewEffect(String keyName, Creature owner)
{
Effect effect = _effectPool.Get();
effect.Init(keyName, owner);
return effect;
}
public static void RemoveEffect(Effect effect)
{
effect.Clear();
_effectPool.Return(effect);
}
private static Pool<Effect> _effectPool = new();Тема закрыта.