Salut, Habr. Mon histoire commence en janvier 2019.
Mes développeurs de jeux Tima et moi avons décidé de prendre le plus grand projet de notre histoire, un jeu de plateforme 2D. Non, nous n'avions jamais fait de FlappyBirds ou de serpents auparavant, mais la quantité de travail dans ce projet nous a tout simplement époustouflé. Pour commencer, nous avons abandonné les escaliers verticaux habituels et avons monté les marches. Nous avons écrit la logique des portes, qui pouvaient être verrouillées «avec une clé» et vissé les blocs destructibles. Il est arrivé un moment où il fallait écrire l'intelligence artificielle. En tant que scripteur le plus expérimenté de notre équipe inexpérimentée, l'honneur d'écrire l'IA m'est tombé.
J'ai pleuré dans l'oreiller, ne comprenant pas quoi faire, j'étais très fier d'écrire l'une des mécaniques les plus difficiles de notre projet.
Étape 1: trouver le chemin et se déplacer le long du chemin
Étape 1.1: Trouver le chemin
Étant donné que les principaux sites ne seront pas en plein air, mais dans les bâtiments, il a fallu rechercher l'itinéraire parmi des dizaines de portes, escaliers et pièces. Après réflexion, le chef d'équipe a décidé qu'il valait la peine de faire une certaine parodie de l'algorithme A *, où nous aurions des nœuds entre lesquels le bot s'exécuterait. fait une scène de test, mis les nœuds, pour plus de clarté, accroché SprateRenderers sur eux. Que faire ensuite?
Avec cette question à l'esprit, j'ai marché pendant 3 jours. Jusqu'à présent, un de mes camarades n'a pas proposé d'algorithme intéressant lorsque les nœuds seront excités, comme les neurones du cerveau.
Alors. Il y a un nœud A, près duquel se trouve une IA et un nœud B, auquel l'IA devrait venir. a donné à tous les nœuds leur ID et a marqué les nœuds connectés auxquels ils enverront un signal. Chaque nœud avait sa propre variable booléenne "isChecked" et la variable "triggeredBy", qui contenait l'ID du nœud qui l'avait "excité". Ainsi, lorsque le nœud B est affecté, il passera par la chaîne jusqu'au nœud A, reconnaissant tous les ID des nœuds traversés par le signal. J'ai donc obtenu le chemin à partir des ID des nœuds que le bot devrait traverser. Si soudain vous ne comprenez pas comment cela fonctionne, alors je vais vous raconter une histoire.
Une fois, Ivan n'avait rien à faire, et il a donc décidé de faire son arbre généalogique. Malheureusement, il ne disposait pas de suffisamment d'informations pour traduire cette idée en réalité. Ivan était si passionné par cette idée qu'il a décidé que lorsqu'il atteindrait le géniteur principal, il pourrait découvrir ses parents inattendus. Ivan savait où il pouvait rencontrer son père pour parler et s'y rendit. Le père lui a dit que le nom du grand-père d'Ivan était Ivan et lui a dit où il pouvait être trouvé. Ivan a trouvé Ivan, et il a dit que l'arrière-grand-père d'Ivan pouvait connaître personnellement cet ancêtre, mais il était mort depuis longtemps. Ivan a consacré la moitié de sa vie à l'étude des arts sombres, mais il a finalement pu ressusciter son arrière-grand-père. L'arrière-grand-père a déclaré que son ancêtre était un loup-garou et que son corps était enterré au bord des trois pins. Ivan s'y est rendu et a trouvé un homme en train de creuser une tombe. Il s'est avéré que cet homme est le cousin de douze ans Ivan. Ivan était très surpris qu'ils soient venus à un seul endroit, mais son frère s'est avéré être un programmeur et a tout expliqué.
- Le principe de navigation de mon jeu préféré * nom * fonctionne ici!
- Et c'est quoi?
- De chaque héritier, vous pouvez venir au parent commun du système, si dans ce système chaque héritier connaît personnellement son parent.
Voici le résultat:

Il s'agit d'un tableau de variables int qui signifie les ID des nœuds que l'unité doit parcourir.
Étape 1.2.1: déplacement le long du chemin
J'ai une liste d'ID de nœuds, j'ai un bot. Et ensuite? Et puis ce dont vous avez besoin pour déplacer le bot le long de ce chemin.
Eh bien, j'ai pensé à cette option: le bot a atteint le nœud, vérifié, regardé ce qui était ensuite, est allé au nœud suivant. L'a fait. Gagné. J'étais content ... Mais ...
Étape 1.2.2: les échelles et leur interaction avec l'IA
Comme le disait un héros en noir et blanc: "Escaliers ... mon principal ennemi .."
Il était nécessaire de déterminer si le nœud suivant est au-dessus de l'IA, en dessous ou au niveau. En fonction de ces informations, il passera devant les escaliers (ignorera la collision) ou montera dessus (interagira avec la collision). Oh, et beaucoup de cellules nerveuses sont mortes dans cette bataille avec le moteur ... Sur les forums, j'ai lu que vous pouvez tout organiser en couches et dans l'onglet Édition-> Physique2D, vous pouvez configurer en ignorant les collisions d'une couche et d'une autre. Tout a fonctionné!
Il ne reste plus qu'à lui apprendre à ouvrir la porte. Il n'y a eu aucun problème.
Le résultat:


Étape 2: émotions et signaux
Étape 2.1: Émotions
Oui, nous avons décidé d'attacher des émotions ... Et des indices.
Les émotions seront mises en évidence avec des expressions faciales et des animations d'action.
Les répliques seront affichées avec des frais généraux de texte.
J'ai foutu les émotions d'un seul coup ... Pour cela, j'ai déjà fait la variable "emotionID", qui stockait l'ID de l'émotion. Et voici les répliques ...
Étape 2.2: répliques
Pour la beauté fait une classe séparée Phrases
[System.Serializable]
Fait un tableau de cette classe. De plus, juste en fonction de emotionID, j'ai mis n'importe quelle phrase de la liste. Mis à jour une fois toutes les N secondes.
Mais j'ai décidé d'aller plus loin! Pour chaque caractère, j'ai créé un fichier avec l'extension .phrs, codé en ajoutant X octets au nombre d'octets de chaque caractère dans le fichier. Le résultat était un texte illisible et immuable. a fait quelque chose comme son balisage, fait un algorithme qui prend et traduit tout dans ce tableau dans la classe Phrases par ce balisage.
Super! Tout fonctionne!
Je voulais écrire un programme sur un sharpe propre pour remplir un tel fichier, mais ici nous allons à la fin de l'histoire.
La fin ..?
Nous étions vite fatigués du gros travail non rémunéré ... La fixation d'un nouvel encodeur n'a pas aidé ... L'équipe s'est effondrée ... Le code se trouve toujours sur le cloud Unity.
Bien sûr, il n'y a pas si longtemps, l'idée de poursuivre le projet a commencé à émerger, mais avec une monétisation plus poussée ... Si quelque chose fonctionne, alors j'écrirai probablement toute l'histoire du développement. Mais c'est là que se termine mon histoire sur le scripteur novice et l'IA.