374 lines
9.8 KiB
Markdown
374 lines
9.8 KiB
Markdown
---
|
|
title: IA NPC
|
|
type: docs
|
|
weight: 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
|
|
|
|
```java
|
|
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 :
|
|
|
|
```java
|
|
// 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
|
|
|
|
```java
|
|
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
|
|
|
|
```java
|
|
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 :
|
|
|
|
```java
|
|
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 :
|
|
|
|
```java
|
|
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
|
|
|
|
```java
|
|
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
|
|
|
|
```java
|
|
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 :
|
|
|
|
```java
|
|
// 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
|
|
|
|
```java
|
|
// 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
|
|
|
|
```java
|
|
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
|
|
|
|
```java
|
|
// 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
|
|
|
|
```java
|
|
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 >}}
|