Gestion de l'état et des événements entre les composants de GameObject

Gestion de l'état et des événements entre les composants de GameObject


Lien vers le projet

Comme chacun le sait, plus ou moins familier avec la plate-forme Unity, chaque objet de jeu GameObject est constitué de composants (intégrés ou personnalisés, ce qui est généralement appelé un «script»). Les composants héritent de la classe de base MonoBehavior .



Et généralement, bien ou souvent, un lien direct est établi pour lier les composants.



C'est-à-dire dans un composant, pour obtenir des données d'un autre composant, nous obtenons ce dernier en utilisant la méthode GetComponent <...> () , par exemple comme ceci:



Dans cet exemple, une référence à un composant de type SomeComponent sera placée dans la variable someComponent .

Avec cette approche «étroitement couplée», surtout quand il y a un grand nombre de composants, il est assez facile de se confondre et de maintenir l'intégrité d'une telle connexion. Par exemple, si le nom d'une propriété ou d'une méthode dans un composant change, vous devrez le corriger dans tous les composants qui l'utilisent. Et c'est une hémorragie.

Sous la coupe beaucoup de photos

Créer une solution basée sur la «forte connectivité» des composants


Nous allons créer un projet vide pour reproduire la situation habituelle lorsque nous avons certains composants et que chacun d'eux se réfère les uns aux autres, pour recevoir des données ou pour contrôler.



J'ai ajouté deux scripts, FirstComponent et SecondComponent , qui seront utilisés comme composants dans l'objet de jeu:



Je vais maintenant définir une structure simple pour chacun des composants nécessaires aux expériences.





Imaginez maintenant une situation dans laquelle nous aurions besoin d'obtenir les valeurs du champ state1 du composant FirstComponent et d'appeler sa méthode ChangeState (...) dans le composant SecondComponent . Pour ce faire, vous devez obtenir un lien vers le composant et demander les données nécessaires dans le composant SecondComponent :



Après avoir démarré le jeu dans la console, on verra que nous avons reçu des données de FisrtComponent de SecondComponent et changé l'état du premier



Maintenant, exactement de la même manière, nous pouvons obtenir les données et dans la direction opposée du composant FirstComponent pour obtenir les données du composant SecondComponent .



Après le démarrage du jeu, il sera également visible que nous recevons des données et pouvons contrôler le composant SecondComponent à partir de FirstComponent .



C'était un exemple assez simple, et pour comprendre quel genre de problème je veux décrire, il serait nécessaire de compliquer considérablement la structure et les relations de tous les composants, mais le sens est clair. Maintenant, la connexion entre les composants est la suivante:





L'expansion d'un seul objet de jeu avec de nouveaux composants, s'ils ont besoin d'interagir avec des objets existants, sera plutôt routinière. Et surtout si, par exemple, le nom du champ state1 dans le composant FirstComponent change, par exemple, en state_1 et que vous devez changer le nom où il est utilisé dans tous les composants. Ou lorsque le composant contient trop de champs, il devient alors assez difficile de les parcourir.

Création d'une solution basée sur «l'état général» entre les composants


Imaginez maintenant que nous n'aurions pas besoin d'obtenir un lien vers chaque composant d'intérêt et d'obtenir des données de celui-ci, mais il y aurait un certain objet qui contient les états et les données de tous les composants de l'objet de jeu. Dans le diagramme, cela ressemblerait à ceci:



L'état général ou l'objet État général (SharedState) est également un composant qui jouera le rôle d'un composant de service et stockera l'état de tous les composants de l'objet de jeu.

Je vais créer un nouveau composant et le nommer SharedState:



Et je vais déterminer le code de ce composant universel. Il stockera un dictionnaire et un indexeur fermés pour un travail plus pratique avec le dictionnaire de composants, ce sera également l'encapsulation et il ne fonctionnera pas directement avec le dictionnaire d'autres composants.



Maintenant, ce composant doit être placé sur l'objet de jeu afin que les autres composants puissent y accéder:



Ensuite, vous devez apporter quelques modifications aux composants FirstComponent et SecondComponent afin qu'ils utilisent le composant SharedState pour stocker leur état ou leurs données:





Comme vous pouvez le voir dans le code du composant, nous ne stockons plus le champ, nous utilisons plutôt l'état général et avons accès à ses données à l'aide de la clé «état1» ou «compteur». Maintenant, ces données ne sont liées à aucun composant, et si un troisième composant apparaît, alors avoir accès à SharedState, il pourra accéder à toutes ces données.

Maintenant, pour illustrer le fonctionnement de ce schéma, vous devez modifier les méthodes de mise à jour dans les deux composants. Dans FisrtComponent :



Et dans le composant SecondComponent :



Maintenant, les composants ne connaissent pas l'origine de ces valeurs, c'est-à-dire avant de se tourner vers un composant spécifique pour les obtenir, et maintenant ils sont simplement stockés dans un espace commun et n'importe quel composant y a accès.

Après avoir démarré le jeu, vous pouvez voir que les composants obtiennent les valeurs souhaitées:



Maintenant que nous savons comment cela fonctionne, nous pouvons dériver l'infrastructure de base pour accéder à l'état général dans la classe de base, afin de ne pas tout faire séparément dans chaque composant:



Et je vais le rendre abstrait, afin de ne pas en créer accidentellement une instance ... Et il est également conseillé d'ajouter un attribut indiquant que ce composant de base nécessite le composant SharedState :



Vous devez maintenant modifier les composants FirstComponent et SecondComponent afin qu'ils héritent de SharedStateComponent et supprimez tous les éléments inutiles:





Ok Qu'en est-il des méthodes d'appel? Il est proposé de le faire également non pas directement, mais via le modèle Publisher-Subscriber. Simplifié.

Pour l'implémenter, vous devez ajouter un autre composant commun, similaire à celui qui contient les données, sauf que celui-ci ne contiendra que des abonnements et sera appelé SharedEvents :



Le principe est le suivant. Un composant qui veut appeler une méthode sur un autre composant ne le fera pas directement, mais en appelant un événement, juste par son nom, car nous obtenons des données de l'état général.

Chaque composant est abonné à certains événements qu'il est prêt à suivre. Et s'il intercepte cet événement, il exécute le gestionnaire, qui est défini dans le composant lui-même.
Créez le composant SharedEvents :



Et nous définirons la structure nécessaire pour gérer les abonnements et les publications.



Pour l'échange de données entre abonnements, publications, une classe de base est définie, une classe spécifique sera déterminée indépendamment pour l'auteur de chaque événement, puis plusieurs exemples seront définis:



Vous devez maintenant ajouter un nouveau composant à l'objet de jeu:



et développez un peu la classe de base SharedStateComponent et ajoutez l'exigence que l'objet contienne SharedEvents



En plus de l'objet d'état général, l'objet d'abonnement général doit être obtenu à partir de l'objet de jeu:





Nous définissons maintenant un abonnement aux événements, que nous traiterons dans FisrtComponent et une classe pour le transfert de données via ce type d'événement, et changerons également SecondComponent pour que l'événement de cet abonnement soit publié:





Nous avons maintenant souscrit à tout événement appelé «writesomedata» dans le composant FirstComponent et imprimons simplement un message à la console quand il se produit. Et cela survient dans cet exemple en invoquant la publication d'un événement avec le nom «writesomedata» dans le composant SecondComponent et en transmettant certaines informations qui peuvent être utilisées dans le composant qui capture les événements sous ce nom.

Après avoir démarré le jeu en 5 secondes, nous verrons le résultat du traitement de l'événement dans FirstComponent :



Résumé


Maintenant, si vous devez développer les composants de cet objet de jeu, qui utilisera également l'état général et les événements généraux, vous devez ajouter une classe et hériter simplement de SharedStateComponent :



Suite du sujet

Source: https://habr.com/ru/post/fr438554/


All Articles