Gerenciando estado e eventos entre componentes no GameObject
Link para o projetoComo todos sabem, mais ou menos familiarizados com a plataforma Unity, cada objeto de jogo 
GameObject consiste em componentes (embutidos ou personalizados, que geralmente são chamados de "scripts"). Os componentes são 
herdados da classe base 
MonoBehavior .

E geralmente, bem ou frequentemente, é feito um link direto para vincular os componentes.

I.e. em um componente, para obter dados de outro componente, obtemos o último usando o método 
GetComponent <...> () , por exemplo:

Neste exemplo, uma referência a um componente do tipo 
SomeComponent será colocada na variável 
someComponent .
Com essa abordagem "fortemente acoplada", especialmente quando há um grande número de componentes, é muito fácil ficar confuso e manter a integridade dessa conexão. Por exemplo, se o nome de uma propriedade ou método em um componente mudar, será necessário corrigi-lo em todos os componentes que o usam. E isso é hemorragia.
Sob o corte muitas fotosCriando uma solução baseada na "forte conexão" dos componentes
Criaremos um projeto vazio para reproduzir a situação usual quando tivermos certos componentes e cada um deles se referir um ao outro, para receber dados ou controlar.
 Adicionei
Adicionei dois scripts, 
FirstComponent e 
SecondComponent , que serão usados como componentes no objeto do jogo:

Agora vou definir uma estrutura simples para cada um dos componentes necessários para os experimentos.


Agora imagine uma situação na qual precisaríamos obter os valores dos campos 
state1 do componente 
FirstComponent e chamar seu 
método ChangeState (...) no componente 
SecondComponent . Para fazer isso, você precisa obter um link para o componente e solicitar os dados necessários no componente 
SecondComponent :

Após iniciarmos o jogo no console, veremos que recebemos dados do 
FisrtComponent do 
SecondComponent e alteramos o estado do primeiro

Agora, exatamente da mesma maneira, podemos obter os dados e na direção oposta do componente 
FirstComponent para obter os dados do componente 
SecondComponent .

Após o início do jogo, também será visível que estamos recebendo dados e podemos controlar o componente 
SecondComponent do 
FirstComponent .

Este foi um exemplo bastante simples e, para entender que tipo de problema eu quero descrever, seria necessário complicar bastante a estrutura e os relacionamentos de todos os componentes, mas o significado é claro. Agora a conexão entre os componentes é a seguinte:


Expandir até mesmo um objeto de jogo com novos componentes, se eles precisarem interagir com os existentes, será bastante rotineiro. E especialmente se, por exemplo, o nome do campo 
state1 no componente 
FirstComponent for alterado, por exemplo, para 
state_1 e você precisar alterar o nome em que é usado em todos os componentes. Ou quando o componente tem muitos campos, torna-se bastante difícil navegá-los.
Criando uma solução baseada no "estado geral" entre componentes
Agora imagine que não precisaríamos obter um link para cada componente de interesse e obter dados dele, mas haveria um certo objeto que contém os estados e dados de todos os componentes no objeto do jogo. No diagrama, ficaria assim:

Estado geral ou Objeto de estado geral (SharedState) também é um componente que desempenhará a função de um componente de serviço e armazenará o estado de todos os componentes do objeto de jogo.
Vou criar um novo componente e denominar SharedState:

E determinarei o código para esse componente universal. Ele armazenará um dicionário e um indexador fechados para um trabalho mais conveniente com o dicionário de componentes, também será um encapsulamento e não funcionará diretamente com o dicionário de outros componentes.

Agora, esse componente precisa ser colocado no objeto do jogo para que os outros componentes possam acessá-lo:

Em seguida, é necessário fazer algumas alterações nos componentes 
FirstComponent e 
SecondComponent para que eles usem o componente 
SharedState para armazenar seus estados ou dados:


Como você pode ver no código do componente, não armazenamos mais o campo. Em vez disso, usamos o estado geral e temos acesso a seus dados usando a tecla “state1” ou “counter”. Agora, esses dados não estão vinculados a nenhum componente e, se um terceiro componente aparecer, tendo acesso ao SharedState, ele poderá acessar todos esses dados.
Agora, para demonstrar a operação desse esquema, você precisa alterar os métodos de Atualização nos dois componentes. No 
FisrtComponent :

E no componente 
SecondComponent :

Agora, os componentes não sabem a origem desses valores, ou seja, antes de recorrerem a algum componente específico para obtê-los, e agora eles são simplesmente armazenados em um espaço comum e qualquer componente tem acesso a eles.
Depois de iniciar o jogo, você pode ver que os componentes obtêm os valores desejados:

Agora que sabemos como ele funciona, podemos derivar a infraestrutura básica para acessar o estado geral na classe base, para não fazer tudo isso em cada componente separadamente:

E vou torná-lo abstrato, para não criar acidentalmente uma instância dela ... E também é aconselhável adicionar um atributo indicando que esse componente base requer o componente 
SharedState :

Agora você precisa alterar os componentes 
FirstComponent e 
SecondComponent para que eles herdem do 
SharedStateComponent e remova todos os desnecessários:


Ok E quanto a chamar métodos? Propõe-se fazer isso também não diretamente, mas através do padrão Publisher-Subscriber. Simplificado.
Para implementar isso, você precisa adicionar outro componente comum, semelhante ao que contém os dados, exceto que este conterá apenas assinaturas e será chamado 
SharedEvents :

O princípio é o seguinte. Um componente que deseja chamar algum método para outro componente não fará isso diretamente, mas chamando um evento, apenas pelo nome, à medida que obtemos dados do estado geral.
Cada componente assina alguns eventos que está pronto para rastrear. E se ele capturar esse evento, ele executará o manipulador, que é definido no próprio componente.
Crie o componente 
SharedEvents :

E definiremos a estrutura necessária para gerenciar assinaturas e publicações.

Para a troca de dados entre assinaturas, publicações, é definida uma classe base, uma determinada será determinada para o autor de cada evento de forma independente e, em seguida, vários exemplos serão definidos:

Agora você precisa adicionar um novo componente ao objeto do jogo:

e expanda um 
pouco a classe base 
SharedStateComponent e inclua o requisito de que o objeto contenha 
SharedEvents 

Assim como o objeto de estado geral, o objeto de assinatura geral deve ser obtido no objeto de jogo:


Agora, definimos uma assinatura de evento, que processaremos em 
FisrtComponent e uma classe para transferir dados através desse tipo de evento, e também 
alteramos SecondComponent para que o evento dessa assinatura seja publicado:


Agora, inscrevemos-se em qualquer evento chamado “writeomedata” no componente 
FirstComponent e simplesmente 
imprima uma mensagem no console quando ocorrer. E surge neste exemplo invocando a publicação de um evento com o nome "writeomedata" no componente 
SecondComponent e transferindo algumas informações que podem ser usadas no componente que captura eventos com esse nome.
Depois de iniciar o jogo em 5 segundos, veremos o resultado do processamento do evento no 
FirstComponent :

Sumário
Agora, se você precisar expandir os componentes desse objeto de jogo, que também usará o estado geral e os eventos gerais, será necessário adicionar uma classe e simplesmente herdar de 
SharedStateComponent :
 Continuação do tópico
Continuação do tópico