Comparando delegates e Unity Events
No meu vídeo sobre um padrão para enviar mensagens na Unity utilizando delegate
tive um comentário perguntando se não seria melhor utilizar o UnityEvents
por questões de performance. Eu respondi o comentário dizendo que não era um problema tão grande, até por que o envio de mensangens não é algo que quero fazer o tempo todo, mas fiquei pensando sobre outro ponto que comentei em relação a flexibilidade. Decidi fazer este post comparando o código do meu post com o UnityEvents.
Você pode ver o código completo da classe MessageManager
no meu post, mas vou postar um dos métodos aqui para ficar mais fácil de escrever sobre ele. Este é o SendMessage()
, responsável por executar o DynamicInvoke
, que usa reflection para resolver o tipo do delegate
e aloca memória pra isso. Neste link do StackOverflow existe uma boa explicação comparando o DynamicInvoke
com o Invoke
, porém para a minha classe MessageManager
precisei utilizá-lo sacrificando um pouco de performance por mais flexibilidade, além de deixar o código mais claro.
Para comparar com o UnityEvents
criei duas classes de teste, uma para chamar ele e o MessageManager
uma vez por Update
e outra para escutá-los. Para deixar o resultado mais limpo no profiler eu enviei sempre o mesmo objeto que foi criado no Awake
da classe.
UpdateTestEvent
e UpdateTestData
são uma struct
e um UnityEvent
, respectivamente. Ambos MessageManager
e UnityEvents
enviam o mesmo objeto.
E abaixo está o resto do código, responsável por adicionar e remover os listeners
. Eu não adicionar todo do código pra não deixar o post ainda maior, mas o que falta abaixo é só a parte que soma Counter
em outra variável e mostrar isso em um Text
na UI.
Agora vamos o resultado do profiler. Eu marquei dois momentos em que há a chamada do GC.Alloc
, o primeiro é relacionado ao DynamicInvoke
, e o segundo não consegui entender da onde veio mas está relacionado ao SendMessage()
também, alocando um total de 68 bytes por cada vez que o MessageManager
é usado para enviar um objeto e demora 0.03 milisegundos. Já o UnityEvents
não está alocando nada de memória extra e nem demora para ser executado.
Então isso quer dizer que o UnityEvents
é o melhor para este caso? Depende. Evitar usar um delegate
com DynamicInvoke
para enviar um objeto como mensagem de vez em quando não vai causar impacto suficiente para reduzir o uso de memória ou aumentar o FPS do seu jogo. Neste exemplo, e no exemplo do meu vídeo, o uso do UnityEvents
é praticamente o mesmo que o MessageManager
, então seria um bom caso para evitar o DynamicInvoke
desnecessário.
Eu não consegui pensar em um exemplo onde o meu código se encaixaria melhor do que o UnityEvents
, mas como escrevi no outro post meu objetivo era mostrar uma implementação do design patter Observer. É importante entender como os padrões funcionam para saber qual pode ser útil em uma determinada situação, mesmo que seja para usar uma “solução pronta” como o UnityEvents
.