Files
Documentation/content/world/entities/npc/npc-ai.fr.md
2026-01-20 20:33:59 +01:00

9.8 KiB

title, type, weight
title type weight
IA NPC docs 3

Le système d'IA NPC fournit une prise de décision intelligente via les blackboards, decision makers, capteurs et instructions.

Packages:

  • com.hypixel.hytale.server.npc.blackboard
  • com.hypixel.hytale.server.npc.decisionmaker
  • com.hypixel.hytale.server.npc.sensorinfo
  • com.hypixel.hytale.server.npc.instructions

Système Blackboard

Le Blackboard est un espace mémoire partagé où les composants NPC communiquent via des paires clé-valeur.

Classe Blackboard

public class Blackboard {
    private Map<BlackboardKey<?>, Object> data;

    // Stocker une valeur
    public <T> void set(BlackboardKey<T> key, T value);

    // Récupérer une valeur
    public <T> T get(BlackboardKey<T> key);
    public <T> T getOrDefault(BlackboardKey<T> key, T defaultValue);

    // Vérifier l'existence
    public boolean has(BlackboardKey<?> key);

    // Supprimer une valeur
    public void remove(BlackboardKey<?> key);

    // Tout effacer
    public void clear();
}

BlackboardKey

Clés typées pour l'accès au blackboard :

// Clés prédéfinies
public class BlackboardKeys {
    public static final BlackboardKey<Entity> TARGET =
        new BlackboardKey<>("target", Entity.class);
    public static final BlackboardKey<Vector3d> HOME_POSITION =
        new BlackboardKey<>("home_position", Vector3d.class);
    public static final BlackboardKey<Float> ALERT_LEVEL =
        new BlackboardKey<>("alert_level", Float.class);
    public static final BlackboardKey<Boolean> IN_COMBAT =
        new BlackboardKey<>("in_combat", Boolean.class);
}

// Clés personnalisées
BlackboardKey<String> CUSTOM_KEY = new BlackboardKey<>("custom_data", String.class);

Utiliser le Blackboard

NPCEntity npc = // obtenir le NPC
Blackboard bb = npc.getBlackboard();

// Définir la cible
bb.set(BlackboardKeys.TARGET, targetEntity);

// Obtenir la position d'origine
Vector3d home = bb.getOrDefault(BlackboardKeys.HOME_POSITION, npc.getPosition());

// Vérifier le statut de combat
if (bb.getOrDefault(BlackboardKeys.IN_COMBAT, false)) {
    // Gérer le combat
}

Système Decision Maker

Le Decision Maker évalue les options et sélectionne la meilleure action pour le NPC.

Interface DecisionMaker

public interface DecisionMaker {
    // Évaluer et sélectionner la meilleure option
    Option evaluate(NPCEntity npc, Blackboard blackboard);

    // Obtenir toutes les options disponibles
    List<Option> getOptions();

    // Ajouter une option
    void addOption(Option option);
}

Classe Option

Les options représentent les actions possibles :

public class Option {
    private String id;
    private Evaluator evaluator;
    private Action action;
    private float basePriority;

    // Calculer le score selon le contexte
    public float evaluate(NPCEntity npc, Blackboard blackboard);

    // Exécuter l'action
    public void execute(NPCEntity npc, Blackboard blackboard);
}

Interface Evaluator

Les évaluateurs calculent les scores des options :

public interface Evaluator {
    // Retourne un score de 0.0 à 1.0
    float evaluate(NPCEntity npc, Blackboard blackboard);
}

// Évaluateurs intégrés
public class Evaluators {
    // Retourne 1.0 si une cible existe
    public static final Evaluator HAS_TARGET = (npc, bb) ->
        bb.has(BlackboardKeys.TARGET) ? 1.0f : 0.0f;

    // Retourne le pourcentage de vie
    public static final Evaluator HEALTH_PERCENT = (npc, bb) ->
        npc.getHealth() / npc.getMaxHealth();

    // Retourne 1.0 si à la maison
    public static final Evaluator AT_HOME = (npc, bb) -> {
        Vector3d home = bb.get(BlackboardKeys.HOME_POSITION);
        return npc.getPosition().distance(home) < 5.0 ? 1.0f : 0.0f;
    };
}

Créer un Decision Maker

DecisionMaker dm = new StandardDecisionMaker();

// Ajouter option d'attaque
dm.addOption(new Option(
    "attack",
    Evaluators.HAS_TARGET,
    new AttackAction(),
    10.0f  // Haute priorité
));

// Ajouter option de fuite
dm.addOption(new Option(
    "flee",
    (npc, bb) -> npc.getHealth() < 20 ? 1.0f : 0.0f,
    new FleeAction(),
    15.0f  // Priorité plus haute quand déclenché
));

// Ajouter option d'errance
dm.addOption(new Option(
    "wander",
    (npc, bb) -> 0.3f,  // Score constant bas
    new WanderAction(),
    1.0f   // Basse priorité par défaut
));

npc.setDecisionMaker(dm);

Système de Capteurs

Les capteurs collectent des informations sur le monde et mettent à jour le blackboard.

Interface Sensor

public interface Sensor {
    // Traiter l'entrée du capteur
    void sense(NPCEntity npc, Blackboard blackboard, float deltaTime);

    // Obtenir le type de capteur
    String getSensorType();
}

Classes SensorInfo

Conteneurs d'informations de capteurs :

// Info de détection visuelle
public class VisualSensorInfo {
    private List<Entity> visibleEntities;
    private float detectionRange;
    private float fieldOfView;

    public List<Entity> getVisibleEntities();
    public boolean canSee(Entity entity);
}

// Info de détection audio
public class AudioSensorInfo {
    private List<SoundEvent> heardSounds;
    private float hearingRange;

    public List<SoundEvent> getHeardSounds();
    public Vector3d getLoudestSoundPosition();
}

// Info de détection de menace
public class ThreatSensorInfo {
    private List<Entity> threats;
    private Entity primaryThreat;
    private float threatLevel;
}

Capteurs Intégrés

// Capteur visuel - détecte les entités visibles
public class VisualSensor implements Sensor {
    private float range = 20.0f;
    private float fov = 120.0f;  // degrés

    @Override
    public void sense(NPCEntity npc, Blackboard bb, float dt) {
        List<Entity> visible = findVisibleEntities(npc);
        bb.set(BlackboardKeys.VISIBLE_ENTITIES, visible);
    }
}

// Capteur de proximité - détecte les entités proches
public class ProximitySensor implements Sensor {
    private float range = 5.0f;

    @Override
    public void sense(NPCEntity npc, Blackboard bb, float dt) {
        List<Entity> nearby = findNearbyEntities(npc, range);
        bb.set(BlackboardKeys.NEARBY_ENTITIES, nearby);
    }
}

// Capteur de dégâts - réagit aux dégâts subis
public class DamageSensor implements Sensor {
    @Override
    public void sense(NPCEntity npc, Blackboard bb, float dt) {
        if (npc.wasRecentlyDamaged()) {
            bb.set(BlackboardKeys.LAST_ATTACKER, npc.getLastAttacker());
            bb.set(BlackboardKeys.ALERT_LEVEL, 1.0f);
        }
    }
}

Système d'Instructions

Les instructions définissent des objectifs comportementaux de haut niveau.

Interface Instruction

public interface Instruction {
    // Vérifier si l'instruction doit s'activer
    boolean shouldActivate(NPCEntity npc, Blackboard blackboard);

    // Exécuter la logique de l'instruction
    void execute(NPCEntity npc, Blackboard blackboard, float deltaTime);

    // Vérifier si l'instruction est complète
    boolean isComplete(NPCEntity npc, Blackboard blackboard);

    // Obtenir la priorité
    float getPriority();
}

Instructions Intégrées

// Instruction d'errance
public class WanderInstruction implements Instruction {
    private float wanderRadius;
    private float minWaitTime;
    private float maxWaitTime;

    @Override
    public boolean shouldActivate(NPCEntity npc, Blackboard bb) {
        return !bb.has(BlackboardKeys.TARGET);
    }
}

// Instruction de garde
public class GuardInstruction implements Instruction {
    private Vector3d guardPosition;
    private float guardRadius;

    @Override
    public void execute(NPCEntity npc, Blackboard bb, float dt) {
        if (npc.getPosition().distance(guardPosition) > guardRadius) {
            bb.set(BlackboardKeys.MOVE_TARGET, guardPosition);
        }
    }
}

// Instruction de suivi
public class FollowInstruction implements Instruction {
    private Entity followTarget;
    private float followDistance;
}

// Instruction de patrouille
public class PatrolInstruction implements Instruction {
    private List<Vector3d> patrolPoints;
    private int currentPoint;
}

Combiner les Systèmes d'IA

public void setupNPCAI(NPCEntity npc) {
    // Configurer le blackboard
    Blackboard bb = npc.getBlackboard();
    bb.set(BlackboardKeys.HOME_POSITION, npc.getPosition());
    bb.set(BlackboardKeys.AGGRO_RANGE, 15.0f);

    // Ajouter les capteurs
    npc.addSensor(new VisualSensor(20.0f, 120.0f));
    npc.addSensor(new ProximitySensor(5.0f));
    npc.addSensor(new DamageSensor());

    // Configurer le decision maker
    DecisionMaker dm = new StandardDecisionMaker();
    dm.addOption(new Option("attack", hasHostileTarget, attackAction, 10.0f));
    dm.addOption(new Option("flee", lowHealth, fleeAction, 15.0f));
    dm.addOption(new Option("patrol", isGuard, patrolAction, 5.0f));
    dm.addOption(new Option("idle", always, idleAction, 1.0f));
    npc.setDecisionMaker(dm);

    // Ajouter les instructions
    npc.addInstruction(new GuardInstruction(guardPost, 10.0f));
    npc.addInstruction(new ReactToThreatInstruction());
}

Bonnes Pratiques

{{< callout type="info" >}} Directives IA :

  • Utilisez le Blackboard pour toute communication inter-composants
  • Gardez les Évaluateurs simples et rapides - ils s'exécutent fréquemment
  • Utilisez des portées de capteurs appropriées pour équilibrer conscience vs performance
  • Concevez les Instructions pour être interruptibles
  • Testez le comportement IA avec différents scénarios {{< /callout >}}

{{< callout type="warning" >}} Performance : Un grand nombre de NPCs avec une IA complexe peut impacter les performances. Considérez :

  • Réduire la fréquence de mise à jour des capteurs pour les NPCs distants
  • Utiliser le LOD (Level of Detail) pour la complexité IA
  • Limiter les requêtes de pathfinding {{< /callout >}}