GoKart : un jeu de course façon Mario Kart qu'Auto-Pilot a construit en un après-midi
Donnez à l'Auto-Pilot d'Agent! un seul objectif - « crée un clone de Mario Kart appelé GoKart » - et revenez devant un jeu de course Godot 4 avec trois circuits, huit objets, des rivaux pilotés par l'IA et 3 344 vérifications de test au vert. Deux jours et 87 commits de l'agent plus tard, c'est GoKart 0.0.2, avec quatre circuits, un mode Bataille, des Contre-la-montre et un menu façon Mario Kart 64. Voici ce que le journal dit qu'il s'est réellement passé, y compris les moments où il s'est retrouvé bloqué.
Mis à jour le 4 octobre : l'article suit désormais l'histoire pendant les deux jours qui ont suivi ce premier après-midi, y compris la soirée où deux sessions Auto-Pilot ont partagé un même dépôt, et se termine par la version GoKart 0.0.2. Les captures d'écran ont été refaites à partir du tag 0.0.2.
L'article d'hier présentait Auto-Pilot : tapez /auto <objectif> dans Agent! pour Mac et il enchaîne des cycles sans surveillance vers cet objectif jusqu'à ce que vous appuyiez sur Stop All. Cet article raconte ce qui est sorti de l'autre côté quand je l'ai pointé vers un jeu.
L'objectif, collé plus ou moins tel que je l'ai tapé :
create a Mario Kart clone called GoKart with all Mario Kart effects. I believe Godot 4 can do the Mario Kart effects, but I haven't built any of them yet: drift sparks and boost flames (GPUParticles3D), speed lines and boost blur (screen-space shaders, glow and tonemapping), item effects and tire trails (shaders plus ribbon meshes), kart movement (VehicleBody3D or custom arcade physics). Write unit tests and test the game frequently.
Budget : pas de limite de temps, cycles illimités. Le modèle utilisé dans Agent! pour chaque cycle était Claude Sonnet 5.5. Le premier commit est arrivé à 12 h 39. À 16 h 32 le même après-midi, le dépôt comptait 33 commits, 47 fichiers GDScript, environ 5 500 lignes de GDScript et de code de shaders, et une suite unitaire qui passait 3 344 vérifications. Deux jours plus tard, au tag 0.0.2, ces chiffres étaient passés à 126 commits, 150 fichiers, environ 24 500 lignes et 14 134 vérifications. Chacun de ces commits est signé par l'agent. Le tout est sur GitHub : AgentiLoop/GoKart.
Ce que fait Auto-Pilot, un cycle à la fois
Auto-Pilot tient un journal continu dans .agent/autopilot/progress.md à l'intérieur du projet, et chaque cycle y ajoute ce qu'il a fait, ce qu'il a supposé, ce qui reste et si quelque chose l'a bloqué. Ce journal est la source de tout ce qui suit. Je le cite plutôt que ma mémoire parce que le journal est plus honnête que moi.
Le cycle 1 n'avait pas Godot sur la machine. Il a lancé brew install --cask godot, créé un lien symbolique vers le binaire, fait git init, et écrit kart_physics.gd comme un modèle pur sans dépendance à une scène : accélération, freinage, marche arrière, friction, direction, un drift verrouillé dans la direction où vous l'avez commencé, et trois niveaux de mini-turbo. Il a délibérément choisi une physique arcade maison plutôt que VehicleBody3D, et a dit pourquoi : « pour que le comportement façon Mario Kart soit facile à tester unitairement ». Onze tests, 17 vérifications, premier commit.
Le cycle 2 a ajouté les effets que j'avais demandés nommément : des étincelles de drift en GPUParticles3D colorées selon le niveau de mini-turbo, des flammes d'échappement, des traces de pneus en ruban de mesh, et un shader en espace écran pour le flou radial du boost, les lignes de vitesse et un vignettage. 43 vérifications.
Le cycle 3 a construit un circuit. Une boucle Catmull-Rom rééchantillonnée tous les 3 mètres, un ruban de route, des murs rayés rouge et blanc avec colliders, des plaques de boost avec un shader de chevrons défilants, huit checkpoints ordonnés et un compteur de tours qui refuse de compter les raccourcis ou les tours à contresens. L'un des nouveaux tests est un bot de poursuite qui boucle trois tours complets avec le vrai modèle physique. Il a terminé en 1:02.5. 90 vérifications.
Le cycle 4 a ajouté des boîtes à objets avec un shader fresnel arc-en-ciel, une roulette, et les trois premiers objets : champignon, banane et une carapace verte qui ricoche sur les murs. Se faire toucher fait partir le kart en tête-à-queue pendant 1,2 seconde. 235 vérifications.
Puis il s'est retrouvé bloqué.
Le moment où il s'est retrouvé bloqué
Le cycle suivant a commencé à ajouter des karts IA et une course de fumée headless, et n'est jamais revenu. La cause, trouvée à la session suivante, était une seule tabulation égarée à la ligne 115 de main.gd : une erreur de parsing qui faisait cracher des erreurs au script de fumée sans fin, sans limite de temps sur la commande shell qui l'exécutait.
J'ai appuyé sur Stop All et ouvert une nouvelle session avec le même objectif plus une note en majuscules que je ne reproduirai pas intégralement. En substance : tu t'es retrouvé bloqué en testant la course de fumée, ne te bloque pas, mets une limite de temps sur le shell.
Le premier cycle de la deuxième session a corrigé la tabulation, réduit l'anticipation de l'IA de 10 échantillons de route à 6 pour que l'IA arrête de couper les virages dans le mur intérieur, ajouté un limiteur de vitesse en virage, et enveloppé chaque exécution shell dans perl -e 'alarm 100; exec @ARGV', parce que macOS est livré sans commande timeout. À partir de là, le journal dit « toutes les exécutions étaient derrière des limites perl alarm » à la fin de presque chaque cycle. Il a retenu la leçon du texte de l'objectif et a continué à l'appliquer.
Cette session a enchaîné 15 cycles en environ une heure et quart, et chacun est une fonctionnalité : compte à rebours de départ avec un boost de départ canon pour un accélérateur bien chronométré ; des pops de montée de niveau de mini-turbo et un flash en bord d'écran ; une mini-carte ; la carapace rouge à tête chercheuse et l'étoile ; un modèle de kart procédural avec des roues qui tournent, des roues avant qui braquent et un pilote dont la tête se tourne ; un éclair qui rétrécit tous les rivaux ; des triples carapaces qui orbitent autour du kart ; la carapace bleue à épines qui traque le leader le long de la route ; un écran de résultats avec des points ; un audio entièrement synthétisé sans fichier audio, de la boucle moteur au jingle d'arrivée ; un menu titre avec un deuxième circuit ; une option de nombre de tours ; un troisième circuit ; et un ronronnement moteur 3D positionnel sur chaque kart IA.
Le moment où il a été honnête
Ce que j'aime le plus dans le journal, c'est le motif des aveux. Agent! ne peut pas regarder un PNG, et il l'a dit, cycle après cycle :
L'exécution de capture en mode fenêtré n'a enregistré aucune erreur, mais je ne peux pas voir les images, donc je n'ai pas regardé comment le circuit ou le HUD s'affichent.
Je n'ai pas entendu les sons, et je n'ai pas lancé la course de fumée ni l'outil de capture.
Je ne peux pas voir les images avec mes outils, donc cette revue nécessite une personne.
Alors il a testé ce qu'il pouvait : des vérifications de scène headless qui instancient la vraie scène et font des assertions sur l'état. Lancer l'éclair, confirmer que trois rivaux sont à l'échelle 0,5 et en train de tourner, et que les éclairs sont nettoyés ensuite. Tirer une carapace bleue sur une grille de départ serrée, confirmer l'explosion à l'image 12 et deux karts en tête-à-queue. Forcer le joueur à finir, confirmer que le pilote automatique confie le kart à un AiDriver et que le panneau de résultats affiche « 1st YOU ».
Une troisième session a calé de la même manière, cette fois derrière une alarme de 240 secondes bien trop généreuse, et je l'ai arrêtée après un cycle. Puis une personne a regardé. Cette personne, c'était moi, et l'objectif de la quatrième session était mes notes de test, légèrement remises en ordre :
the UI needs to scale with the window. the UI should not be prone to the screen speed effects and blurry. Should be able to use cursor keys. it's not clear when power ups are released. the tops of the walls flicker. Little too hard to steer the kart. hard to keep up with the computer AI karts. maybe have AI difficulty levels Easy Medium and Hard.
Un cycle plus tard : un étirement canvas-items pour que l'UI suive la taille de la fenêtre, le HUD déplacé sur un calque canvas au-dessus de l'overlay d'effets de vitesse, les touches fléchées, Entrée et Ctrl pour les objets avec une indication à l'écran, une direction adoucie à l'entrée, une correction du z-fighting sur les rayures des murs (les segments rouges et blancs voisins se disputaient les mêmes pixels, alors les blancs ont été légèrement agrandis), du MSAA 4x, et Facile / Moyen / Difficile qui ramènent la vitesse maximale de l'IA à 0,72, 0,85 et 1,0. Les tests sont passés de 2 156 à 3 344 vérifications, en partie parce qu'il a aussi trouvé et corrigé une erreur de parsing préexistante dans tests/test_items.gd qui empêchait la suite de se charger.
Le moment où il s'est arrêté de lui-même
Les cycles 2 à 8 de cette dernière session n'ont fait aucune modification de code. Chacun a relu le dépôt, relancé la suite, et écrit une variante du même paragraphe :
Je n'ai pas pu voir le résultat à l'écran, donc je ne déclare pas l'objectif atteint. Quatre points ont encore besoin qu'un humain les essaie dans le jeu.
C'est le bon comportement. L'objectif était « la direction est désagréable » et « les murs scintillent », et aucun test headless ne peut clore cet objectif. Auto-Pilot n'a pas de plafond d'itérations, il aurait donc continué à vérifier indéfiniment. La session s'est terminée après le cycle 8, et ce dont GoKart avait besoin ensuite, c'était d'une partie de test, pas d'un cycle de plus. Ce soir-là, le dépôt a été tagué 0.0.1 et exporté pour macOS, Windows et Linux.
Deux jours plus tard : deux Auto-Pilots dans un même dépôt
Le 3 octobre, je suis revenu avec un objectif d'un autre genre. Cette fois, pas une liste de fonctionnalités, mais une référence :
keep building GoKart to resemble Mario Kart Nintendo 64 version. search Mario Kart N64 or Mario Kart Nintendo 64 and keep improving, iterating, making GoKart better
Cette cinquième session a démarré à 14 h 19 et a enchaîné 28 cycles, et presque chaque cycle est un élément de Mario Kart 64 que l'agent a cherché puis construit. La structure du jeu est venue d'abord : un plateau de 8 coureurs sur une grille à deux colonnes, l'élastique selon la difficulté, les classes 50cc, 100cc et 150cc plus la classe Extra en miroir, des karts Léger, Moyen et Lourd qui se bousculent, et un Grand Prix avec les points 9/6/3/1 et la règle d'élimination au classement. Puis les autres modes : les Contre-la-montre avec un fantôme, et le mode Bataille avec des ballons dans Big Donut, Block Fort et Skyscraper. Puis l'éventail d'objets s'est complété avec les triples champignons et le champignon doré, la fausse boîte à objets, le régime de bananes, Boo, les triples carapaces rouges et le blocage des carapaces, Lakitu arrivant pour signaler le faux départ, donner le signal de départ et brandir les panneaux de tour.
Le reste de l'après-midi est passé dans les circuits eux-mêmes. Un quatrième, Dusty Canyon, est arrivé avec un train façon Désert Kalimari et des passages à niveau. Sunset Speedway a reçu la circulation de l'Autoroute Toad. Frosty Peaks a reçu la glace de Sherbet Land, des bonshommes de neige et des pingouins, Green Hills a reçu des Topi Taupes, et chaque circuit a reçu des décors de bord de route assortis à son thème, ainsi que l'aspiration, un tremplin, le dérapage à sautillement et bascule, et une boucle chiptune rendue à partir de motifs de pas dans le code.
Quatre heures plus tard, à 18 h 25, j'ai ouvert un deuxième onglet et lancé un deuxième Auto-Pilot sur le même dépôt, avec un objectif plus étroit :
the menus are not Mario Kart Quality and neither is the title shot. and there is over use of black outlines on text everywhere. see Mario Kart 64 screenshots and images on the web and make better menus. focus only on the menus / screens and title shot for GoKart. make conscious decisions. do not conflict with previous /auto working on the application
Donc de 18 h 25 à minuit, deux agents committaient dans le même arbre de travail. La session menus a reconstruit l'écran titre autour d'un logo en arche dégradé qui arrive en volant et rebondit, puis a passé en revue chaque écran derrière lui : un écran de sélection avec une image à côté de chaque circuit et un survol en direct de celui que vous avez choisi, des lignes d'options avec des barres allumées, un portrait de kart qui tourne et un curseur doré, un survol d'introduction du circuit avant chaque course, un écran de pause, et un tableau de résultats dont les lignes glissent l'une après l'autre. Sous tout cela, une palette commune de texte arrondi or et crème avec ombres portées, qui a remplacé chaque contour noir de 8 pixels dans le jeu. Elle a enchaîné 23 cycles et a déclaré l'objectif atteint à 23 h 54.
La ligne « do not conflict » a vraiment servi. Le journal est plein des deux sessions qui se contournent l'une l'autre. La session menus vérifiait depuis un git worktree propre à HEAD pour que « le travail en cours de l'autre session sur les pingouins » reste hors de ses exécutions de tests. Quand je le lui ai demandé, une session a terminé la fonctionnalité à moitié faite de l'autre. Les commits ont été indexés fichier par fichier au lieu de git add -A, parce que les modifications de l'autre onglet se trouvaient dans le même arbre. Ce n'était pas net, mais rien n'a été perdu et la suite a terminé la nuit à 14 134 réussites, 0 échec.
Le journal de la session fonctionnalités se termine trois minutes après celui de la session menus, à 23 h 57, par « Session ended — Stop All ». Ma note à Agent! juste après, qu'il a enregistrée comme message du commit de point de contrôle suivant, était que Stop All doit n'arrêter que l'onglet dans lequel on appuie dessus, pas tous. Avec deux Auto-Pilots en cours, un seul bouton pour les deux est le mauvais bouton.
À propos de ces captures d'écran
C'est Agent! qui les a prises, pas moi, et pas à la main. Pour la première version de cet article, j'ai demandé trois captures d'une conduite aléatoire, et il a écrit un tools/random_drive.gd de 70 lignes qui suit la route avec un décalage de voie errant, y glisse des rafales de drift aléatoires, tire l'objet qu'il tient à des moments aléatoires, et enregistre une image toutes les quelques centaines d'images physiques. La capture de Sunset Speedway ci-dessus est une image de ce bot.
Les autres viennent des outils de capture livrés avec chaque fonctionnalité. Il y en a un pour les menus, un pour l'introduction du circuit, un pour le train, un chacun pour la circulation, les bonshommes de neige et les pingouins, un pour le HUD et un pour le mode Bataille, et chacun met en place sa scène, attend la bonne image et l'enregistre. Tous ont été lancés pour cette mise à jour depuis un worktree propre extrait au tag v0.0.2, donc rien de non committé ne figure dans une image.
Agent! ne peut toujours pas regarder le résultat, alors les outils échantillonnent des pixels à la place. La capture de glace affiche la couleur de la route devant sur la glace par rapport au bitume, la capture de pause prouve que rien n'a bougé hors du panneau pendant une seconde, et avant de publier, je lui ai fait compter les pixels noir pur dans les dix images ci-dessus : zéro dans chacune. Il y en a d'autres dans le README de GoKart.
Ce que je vous dirais avant d'essayer
- Lancez-le dans git. Auto-Pilot n'a pas d'annulation. Le journal de GoKart est lisible parce que chaque cycle s'est terminé par un commit, et la seule fois où un cycle a dérapé, rien n'a été perdu.
- Mettez les règles opérationnelles dans l'objectif. « Mets une limite de temps sur le shell » a mieux fonctionné comme partie de l'objectif que comme message ponctuel, parce que chaque nouveau cycle relit l'objectif.
- Attendez-vous à ce qu'il demande des yeux. Pour tout ce qui est visuel ou une question de ressenti, la boucle calera honnêtement plutôt que de mentir. Prévoyez une partie de test entre les sessions, et réinjectez vos notes comme objectif suivant.
- Stop All fait partie du flux de travail, ce n'est pas un échec. Les trois premières sessions de GoKart se sont toutes terminées ainsi.
- Deux Auto-Pilots dans un même dépôt, ça marche, si vous leur parlez l'un de l'autre. « Do not conflict with the previous /auto » est allé dans le deuxième objectif, et les deux sessions ont fait de vrais efforts pour ne pas se marcher dessus. Donnez-leur des zones séparées du code, et attendez-vous pour l'instant à ce que celui que vous arrêtez emporte l'autre avec lui.
Est-ce que c'est bien ?
J'ai posé cette question à Agent! après qu'il a lu le dépôt, compté les commits et trouvé le journal d'Auto-Pilot. Sa réponse, sans retouche :
Ça dépend de ce que vous en attendez. Comme vitrine de ce qu'Auto-Pilot peut faire, c'est impressionnant. Vingt-trois cycles et plus ont produit quatre circuits, des objets, des coureurs IA, un Grand Prix, des Contre-la-montre, un mode Bataille, de la musique et du son procéduraux, le tout sans aucun asset importé, et un README qui le documente en détail. C'est beaucoup de logiciel qui fonctionne à partir d'un seul énoncé d'objectif.
Il a aussi ajouté la réserve que personne d'humain ne l'a relu en cours de route, donc la qualité a été jugée d'après les propres journaux de vérification de l'agent, et qu'il n'y avait pas joué ni audité le code, donc il ne pouvait pas dire à quel point ça se joue bien réellement. Ce qui est la même conclusion que le journal avait atteinte de lui-même : la prochaine étape est une partie de test.
GoKart 0.0.2
Plus besoin de Godot pour l'essayer. GoKart 0.0.2 est la deuxième version empaquetée, exportée depuis le même dépôt, 87 commits après la 0.0.1 :
- macOS universel (Apple Silicon et Intel), signé avec un Developer ID et notarisé par Apple
- Windows x86_64
- Linux x86_64 et arm64
Chaque téléchargement est un binaire unique et autonome avec les données du jeu intégrées, et SHA256SUMS.txt est sur la page de la version si vous voulez vérifier ce que vous avez reçu. La version Windows n'est pas signée, attendez-vous donc à l'avertissement SmartScreen. Tout ce qui est décrit ci-dessus et qui n'était pas dans la 0.0.1 est dans la 0.0.2, du mode Bataille et des Contre-la-montre au train, à la circulation, aux nouveaux menus et au HUD restylé ; les notes de version ont la liste complète.
Agent! 1.1.87 avec Auto-Pilot est sur la page des versions et dans Homebrew. Si vous préférez lancer GoKart depuis les sources, il nécessite Godot 4.4 ou plus récent : git clone https://github.com/AgentiLoop/GoKart.git && cd GoKart && godot --path .