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

9.2 KiB

title, type, weight
title type weight
Mouvement NPC docs 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

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

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

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

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

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

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

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

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

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

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

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

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

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 :

// 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 >}}