Le framework de combat détaillé ici implémente un système de combat fluide de type « Free-Flow Combat », similaire aux mécaniques rencontrées dans des jeux d'action célèbres. Il fournit non seulement des fonctionnalités de base comme les attaques et les combos, mais intègre également des mécanismes avancés tels que la parry, les ripostes synchronisées et une IA tactique pour les ennemis. L'objectif est de proposer une solution modulaire et performante pour construire des expériences de combat engageantes dans Unity.
Architecture en couches
La conception repose sur une séparation des responsabilités en trois niveaux principaux : une couche d'animation pilotant le comportement, une couche logique gérant l'état du combat, et une couche décisionnelle pour l'IA des adversaires.
Couche pilotée par l'animation
Le système privilégie une approche où l'animation déclenche et guide la logique. Le flux typique pour une attaque est le suivant : une entrée utilisateur déclenche le changement vers l'état Attacking, l'animation correspondante est lancée. Des marqueurs temporels (ou Animation Events) dans cette animation contrôlent le moment d'activation de la hitbox pour le calcul des dégâts et ouvrent la fenêtre pour enchaîner dans un combo. Cette synchronisation étroite entre visuel et gameplay garantit une sensation de fluidité.
Combo Editor et structure de données
Les séquences de combos sont gérées via un éditeur visuel basé sur un graphe. Chaque nœud d'attaque, stocké comme un ScriptableObject, contient les données essentielles : l'animation à jouer, la liste des attaques pouvant en découler, les timings critiques, les courbes de déplacement et les coûts en énergie. Le mécanisme de suivi est un graphe orienté où la transition vers l'attaque suivante est conditionnée par la saisie du joueur dans une fenêtre temporelle valide.
Alignement dynamique avec Motion Warping
Pour éviter les attaques « vides » lorsque l'ennemi est légèrement hors de portée, le système applique une correction dynamique de la position du personnage pendant l'animation.
À l'initiation d'une attaque, la position cible et le point d'impact prévu sont enregistrés. Le décalage nécessaire est calculé :
Vector3 correction = positionEnnemi - positionImpactPrevue;
Cette correction est ensuite appliquée progressivement via le Root Motion ou en ajustant le vecteur de mouvement du CharacterController, principalement sur la première moitié de l'attaque pour un résultat naturel.
Systèmes de défense : Garde et Parry
Ces systèmes fonctionnent sur des fenêtres de timing précises.
Garde : Lorsque le joueur est en état de garde et subit un coup, les dégâts sont réduits via un multiplicateur.
if (etatPersonnage == Etat.Garde) {
degatsRecus *= multiplicateurDefense;
}
Parry : La fenêtre de succès est plus réduite. Si le joueur déclenche la parade dans le laps de temps imparti après l'initiation de l'attaque ennemie, une riposte est enclenchée.
if (inputParadeDetecte && tempsEcouleDepuisAttaque < fenetreParade) {
ActiverRiposte();
}
Ripostes et exécutions synchronisées
Les ripostes et les anmiations d'exécution nécessitent une synchronisation parfaite entre deux personnages. Cela est souvent réalisé en définissant un point d'ancrage (« Execution Anchor ») sur la cible. L'attaquant se déplace vers cet ancrage, le défenseur entre dans un état contrôlé, et les deux animations sont jouées de manière synchronisée. Pendant ce processus, les collisions physiques et les contrôles de l'IA sont généralement temporairement désactivés.
IA Tactique des ennemis
Pour éviter le chaos des attaques multiples simultanées, l'IA utilise un système de « slots d'attaque » autour du joueur. Les ennemis circulent en arc de cercle (souvent via NavMeshAgent) et se mettent en file d'attente pour un slot libre avant de pouvoir initier une offensive, garantissant ainsi un rythme de combat lisible.
Sélection adaptative des actions
Les choix d'attaques de l'IA ne sont pas aléatoires. Ils sont conditionnés par une série de critères tels que la distance, le niveau de santé de la cible, ou si elle est en l'air. Cette logique peut être implémentée via un système de priorité ou un arbre de comportements (« Behavior Tree ») qui évalue les conditions et sélectionne l'action la plus appropriée.
Intégration modulaire
Le framework est conçu pour être découplé via des interfaces. Par exemple, un système de dommage pourrait dépendre de IReceiveDamage, tandis que le contrôle du mouvement passerait par IMovementProvider. Cette approche permet de remplacer facilement des modules entiers (comme le système de déplacement) ou d'intégrer d'autres fonctionnalités comme un inventaire ou un système de tir, sans modifier le cœur du système de combat.
Optimisation des performances
Pour des scènes avec de nombreux combattants, des stratégies sont nécessaires : réduire la fréquence de mise à jour de l'IA pour les ennemis éloignés, utiliser un pool d'objets pour les effets visuels, et optimiser les contrôleurs d'animation via une hiérarchie de couches. L'implémentation du Motion Warping doit être surveillée pour éviter des calculs de position trop fréquents.