IA d’Entité

L’IA d’Entité (à ne pas confondre avec l’IA actuelle) est la logique qui contrôle les agents. Elle est structurée à l’aide d’objectifs (ex : vaincs les ennemis) qu’une entité essaie de réaliser avec des tâches plus petites (ex : va vers un ennemi et le frapper avec ton arme). Les sections suivantes décrivent ce que les objectifs, les tâches et les autres composants de l’API d’IA d’Entité sont, comment vous pouvez changer le comportement des entités, et décrivent comment vous pouvez écrire vos propres objectifs d’IA.

Les Agents

Un Agent est un type d”Entity vivante qui supporte l’IA et donc simule le comportement typique des mobs. Vous pouvez vérifier si une Entity est également un Agent en essayant simplement de le cast.

import org.spongepowered.api.entity.living.Agent;

World world = ...;
UUID uuid = ...;

Agent entity = (Agent) world.getEntity(uuid).get();

if (entity.getAgentData().aiEnabled().get()) {
    configureAI(entity);
}

Après le cast, nous pouvons également vérifier si l’IA est actuellement activée. Certains plugins la désactive pour simuler des statues, des gardes ou des magasins.

Objectifs

Dans Minecraft vanilla il y a deux types de Goals.

Le premier est celui par défaut : NORMAL. Cette partie de l’IA contrôle le comportement de l’entité. Cet objectif contient les tâches comme attaquer une cible en utiliser une arme de mêlée ou à distance et regarder dans la zone si il n’y a pas d’ennemi proche. Si nous voulons réécrire ou modifier l’IA nous changerons habituellement cet objectif et ses tâches.

Le deuxième objectif est plus pour les mobs hostiles TARGET. Cet objectif contient des tâches qui aident l’entité à identifier quelle cible elle doit sélectionner puis attaquer à l’aide de l’objectif normal. L’objectif target contient des tâches comme sélectionner la cible attaquable la plus proche et sélectionner l’ennemi qui vous a attaqué en premier.

Le code suivant récupère l’objectif NORMAL de l’entité et le vide.

import org.spongepowered.api.entity.ai.Goal;
import org.spongepowered.api.entity.ai.GoalTypes;

Agent entity = ...;

Optional<Goal<Agent>> normalGoal = entity.getGoal(GoalTypes.NORMAL);
if (normalGoal.isPresent()) {
    normalGoal.get().clear();
}

Une entité avec un objectif vide ne se déplacera pas par lui-même, cependant il terminera son action/mouvement actuel et peut prendre une pose inactive (c’est-à-dire regarder droit devant). L’IA n’affecte pas les bruitages que l’entité pourrait jouer aléatoirement.

Note

Veuillez noter qu’éditer les objectifs ou tâches d’une entité va directement éditer l’entité. Ce comportement diffère des autres parties de l’API où seules des copies sont retournées et qui doivent être appliquées par la suite. Ainsi, il n’est pas possible de transférer les tâches d’une entité vers une autre.

Note

Toute modification apportée à l’IA des entités sera perdue après un redémarrage de serveur ou après le déchargement de l’entité.

Tâches

Le comportement de nombreux types d’entités sont similaires entre eux. Pour cette raison, l’IA d’entité se divise en plusieurs parties plus petites et réutilisables appelées AITasks. Chacune des AITasks représente un seul trait de comportement d’une entité, comme WATCH_CLOSEST, qui fait regarder l’entité vers l’entité correspondante la plus proche, ou AVOID_ENTITY, qui fait fuir l’entité de certaines entités correspondantes.

Note

Minecraft vanilla fournit lui-même en énorme variété de AITaskss, cependant la plupart d’entre eux ne sont pas encore accessibles via l’API.

Ajout d’AITasks Supplémentaires

Ajouter des AITasks additionnels à l’objectif d’une Entity est assez facile. Nous commençons par créer une AITask simple.

import org.spongepowered.api.entity.ai.task.builtin.WatchClosestAITask;

Agent entity = ...;
Goal<Agent> goal = ...;

WatchClosestAITask watchClosestAiTask = WatchClosestAITask.builder()
        .chance(1)
        .maxDistance(30)
        .watch(Player.class)
        .build(entity);
goal.addTask(0, watchClosestAiTask);

Dans cet exemple, nous créons une WatchClosestAITask à l’aide du builder associé. En utilisant le build nous définissons les chances de déclenchement de cet objectif à 100%. Ainsi, l’entité va garder au Player le plus proche dans un rayon de 30 blocs. Nous assignons zéro en priorité, ce qui représente une priorité élevée, ainsi cet objectif est prioritaire par rapport aux autres tâches.

Note

Minecraft utilise des valeurs faibles comme priorité élevée et des valeurs élevées comme priorité faible. Par défaut, Minecraft utilise des valeurs de priorité de zéro à environ dix.

Suppression de Certaines AITasks

Supprimer les AITasks correctes peut être un peu délicat, surtout si des entités moddées ou de l’IA personnalisée entrent en jeu. l’API Sponge essaie de fournir un moyen de lever l’ambiguïté. Appeler AITask#getType() retourne un AITaskType qui peut être utilisé pour distinguer les types de tâches existants.

Tout d’abord nous essayons la version simple qui va seulement fonctionner si il n’y a pas de mod modifiant l’IA de présent :

Goal<Zombie> goal = ...;

AITask<Zombie> attackTask = (AITask<Zombie>) goal.getTasks().get(1); // EntityAIZombieAttack
goal.removeTask(attackTask);

Dans ce cas nous comptons aveuglément sur le fait que dans Minecraft vanilla 1.2.2, les Zombies auront la tâche EntityAIZombieAttack en deuxième tâche. Après ça vous n’aurez plus à craindre des attaques de ce zombie. Comme vous pouvez l’imaginer, cette stratégie à des défauts, car elle nécessite des connaissances explicites sur l’ordre des tâches d’IA dans l’entité donnée.

Note

Il n’est pas possible de supprimer de AITasks directement à partir de la liste retournée par Goal#getTasks() car elle est immuable.

Une façon beaucoup plus simple mais également moins puissante de supprimer des tâches est de les supprimer par leur type. C’est l’approche que vous devez suivre, si vous n’avez pas besoin des intérieurs de la tâche pour identifier quelle tâche doit être supprimée.

goal.removeTasks(AITaskTypes.WANDER);

Dans ce cas, nous supprimons toutes les AITasks qui ont le AITaskType WANDER.

Note

Actuellement cette façon est sérieusement limitée en matière d’exploitibilité à cause du support incomplet de AITaskType dans l’API.

Si vous souhaitez supprimer toutes les AITasks, parce que vous voulez configurer l’IA de l’entité à partir de zéro, vous pouvez également utiliser Goal#clear().

Implémenter Votre Propre AITask

Nous pouvons également essayer d’implémenter nos propres AITasks. La page Implémenter Vos Propres AITasks décrit le processus et certains obstacles que vous rencontrerez.

Événements

L’API d’AI ainsi que la plupart de autres parts de la SpongeAPI utilisent les événements. Vous pouvez en savoir plus sur les événements ici.

L’API d’AI elle-même utilise les 3 événements suivants :

L’événement AITaskEvent.Add est publié chaque fois qu’un nouvel AITask a été ajouté à un Goal, de même, l’événement AITaskEvent.Remove est publié si un AITask a été supprimé.

Le SetAITargetEvent est publié à chaque fois qu’un Agent sélectionne une nouvelle cible (généralement pour attaquer) ou lâche une cible.

Tous ces événements sont annulables, nous permettant ainsi d’empêcher tout changement tiers indésirable à nos entités personnalisées.