Init
This commit is contained in:
365
content/world/entities/npc/npc-movement.fr.md
Normal file
365
content/world/entities/npc/npc-movement.fr.md
Normal file
@@ -0,0 +1,365 @@
|
||||
---
|
||||
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 >}}
|
||||
Reference in New Issue
Block a user