Spaces:
Sleeping
🎮 HARVESTER MANUAL CONTROL FIX - Contrôle Manuel vs IA Automatique
Date: 3 Octobre 2025
Problème rapporté: "Havester à sa sortie de HQ reste immobile, et ne reçoit pas l'ordre du joueur de se déplacer"
Status: ✅ CORRIGÉ
🐛 NOUVEAU PROBLÈME IDENTIFIÉ
Symptômes
Après la première correction de l'IA automatique, un nouveau problème est apparu :
- ✅ L'IA automatique fonctionne (Harvester cherche ressources)
- ❌ MAIS le joueur ne peut plus donner d'ordres manuels !
- ❌ Quand le joueur clique pour déplacer le Harvester, il ignore la commande
- ❌ Le Harvester continue de suivre l'IA automatique même si ordre manuel donné
Comportement observé
1. Joueur produit Harvester depuis HQ
2. Harvester commence à chercher minerai automatiquement ✓
3. Joueur clique pour déplacer Harvester manuellement
4. Harvester ignore et continue vers minerai automatiquement ✗
🔍 CAUSE RACINE
Ordre d'exécution dans la game loop
Chaque tick (20x par seconde) :
1. handle_command() - Traite commandes joueur
├─ Reçoit "move_unit" du joueur
└─ Définit unit.target = (clic joueur) ✓
2. update_game_state() - Mise à jour simulation
├─ update_harvester() appelé pour chaque Harvester
└─ ÉCRASE unit.target avec l'IA automatique ✗
Problème de conflit
Séquence du bug :
Tick N:
├─ [WebSocket] Joueur envoie: move_unit(x=800, y=600)
├─ [handle_command] unit.target = Position(800, 600) ✓
│
├─ [update_game_state] update_harvester() appelé
├─ [update_harvester] Condition: not gathering and not ore_target
├─ [update_harvester] find_nearest_ore() trouve minerai à (1200, 800)
├─ [update_harvester] unit.target = Position(1200, 800) ✗ [ÉCRASE!]
│
└─ Résultat: Harvester va vers (1200, 800) au lieu de (800, 600)
Le problème : L'IA automatique s'exécute APRÈS les commandes du joueur et écrase le target manuel !
✅ SOLUTION IMPLÉMENTÉE
Approche : Flag de contrôle manuel
Ajout d'un nouveau champ manual_control à la classe Unit pour distinguer :
- manual_control = False : IA automatique active (comportement par défaut)
- manual_control = True : Joueur contrôle manuellement (IA désactivée temporairement)
Architecture de la solution
┌─────────────────────────────────────────────────────────────┐
│ Unit Dataclass │
├─────────────────────────────────────────────────────────────┤
│ EXISTING FIELDS: │
│ ├─ cargo: int │
│ ├─ gathering: bool │
│ ├─ returning: bool │
│ ├─ ore_target: Optional[Position] │
│ └─ last_attacker_id: Optional[str] │
│ │
│ NEW FIELD: │
│ └─ manual_control: bool = False ← AJOUTÉ │
│ │
│ Purpose: Track when player takes manual control │
└─────────────────────────────────────────────────────────────┘
Logique de commutation
┌───────────────────────────────────────────────────────────────────┐
│ État du Harvester │
├───────────────────────────────────────────────────────────────────┤
│ │
│ MODE AUTOMATIQUE (manual_control = False) │
│ ├─ IA active │
│ ├─ update_harvester() exécuté chaque tick │
│ ├─ Cherche minerai automatiquement │
│ ├─ Récolte automatiquement │
│ └─ Cycle complet géré par IA │
│ │
│ ↓ Joueur donne ordre "move_unit" │
│ │
│ MODE MANUEL (manual_control = True) │
│ ├─ IA désactivée │
│ ├─ update_harvester() SKIPPED │
│ ├─ Harvester obéit aux ordres du joueur │
│ ├─ gathering/returning/ore_target nettoyés │
│ └─ Se déplace vers target défini par joueur │
│ │
│ ↓ Harvester arrive à destination OU dépose cargo │
│ │
│ MODE AUTOMATIQUE (manual_control = False) │
│ └─ Reprend IA automatique │
│ │
└───────────────────────────────────────────────────────────────────┘
🔧 CHANGEMENTS DE CODE
1. Ajout du champ manual_control (Ligne 130)
AVANT :
@dataclass
class Unit:
cargo: int = 0
gathering: bool = False
returning: bool = False
ore_target: Optional[Position] = None
last_attacker_id: Optional[str] = None
APRÈS :
@dataclass
class Unit:
cargo: int = 0
gathering: bool = False
returning: bool = False
ore_target: Optional[Position] = None
last_attacker_id: Optional[str] = None
manual_control: bool = False # True when player gives manual orders
2. Sérialisation JSON (Ligne 148)
AVANT :
"cargo": self.cargo,
"gathering": self.gathering,
"returning": self.returning
APRÈS :
"cargo": self.cargo,
"gathering": self.gathering,
"returning": self.returning,
"manual_control": self.manual_control
3. Skip IA si contrôle manuel (Ligne 427)
AVANT :
# Update units
for unit in list(self.game_state.units.values()):
# RED ALERT: Harvester AI
if unit.type == UnitType.HARVESTER:
self.update_harvester(unit)
continue
APRÈS :
# Update units
for unit in list(self.game_state.units.values()):
# RED ALERT: Harvester AI (only if not manually controlled)
if unit.type == UnitType.HARVESTER and not unit.manual_control:
self.update_harvester(unit)
continue
Effet : Si manual_control = True, update_harvester() n'est pas appelé → IA désactivée
4. Activer contrôle manuel sur ordre joueur (Ligne 633)
AVANT :
if cmd_type == "move_unit":
unit_ids = command.get("unit_ids", [])
target = command.get("target")
if target and "x" in target and "y" in target:
for uid in unit_ids:
if uid in self.game_state.units:
self.game_state.units[uid].target = Position(target["x"], target["y"])
APRÈS :
if cmd_type == "move_unit":
unit_ids = command.get("unit_ids", [])
target = command.get("target")
if target and "x" in target and "y" in target:
for uid in unit_ids:
if uid in self.game_state.units:
unit = self.game_state.units[uid]
unit.target = Position(target["x"], target["y"])
# If it's a Harvester, enable manual control to override AI
if unit.type == UnitType.HARVESTER:
unit.manual_control = True
# Clear AI state
unit.gathering = False
unit.returning = False
unit.ore_target = None
Effet :
- Active
manual_control = Truepour les Harvesters - Nettoie les états de l'IA (
gathering,returning,ore_target) - Le Harvester obéit maintenant à l'ordre manuel
5. Reprendre IA quand destination atteinte (Ligne 483)
AVANT :
# Movement
if unit.target:
# Move towards target
dx = unit.target.x - unit.position.x
dy = unit.target.y - unit.position.y
dist = (dx*dx + dy*dy) ** 0.5
if dist > 5:
unit.position.x += (dx / dist) * unit.speed
unit.position.y += (dy / dist) * unit.speed
else:
unit.target = None
APRÈS :
# Movement
if unit.target:
# Move towards target
dx = unit.target.x - unit.position.x
dy = unit.target.y - unit.position.y
dist = (dx*dx + dy*dy) ** 0.5
if dist > 5:
unit.position.x += (dx / dist) * unit.speed
unit.position.y += (dy / dist) * unit.speed
else:
unit.target = None
# If Harvester reached manual destination, resume AI
if unit.type == UnitType.HARVESTER and unit.manual_control:
unit.manual_control = False
Effet : Quand le Harvester arrive à la destination manuelle, manual_control = False → reprend IA automatique
6. Reprendre IA après dépôt (Ligne 529)
AVANT :
if distance < TILE_SIZE * 2:
# Deposit cargo
self.game_state.players[unit.player_id].credits += unit.cargo
unit.cargo = 0
unit.returning = False
unit.gathering = False
unit.ore_target = None
unit.target = None # Clear target after deposit
APRÈS :
if distance < TILE_SIZE * 2:
# Deposit cargo
self.game_state.players[unit.player_id].credits += unit.cargo
unit.cargo = 0
unit.returning = False
unit.gathering = False
unit.ore_target = None
unit.target = None # Clear target after deposit
unit.manual_control = False # Resume AI after deposit
Effet : Après dépôt de cargo, reprend IA automatique (même si était en mode manuel)
🔄 NOUVEAU COMPORTEMENT
Scénario 1 : IA Automatique (défaut)
1. Harvester spawn depuis HQ
└─ manual_control = False ✓
2. Chaque tick:
├─ update_harvester() exécuté ✓
├─ Cherche minerai automatiquement
├─ Récolte automatiquement
└─ Cycle automatique complet ✓
Scénario 2 : Contrôle manuel par le joueur
1. Joueur clique pour déplacer Harvester vers (800, 600)
├─ handle_command("move_unit")
├─ unit.target = (800, 600)
├─ unit.manual_control = True ✓
└─ gathering/returning/ore_target nettoyés
2. Chaque tick:
├─ Condition: unit.type == HARVESTER and not manual_control
├─ False (manual_control = True)
└─ update_harvester() SKIPPED ✓
3. Harvester se déplace vers (800, 600)
└─ Code de mouvement normal (lignes 470-486)
4. Harvester arrive à destination:
├─ dist < 5
├─ unit.target = None
└─ unit.manual_control = False ✓ [REPREND IA!]
5. Tick suivant:
└─ update_harvester() exécuté de nouveau (IA reprend) ✓
Scénario 3 : Contrôle manuel puis dépôt
1. Joueur déplace Harvester manuellement près d'un patch ORE
└─ manual_control = True
2. Harvester arrive à destination
└─ manual_control = False (reprend IA)
3. IA détecte minerai proche
├─ ore_target = (1200, 800)
├─ gathering = True
└─ Commence récolte automatique ✓
4. Cargo plein, retourne au dépôt automatiquement
└─ returning = True
5. Dépose au HQ
├─ credits += cargo
├─ cargo = 0
└─ manual_control = False (confirmé) ✓
6. Reprend cycle automatique
└─ Cherche nouveau minerai ✓
📊 TABLEAU COMPARATIF
| Situation | AVANT (Bugué) | APRÈS (Corrigé) |
|---|---|---|
| Spawn du HQ | IA fonctionne ✓ | IA fonctionne ✓ |
| Ordre manuel du joueur | ❌ Ignoré (IA écrase) | ✅ Obéit (IA désactivée) |
| Arrivée à destination manuelle | N/A | ✅ Reprend IA automatique |
| Dépôt de cargo | ✅ Reprend IA | ✅ Reprend IA (forcé) |
| Récolte automatique | ✅ Fonctionne | ✅ Fonctionne |
| Cycle complet | ❌ Pas de contrôle manuel | ✅ Manuel ET automatique |
🎯 RÉSULTATS
Comportement attendu (Red Alert classique)
✅ IA Automatique par défaut
- Harvester cherche et récolte ressources automatiquement
- Cycle complet sans intervention du joueur
✅ Contrôle manuel optionnel
- Joueur peut donner ordres manuels (clic droit pour déplacer)
- Harvester obéit immédiatement aux ordres manuels
- IA se désactive temporairement
✅ Retour automatique à l'IA
- Après avoir atteint destination manuelle
- Après avoir déposé cargo
- Le joueur n'a pas besoin de réactiver l'IA
Flexibilité
Le joueur peut maintenant :
- Laisser l'IA gérer (défaut) - Harvester autonome
- Prendre le contrôle - Déplacer manuellement vers un patch spécifique
- Mélanger les deux - Ordres manuels ponctuels, IA reprend après
🧪 TESTS
Test 1 : IA automatique
1. Produire Harvester depuis HQ
2. Observer: Harvester cherche minerai automatiquement ✓
3. Observer: Récolte et dépose automatiquement ✓
Test 2 : Contrôle manuel
1. Produire Harvester
2. Attendre qu'il commence à bouger (IA)
3. Cliquer pour le déplacer ailleurs
4. Observer: Harvester obéit immédiatement ✓
5. Observer: Arrive à destination
6. Observer: Reprend IA automatique ✓
Test 3 : Mélange manuel/automatique
1. Produire Harvester
2. Déplacer manuellement près d'un patch GEM (valeur +100)
3. Attendre arrivée à destination
4. Observer: IA reprend et récolte le GEM proche ✓
5. Observer: Retourne au dépôt automatiquement ✓
6. Observer: Recommence cycle automatique ✓
🐛 DEBUGGING
Si le Harvester ne répond toujours pas aux ordres manuels :
1. Vérifier WebSocket
# Dans handle_command() ligne 633
print(f"[CMD] move_unit: unit_ids={unit_ids}, target={target}")
2. Vérifier manual_control activé
# Après unit.manual_control = True ligne 641
print(f"[Harvester {unit.id[:8]}] manual_control=True, target={unit.target}")
3. Vérifier update_harvester() skipped
# Dans update_game_state() ligne 427
if unit.type == UnitType.HARVESTER:
if unit.manual_control:
print(f"[Harvester {unit.id[:8]}] SKIPPING update_harvester (manual control)")
else:
print(f"[Harvester {unit.id[:8]}] Running update_harvester (AI)")
4. Vérifier reprise de l'IA
# Dans mouvement ligne 486
if unit.type == UnitType.HARVESTER and unit.manual_control:
print(f"[Harvester {unit.id[:8]}] Reached destination, resuming AI")
unit.manual_control = False
📖 DOCUMENTATION
Fichiers modifiés
/home/luigi/rts/web/app.py- Ligne 130: Ajout champ
manual_control - Ligne 148: Sérialisation
manual_control - Ligne 427: Skip IA si
manual_control = True - Ligne 633-642: Activer
manual_controlsur ordre joueur - Ligne 486: Reprendre IA quand destination atteinte
- Ligne 532: Reprendre IA après dépôt
- Ligne 130: Ajout champ
Fichiers créés
/home/luigi/rts/web/HARVESTER_MANUAL_CONTROL_FIX.md(ce document)
✅ CONCLUSION
Problème 1: Harvester ne cherchait pas ressources automatiquement
Solution 1: Correction condition not ore_target au lieu de not target
Résultat 1: ✅ IA automatique fonctionne
Problème 2: Harvester ignorait ordres manuels du joueur
Solution 2: Flag manual_control pour désactiver temporairement IA
Résultat 2: ✅ Contrôle manuel fonctionne
Résultat final: 🎮 Harvester fonctionne exactement comme Red Alert !
- ✅ IA automatique par défaut
- ✅ Contrôle manuel optionnel
- ✅ Retour automatique à l'IA
- ✅ Flexibilité totale pour le joueur
Date: 3 Octobre 2025
Status: ✅ CORRIGÉ ET TESTÉ
Version: 2.0 (IA automatique + contrôle manuel)