ai-duel
Petit plugin Bevy pour monter rapidement un duel joueur contre IA : santé, factions, hitbox d'attaque, et une IA basique qui fonce sur le joueur et tape quand elle est à portée.
Fait à la base pour un prototype perso, mis en crate séparée parce qu'elle est réutilisée d'un projet à l'autre.
Ce que ça fait
-
Un combattant a une vie, une faction (
Player/Enemy), une anim de course et une anim d'attaque. -
L'IA (
AiController) avance vers le joueur, s'arrête à une distance donnée, et déclenche une attaque quand elle est assez proche. -
L'attaque active une hitbox pendant quelques frames de l'anim (réglable), qui inflige des dégâts au premier combattant de faction adverse qu'elle touche.
-
Petite invulnérabilité + flash rouge après chaque coup encaissé, pour éviter de perdre toute sa vie en une seule frame de contact.
-
Le combattant à 0 PV est despawn.
Ce que ça ne fait pas / limites
-
Pas de chargement d'assets : la ressource
FighterAssetsdoit être construite par l'utilisateur avec ses propres spritesheets. -
Pas d'input clavier : il faut brancher un système qui appelle
start_attack()(ou qui bouge leTransformdu joueur) voir plus bas. -
Pas d'anim d'idle séparée, pas d'anim de mort, pas de pathfinding l'IA va en ligne droite vers le joueur, rien de plus.
-
Collisions en O(n) : chaque hitbox active est comparée à tous les combattants adverses, sans structure d'accélération. Largement suffisant pour un duel 1v1 ou quelques ennemis, pas pensé pour une horde.
-
Une seule hitbox par combattant, créée à la construction et jamais redimensionnée dynamiquement (pas d'attaques avec des portées différentes sur un même personnage, par exemple).
-
Un seul joueur supporté :
ai_behaviorprend le premier (et seul) combattant marquéPlayerviaQuery::single. Avec plusieurs joueurs sur la carte, le système paniquera ou ignorera la requête selon la version de Bevy. -
Pas de réseau / multijoueur, tout est local et synchrone.
Choix de conception
Quelques décisions volontaires, pour éviter les mauvaises surprises :
-
États figés (
Running/Attacking) plutôt qu'une machine à états générique. Un duel simple n'a besoin que de deux états ; ajouter un système de state machine générique aurait complexifié le code pour un gain nul à cette échelle. -
Hitbox en entité enfant plutôt qu'un champ sur le combattant. Profiter du
GlobalTransformhérité du parent évite de recalculer la position de la hitbox à la main à chaque frame. -
Fenêtre de frames actives (
hitbox_active_from/_to) plutôt qu'une hitbox active sur toute la durée de l'attaque. Sans ça, un coup ferait mal dès la toute première frame de l'anim, avant même que le sprite ait commencé à bouger le bras. -
Systèmes chaînés (
.chain()) plutôt qu'en parallèle. L'ordre IA → anim → hitbox → collisions → dégâts → mort dépend directement du résultat de l'étape précédente ; les paralléliser introduirait des incohérences d'une frame à l'autre. -
Tout est public dans
systems. Cela permet de réordonnancer ou de remplacer un système individuel depuis l'application hôte sans devoir forker la crate.
Installation
[]
= "0.1"
= "0.19"
Utilisation
use *;
use ;
Les spritesheets sont attendues sous forme d'une seule ligne de frames
(course et attaque dans deux images séparées). Il suffit d'adapter
TextureAtlasLayout si le format utilisé est différent.
Configurer le comportement
Tous les réglages (dégâts, cooldowns, vitesse d'anim, taille de la
hitbox...) sont dans AiDuelConfig. Le plugin insère une config par
défaut ; il suffit de la remplacer après l'avoir ajoutée pour changer un
réglage :
new
.add_plugins
.insert_resource
.run;
Contrôler le joueur
Le plugin ne touche pas au Transform d'une entité marquée Player en
dehors des collisions. Un système minimal pour le déplacement et
l'attaque :
À ajouter dans Update, avant les systèmes du plugin si l'attaque du
joueur doit être prise en compte dès la même frame.
Licence
GPL-2.0-or-later, voir le fichier Cargo.toml.