4.9 KiB
Chessistics
Jeu de logistique sur echiquier en Godot 4 / C#. Le joueur place des pieces d'echecs sur un plateau ; elles se deplacent automatiquement et transportent des ressources entre des productions et des demandes.
Architecture : Black-Box Simulation
Ref: https://samuel-bouchet.fr/posts/2026-04-08-black-box-sim/
Le moteur de jeu (chessistics-engine/) est une boite noire sans aucune dependance vers Godot. Il recoit des Commands, mute son etat interne, et retourne des Events. Le code Godot (Scripts/) ne fait que traduire l'input en commands et les events en visuels/animations.
Input → Command → GameSim (state + rules) → Events → Presentation
- Commands (
PlacePieceCommand,StartSimulationCommand, …) : seul moyen de modifier l'etat. - Events (
PiecePlacedEvent,CargoDeliveredEvent, …) : seul output du moteur. Le presenteur les consomme pour animer. - GameSim : point d'entree unique.
ProcessCommand()retourne la liste d'events. - Tests :
chessistics-tests/teste le moteur en headless, sans Godot.
Pieges Godot a eviter
MouseFilter sur les Controls enfants de Node2D
Tout Control (ColorRect, Label…) a MouseFilter = Stop par defaut. Quand un Control est enfant d'un Node2D (ex: les ColorRect dans CellView, les Labels dans PieceView), il participe quand meme au systeme GUI et consomme les clics, empechant _UnhandledInput de recevoir l'evenement.
Regle : toujours mettre MouseFilter = Control.MouseFilterEnum.Ignore sur les Controls purement visuels enfants de Node2D.
Conventions Claude
Plans
Les fichiers de plan doivent etre rediges a la racine du workspace (ex: /workspace/PLAN_juice.md), pas dans .claude/plans/ car ce dossier a une taille limitee.
Harnais d'automatisation (Claude peut jouer tout seul)
Le jeu peut etre pilote de maniere autonome via le flag --automation=<dir>. Un
AutomationHarness (Scripts/Automation/) s'active alors comme noeud au root de la
scene, lit des commandes JSON dans <dir>/inbox/, ecrit les resultats dans
<dir>/outbox/, et place les captures d'ecran dans <dir>/screens/. Sans le flag,
comportement normal — overhead zero.
Cote agent, un wrapper Python stdlib (tools/automation/harness.py) expose une API
simple. Godot attendu a C:\Apps\godot\Godot_v4.6.2-stable_mono_win64_console.exe.
Build + utilisation
dotnet build Chessistics.csproj # compiler avant tout lancement
python tools/automation/smoke.py # smoke test end-to-end
python tools/automation/run_game.py # REPL interactif
API Python
from tools.automation.harness import Harness
with Harness.launch() as h:
h.load_mission("campaign_01", 0) # charge la campagne + mission 0
state = h.state() # snapshot complet (dict)
h.screenshot("before") # -> .automation_runs/<ts>/screens/before.png
h.place("Pawn", (0, 0), (0, 1)) # pose une piece
h.step() # un tour (auto-wait animation)
h.screenshot("after")
h.set_speed(0.1); h.play() # auto-play rapide
Methodes : screenshot, state, select, place, click_cell, key, play,
pause, step, wait_idle, set_speed, load_mission, back_to_menu, quit.
Toutes les commandes non-query attendent EventAnimator.IsAnimating == false avant
de retourner -> appels en serie toujours vus par le prochain state().
Validation visuelle par Claude
Les PNG 1280x720 ecrites dans .automation_runs/<run>/screens/ peuvent etre lues
directement par l'outil Read de Claude. Workflow type pour valider l'UI :
h.load_mission("campaign_01", N)+h.screenshot("mission_N_start")- Lire le PNG -> verifier titre, flavor banner, board, panneau objectifs, stock
- Placer des pieces via
h.place(...)et re-screenshot h.step()en boucle + screenshot a chaque etape- Attendre
phase == "MissionComplete"dans le snapshot
Cette boucle permet de valider que :
- Les demandes affichent les bons compteurs
- Les pieces bougent comme prevu
- Le stock se met a jour
- L'ecran
MissionCompleteapparait quand attendu
Details importants
Placepasse par le signalPlacementRequested(meme chemin qu'un vrai clic) -- ne pas appelerGameSim.ProcessCommand(PlacePieceCommand)directement dans le dispatcher, ca mute deux fois.- Les captures d'ecran sont prises apres
RenderingServer.frame_post_draw-> le frame reflete l'etat final, animations incluses. - La facade (
AutomationFacade) est la seule surface exposee au dispatcher. Elle ne touche que des methodes/signals publics deGameSim,InputMapper,EventAnimator,ControlBar,PieceStockPanel. La separation black-box tient. - Les fichiers IPC sont ecrits
.tmppuis renommes (atomique sur Windows). - La campagne se charge via
load_mission("campaign_01", 0). Passer a une mission0 n'est pas supporte directement (il faut passer par
MissionCompletereel).