O ObjectPool da Unity
Parte da seção Arquitetura de Jogos no Unity do Journey de Unity da Coddy. Lição 48 de 64.
Unity inclui um pool, ObjectPool<T> em UnityEngine.Pool. Você diz a ele o que fazer em cada etapa com quatro lambdas, e ele mantém os objetos extras e as contagens. Esta chaminé solta fumaça a cada 0.2 segundos, e cada nuvem volta após um segundo:
using UnityEngine;
using UnityEngine.Pool;
public class Chimney : MonoBehaviour
{
public Puff puffPrefab;
private ObjectPool<Puff> pool;
private float timer;
void Awake()
{
pool = new ObjectPool<Puff>(
createFunc: () => Instantiate(puffPrefab),
actionOnGet: puff => puff.gameObject.SetActive(true),
actionOnRelease: puff => puff.gameObject.SetActive(false),
actionOnDestroy: puff => Destroy(puff.gameObject),
collectionCheck: true,
defaultCapacity: 10,
maxSize: 20);
}
void Update()
{
timer += Time.deltaTime;
if (timer >= 0.2f)
{
timer = 0f;
Puff puff = pool.Get();
puff.transform.position = transform.position + Vector3.up;
puff.Launch(pool);
}
}
}// Puff.cs
private IObjectPool<Puff> pool;
private float age;
public void Launch(IObjectPool<Puff> owner)
{
pool = owner;
age = 0f;
}
void Update()
{
transform.Translate(0f, Time.deltaTime, 0f);
age += Time.deltaTime;
if (age >= 1f) pool.Release(this);
}createFunc é executada quando Get encontra o pool vazio; actionOnGet é executada a cada Get e actionOnRelease, a cada Release. Quando uma nuvem é liberada enquanto já há objetos extras aguardando, até o limite de maxSize, o pool não a mantém: actionOnDestroy a destrói. defaultCapacity é apenas o tamanho inicial da lista do pool, então nada é criado de antemão. CountAll conta as nuvens que o pool criou e ainda possui, CountActive conta as que estão no jogo e CountInactive, as que estão sobrando. Get ativou a nuvem antes de a chaminé posicioná-la, o que funciona bem aqui porque Puff não tem um OnEnable que leia sua posição. A nuvem mantém o pool como um IObjectPool<Puff>, a interface implementada por todos os pools do Unity, e Launch redefine sua idade a cada uso.
Com collectionCheck ativado, liberar uma nuvem que já está no pool gera uma InvalidOperationException: Trying to release an object that has already been released to the pool. A verificação é executada somente no Editor, porque procura entre os objetos extras a cada Release; em uma build, a nuvem ficaria duas vezes no pool, e dois Get entregariam o mesmo objeto. Uma causa comum é um objeto que continua em execução após ser liberado e se libera novamente, por isso actionOnRelease o desativa.
Desafio
MédioDispare os fogos de artifício usando o pool do Unity.
- No
AwakedeLauncher, crie umObjectPool<Spark>: crie comInstantiate(sparkPrefab), ative quando for obtido, desative quando for liberado, destrua o objeto quando for solto e definamaxSize: 5. - Em
Update, obtenha cada faísca compool.Get()em vez deInstantiate. - Em
Return, chamepool.Release(spark)em vez deDestroy.
Pressione “Jogar” e dispare algumas rajadas. Depois, clique em “Verificar”.
Experimente você mesmo
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Pool;
public class Launcher : MonoBehaviour
{
public Spark sparkPrefab;
public int sparks = 8;
void Awake()
{
// Crie o pool: crie, obtenha, libere e destrua, com no máximo 5 faíscas de reserva
}
void Update()
{
if (Keyboard.current.spaceKey.wasPressedThisFrame)
{
for (int i = 0; i < sparks; i++)
{
Spark spark = Instantiate(sparkPrefab);
spark.transform.position = transform.position + Vector3.up;
spark.Launch(Direction(i), this);
}
}
}
// Uma faísca cuja vida útil terminou
public void Return(Spark spark)
{
Destroy(spark.gameObject);
}
// Para fora e para cima, distribuídas uniformemente ao redor do lançador
Vector3 Direction(int i)
{
return Quaternion.Euler(0f, i * 360f / sparks, 0f) * new Vector3(0f, 1f, 3f);
}
}
Todas as lições de Arquitetura de Jogos no Unity
1Componentes, não hierarquias
Componentes pequenosUm script base de inimigoComponentes abstratosComponentes trabalhando juntosRevisão: torre modularRevisão: canhão duplo4Dados Serializados
Classes SerializáveisListas no InspectorEnums no InspectorRevisão: Tabela de LootRevisão: Sorteie o Loot2Interfaces no Unity
IDamageableInterfaces e TryGetComponentGetComponentsRevisão: tecla de interaçãoRevisão: mais próximo ao alcance5ScriptableObjects
Ativos de DadosAtributos da ArmaConfigurações CompartilhadasSalve o VentoOndas como DadosRevisão: Banco de ItensRevisão: Comprar na Loja3Eventos
Eventos de C# no UnityInscreva-se em OnEnableCampos de UnityEventEventos controlam a interfaceRevisão: pop-up de conquistaRevisão: temporizador do pop-up6Salvando com JSON
JsonUtilitySalve o jogoCarregar e valores padrãoRevisão: slots de salvamentoEscolha e exclua um slot9Pool de Objetos
Por que usar um pool de objetosUm pool com uma filaO ObjectPool da UnityRecapitulação: pool de projéteisPratique por conta própria: Playground de Unity