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

366 lines
9.2 KiB
Markdown

---
title: Mouvement NPC
type: docs
weight: 4
---
Le système de mouvement NPC gère la navigation, le pathfinding et le contrôle de mouvement pour les NPCs.
**Packages:**
- `com.hypixel.hytale.server.npc.movement`
- `com.hypixel.hytale.server.npc.navigation`
## Motion Controller
Le `MotionController` exécute les commandes de mouvement et gère la locomotion des NPCs.
### Classe MotionController
```java
public class MotionController {
private NPCEntity npc;
private MovementState state;
private float currentSpeed;
private Vector3d targetVelocity;
// Commandes de mouvement
public void moveTo(Vector3d target);
public void moveInDirection(Vector3d direction);
public void stop();
// Contrôle de vitesse
public void setSpeed(float speed);
public void walk();
public void run();
public void sprint();
// Requêtes d'état
public boolean isMoving();
public boolean hasReachedTarget();
public MovementState getState();
}
```
### États de Mouvement
```java
public enum MovementState {
IDLE, // Immobile
WALKING, // Mouvement normal
RUNNING, // Mouvement rapide
SPRINTING, // Vitesse maximum
JUMPING, // En l'air (saut)
FALLING, // En l'air (chute)
SWIMMING, // Dans l'eau
CLIMBING, // Sur échelle/liane
SLIDING // Sur pente
}
```
### Utiliser MotionController
```java
NPCEntity npc = // obtenir le NPC
MotionController motion = npc.getMotionController();
// Se déplacer vers une position
motion.moveTo(targetPosition);
// Définir la vitesse de mouvement
motion.run(); // ou motion.setSpeed(5.0f);
// Vérifier si arrivé
if (motion.hasReachedTarget()) {
// Destination atteinte
}
// Arrêter le mouvement
motion.stop();
```
## Path Follower
Le `PathFollower` suit et parcourt les chemins calculés.
### Classe PathFollower
```java
public class PathFollower {
private List<Vector3d> path;
private int currentIndex;
private float waypointRadius;
private boolean smoothPath;
// Gestion de chemin
public void setPath(List<Vector3d> path);
public void clearPath();
public boolean hasPath();
// Suivi
public Vector3d getNextWaypoint();
public void advanceToNextWaypoint();
public boolean hasReachedWaypoint(Vector3d position);
// Progression
public float getPathProgress(); // 0.0 à 1.0
public int getRemainingWaypoints();
}
```
### Exemple de Suivi de Chemin
```java
PathFollower pathFollower = npc.getPathFollower();
MotionController motion = npc.getMotionController();
// Définir un chemin
pathFollower.setPath(calculatedPath);
// Dans la boucle de mise à jour
if (pathFollower.hasPath()) {
Vector3d nextWaypoint = pathFollower.getNextWaypoint();
// Se déplacer vers le waypoint
motion.moveTo(nextWaypoint);
// Vérifier si atteint
if (pathFollower.hasReachedWaypoint(npc.getPosition())) {
pathFollower.advanceToNextWaypoint();
}
}
```
## Navigation Graph
Le système de navigation utilise le pathfinding A* sur un graphe de navigation.
### Classe NavigationGraph
```java
public class NavigationGraph {
// Trouver un chemin entre deux points
public List<Vector3d> findPath(
Vector3d start,
Vector3d end,
NavigationConfig config
);
// Vérifier si un point est navigable
public boolean isNavigable(Vector3d position);
// Obtenir le point navigable le plus proche
public Vector3d getNearestNavigablePoint(Vector3d position);
}
```
### NavigationConfig
```java
public class NavigationConfig {
private float maxDistance; // Longueur max du chemin
private float stepHeight; // Hauteur max de marche
private float entityWidth; // Largeur de collision entité
private float entityHeight; // Hauteur de collision entité
private boolean canSwim; // Autoriser chemins aquatiques
private boolean canClimb; // Autoriser échelles/lianes
private boolean canOpenDoors; // Autoriser traversée de portes
private Set<String> avoidBlocks; // Blocs à éviter
// Pattern builder
public static NavigationConfig builder()
.maxDistance(100.0f)
.stepHeight(1.0f)
.entityWidth(0.6f)
.entityHeight(1.8f)
.canSwim(false)
.build();
}
```
### Exemple de Pathfinding
```java
NavigationGraph navGraph = world.getNavigationGraph();
NavigationConfig config = NavigationConfig.builder()
.maxDistance(50.0f)
.canSwim(true)
.build();
List<Vector3d> path = navGraph.findPath(
npc.getPosition(),
targetPosition,
config
);
if (path != null && !path.isEmpty()) {
npc.getPathFollower().setPath(path);
}
```
## Comportements de Mouvement
Comportements de mouvement pré-construits pour les patterns courants.
### WanderBehavior
```java
public class WanderBehavior {
private float wanderRadius;
private float minPauseDuration;
private float maxPauseDuration;
public WanderBehavior(float radius) {
this.wanderRadius = radius;
}
public void update(NPCEntity npc, float deltaTime) {
if (!npc.getMotionController().isMoving()) {
Vector3d wanderTarget = calculateWanderTarget(npc);
npc.getMotionController().moveTo(wanderTarget);
}
}
}
```
### FollowBehavior
```java
public class FollowBehavior {
private Entity target;
private float followDistance;
private float catchUpDistance;
public void update(NPCEntity npc, float deltaTime) {
float distance = npc.getPosition().distance(target.getPosition());
if (distance > catchUpDistance) {
npc.getMotionController().run();
} else if (distance > followDistance) {
npc.getMotionController().walk();
npc.getMotionController().moveTo(target.getPosition());
} else {
npc.getMotionController().stop();
}
}
}
```
### PatrolBehavior
```java
public class PatrolBehavior {
private List<Vector3d> patrolPoints;
private int currentPointIndex;
private boolean loop;
private float waitTimeAtPoint;
public void update(NPCEntity npc, float deltaTime) {
Vector3d currentTarget = patrolPoints.get(currentPointIndex);
MotionController motion = npc.getMotionController();
if (motion.hasReachedTarget()) {
// Attendre au point
currentPointIndex = (currentPointIndex + 1) % patrolPoints.size();
} else {
motion.moveTo(currentTarget);
}
}
}
```
### FleeBehavior
```java
public class FleeBehavior {
private float fleeDistance;
private Entity threat;
public void update(NPCEntity npc, float deltaTime) {
Vector3d awayFromThreat = npc.getPosition()
.subtract(threat.getPosition())
.normalize()
.multiply(fleeDistance);
Vector3d fleeTarget = npc.getPosition().add(awayFromThreat);
npc.getMotionController().sprint();
npc.getMotionController().moveTo(fleeTarget);
}
}
```
## Évitement d'Obstacles
```java
public class ObstacleAvoidance {
private float avoidanceRadius;
private float lookAheadDistance;
public Vector3d calculateAvoidanceVector(
NPCEntity npc,
Vector3d desiredDirection
) {
// Lancer des rayons pour détecter les obstacles
List<RaycastHit> obstacles = castAvoidanceRays(npc, desiredDirection);
if (obstacles.isEmpty()) {
return desiredDirection;
}
// Calculer la direction d'évitement
Vector3d avoidance = Vector3d.ZERO;
for (RaycastHit hit : obstacles) {
Vector3d away = npc.getPosition().subtract(hit.position).normalize();
avoidance = avoidance.add(away);
}
return desiredDirection.add(avoidance.normalize()).normalize();
}
}
```
## Systèmes de Mouvement
Systèmes ECS qui traitent le mouvement des NPCs :
```java
// Système de mise à jour de mouvement
public class NPCMovementSystem implements System {
@Override
public void update(float deltaTime) {
for (NPCEntity npc : npcsWithMovement) {
MotionController motion = npc.getMotionController();
PathFollower path = npc.getPathFollower();
// Mettre à jour le suivi de chemin
if (path.hasPath()) {
updatePathFollowing(npc, motion, path, deltaTime);
}
// Appliquer le mouvement
motion.update(deltaTime);
}
}
}
```
## Bonnes Pratiques
{{< callout type="info" >}}
**Directives de Mouvement :**
- Utilisez un NavigationConfig approprié au type de NPC
- Mettez en cache les chemins quand possible pour éviter les recalculs fréquents
- Utilisez le lissage de chemin pour un mouvement plus naturel
- Considérez la taille de l'entité lors du pathfinding
- Implémentez l'évitement d'obstacles pour les environnements dynamiques
{{< /callout >}}
{{< callout type="warning" >}}
**Performance du Pathfinding :**
- Limitez les requêtes de pathfinding par frame
- Utilisez des distances max plus courtes quand possible
- Mettez en cache les chemins fréquemment utilisés
- Considérez le pathfinding hiérarchique pour les grands mondes
{{< /callout >}}