Pour les deux ans de la mise à disposition du public de Chat GPT, Bob avait envie de proposer quelque chose de plus velu que l’an passé. Je me suis dit que proposer un jeu entièrement développé par l’IA serait un bon petit défi. Entendons-nous bien : il ne s’agit pas d’utiliser l’IA comme outil accélérateur ou facilitateur du développement, comme je le fais depuis un certain temps déjà, mais de réussir à obtenir un jeu « complet » sans toucher au code écrit par l’intelligence artificielle. Un défi pas si simple en pratique.

Car si les outils d’IA permettent d’accélérer franchement la programmation, ils ne sont pas intelligents et se contentent de développer et mettre en bonne forme les requêtes soumises. Personnellement, sous Unity, j’utilise AI Toolbox, un des premiers outils proposés, qui est fiable et régulièrement mis à jour. Le principe est simple, je demande à l’outil de créer (ou modifier) un script C# en langage simple, et j’obtiens un script directement exploitable (dès lors qu’on comprend comment s’adresser au modèle de langage, les résultats obtenus sont très bons). Je précise : AI Toolbox ne permet pas au développeur d’obtenir quelque chose qu’il ne sait pas faire – car il ne saura alors pas de demander correctement – mais il permet d’obtenir presque instantanément un script qui aurait demandé quelques minutes de rédaction et/ou de recherches dans la documentation. Et sur un projet complet, ça représente des heures de gagnées !
Des exemples ? Imaginons que j’ai besoin d’un système de commande simple. Je vais demander à l’outil d’IA quelque chose comme :

J’obtiens alors un script complet, qui prend en compte les exceptions et est parfaitement fonctionnel :

Plutôt pas mal, hein ? Sur le fond, le script est très simple, mais il est beaucoup plus rapide de rédiger la première fenêtre que la seconde, d’autant plus que Chat GPT (qui est le moteur de langage utilisé par AI Toolbox) est très tolérant sur les fautes de frappe, ce qui n’est pas le cas de C# ! Prenons un autre exemple, pour ouvrir un PDF depuis Unity :

J’ai fait un joli mélange franco/anglais (« fonction public ») et, surtout, ce genre de commande d’apparence simple nécessite toujours d’aller fouiner dans la documentation pour trouver la syntaxe exacte, ce qui peu facilement prendre cinq à dix minutes. Alors qu’avec l’intelligence artificielle, bim !, script instantané :

C’est clair et fonctionnel, les using sont intégrés… Bref, de la belle ouvrage ! L’Intelligence Artificielle est donc un allié précieux pour le développeur. Mais est-elle assez avancée pour éviter au développeur d’aller reprendre « manuellement » les scripts générés à la main ? Bob va vérifier ça !
SOMMAIRE
- Feuille de route
- Préparation « manuelle »
- Expérimentation
- Le Game Manager
- Deplacer le tetrimino
- Arrêt du tetrimino
- Gestion des empilements et des lignes
- Suppression de la ligne complète
- Améliorations
- Conclusion
Feuille de route

Pour mon expérience, j’ai désigné le vénérable Tetris comme cobaye idéal. Pourquoi Tetris ? Principalement parce que parmi tous les classiques que j’ai recréés pour parfaire mes gammes – rappelez-vous Bob le Frog le printemps passé ! – Tetris est le seul qui me résiste. Je ne me l’explique pas, mais toutes mes tentatives de recréation de ce classique, auquel je m’adonne pourtant avec passion depuis une quarantaine d’années, se sont soldées par des échecs. Il doit y avoir dans la logique du jeu quelque chose que je ne saisis pas, alors même je suis assez bon quand j’y joue… Bref, l’heure est venue de prendre ma revanche !
Mais pour relever le défi, il me faut une feuille de route. Première chose : je ne vais pas chercher à recréer le Tetris ultime, fidèle au pixel près aux règles officielles. Il existe d’ailleurs des différences entre les multiples versions canoniques, sans compter tous les clones. Dès que j’aurai obtenu un clone fonctionnel, je considérerait le défi relevé. Et je vous rappelle que sur bobdupneu.fr, c’est Bob qui fixe les règles ! Deuxième chose, et parce que c’est la troisième fois que je tente de rédiger cet article qui me trotte dans la tête depuis plus d’un an et que j’ai lamentablement échoué à deux reprises, il m’est apparu nécessaire de chercher un guide : le tutoriel de Valem sur Tetris fera parfaitement l’affaire !
Suivre un guide me permettra de me concentrer sur mes demandes à Chat GPT, tout en disposant d’un modèle de ce que je dois obtenir de l’IA pour rester sur les rails de la réussite. Et peut-être que la 3ème fois sera la bonne !
Préparation « manuelle »
Pour que le défi reste simple, je n’utiliserai rien d’autre que les outils d’Unity et respecterai approximativement les recommandations du Tetris Guideline. Je créé un nouveau projet « Universal 2D » dans Unity – que je nomme TetrIA, parce que je suis un gars rigolo – et passe directement en projet Web, car je souhaite intégrer le résultat de mon expérimentation dans l’article.
Une fois cette configuration de base effectuée, je créé une grille de 10 colonnes sur 20 lignes, les 7 tetriminos officiels et une interface simple, en suivant pour ce faire les explications de mon guide Valem.
La capture d’écran ci-après montre le résultat. Maintenant, à Chat GPT de bosser !

Expérimentation
Soyons fous ! Demandons à Chat GPT de créer un jeu de Tetris, tout simplement!

Le résultat semble de prime abord intéressant…

Le seul tout petit problème, c’est que l’IA fait son fonctionnaire pour ce qui est des fonctions, qui ne sont que des coquilles vides…

Bref, comme je l’expliquais plus haut, Chat GPT ne remplace pas le programmeur, qui va devoir lui donner des instructions précises et imaginer lui-même la logique globale du jeu, l’IA ne permettant que d’accélérer l’écriture du code. Bien essayé, mais il va falloir bosser un peu quand même !
Le Game Manager
Je commence toujours le développement par la création d’un objet vide Game Manager auquel je rattache un script GameManager qui va réunir tous les éléments nécessaires à la bonne gestion du jeu. Ma première demande à Chat GPT est un peu longue mais ne contient rien de compliqué :

J’obtiens alors un script tout a fait correct; je modifie juste à la main la nature des textes à modifier pour en faire des Text Mesh Pro (ce que j’ai en fait utilisé dans mon UI) et je sérialise les deux panneaux Start et Game Over afin de pouvoir les lier dans l’inspector :

Il ne s’agit pas d’erreurs de Chat GPT mais de points de détail auxquels je n’ai pensé qu’après coup. Mon script est donc le suivant :
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using TMPro;
public class GameManager : MonoBehaviour
{
[Tooltip("Score du joueur")]
public int Score;
[Tooltip("Nombre de lignes complétées")]
public int Lignes;
[Tooltip("Niveau actuel")]
public int Niveau;
[Tooltip("Vitesse du jeu")]
public int Vitesse;
[Tooltip("Texte affichant le score")]
public TextMeshProUGUI T_Score;
[Tooltip("Texte affichant le niveau")]
public TextMeshProUGUI T_Niveau;
[Tooltip("Texte affichant les lignes")]
public TextMeshProUGUI T_Lignes;
[Tooltip("Indique si le jeu est en cours")]
public bool JeuEnCours;
[SerializeField] GameObject p_GameOver;
[SerializeField] GameObject p_Start;
void Start()
{
Vitesse = 1;
Niveau = 1;
ActualiserUI();
p_GameOver.SetActive(false);
p_Start.SetActive(true);
JeuEnCours = false;
}
void Update()
{
if (!JeuEnCours && p_Start.activeSelf)
{
if (Input.GetKeyDown(KeyCode.Return))
{
JeuEnCours = true;
p_Start.SetActive(false);
}
}
if (!JeuEnCours && p_GameOver.activeSelf)
{
if (Input.GetKeyDown(KeyCode.Return))
{
nouvellePartie();
}
}
}
public void ActualiserUI()
{
T_Score.text = Score.ToString("D6");
T_Niveau.text = Niveau.ToString("D2");
T_Lignes.text = Lignes.ToString("D3");
}
public void GameOver()
{
JeuEnCours = false;
p_GameOver.SetActive(true);
}
private void nouvellePartie()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
}
Ce code est parfaitement fonctionnel, les using ont été prévus, et le code utilisé est assez élégant. Je lance le jeu et constate que tout fonctionne (actualisation de l’affichage et apparition du panneau Start qui disparaît avec une pression sur la touche entrée.

Il est temps de s’attaquer à la logique propre à Tetris.
Déplacer le tetrimino
Dans Tetris, le tetrimino en jeu se déplace automatiquement vers le bas, la vitesse augmentant selon les niveaux. Le joueur peut déplacer la pièce à droite et à gauche – par à-coup d’une unité précisément – et accélérer sa descente. Également, il peut faire tourner la pièce de 90° dans le sens des aiguilles d’une montre, et la pièce doit toujours rester dans la grille. Commençons par le plus simple : les mouvements verticaux et horizontaux. Une requête assez simple produit un script court et parfaitement fonctionnel.


Il faut ensuite bloquer la pièce dans la zone de jeu; pour mémoire, la grille comporte 10 colonnes et 20 lignes. Il « suffit » dont de contrôler que chacun des quatre carrés de chaque tetrimino se trouve à l’intérieur de cette grille après chaque mouvement, et d’annuler le mouvement sinon. Pour cela, je demande à Chat GPT de modifier le script que je viens de créer.

La requête est très simple, mais le travail effectué par Chat GPT est assez important. Attention toutefois : il n’y a rien de complexe dans le code créé, mais – et il s’agit là de la force de l’IA comme assistant du développeur – cinq lignes de requête génèrent trois fois plus de lignes de code, sans compter la mise en forme, toute erreur dans une de ces lignes, à commencer par l’oubli d’un point-virgule, entraînant une erreur de compilation. Le gain de temps et donc évident. Dans le cas présent, Chat GPT créé la grille de jeu et l’utilise dans une nouvelle fonction pour vérifier que le tetrimino est dans l’aire de jeu, sans oublier de modifier les fonctions déjà existantes pour prendre en compte la nouveauté. Simple et efficace !



Il faut maintenant faire tourner le tetrimino; sur la vidéo de Valem qui me sert de guide, un tableau bien pratique montre les axes de rotation des sept tetrimino.

Il faut donc demander à Chat GPT de créer ce point de rotation – dont la position sera réglée dans l‘inspector pour chaque forme – et de faire tourner le tetrimino autour de cette forme de 90° à chaque pression sur la touche haut du clavier.
La requête est simple et le code généré l’est encore plus :


Le code fonctionne mais… lorsque le tetrimino change tourne, il ne descend plus mais se déplace dans la direction de sa base (donc si il est à l’envers, il remonte !). J’ai tout de suite identifié le problème : le déplacement du tetrimino se fait relativement a son orientation, alors qu’il devrait se faire par-rapport à l’orientation de la grille. Reste plus qu’à l’expliquer à Chat GPT, qui modifie utilement le script : le tetrimino se déplace désormais comme il faut même après une rotation. Il faut désormais gérer l’empilement des pièces et – étape sur laquelle je bute habituellement – la disparition des lignes…


Gestion des empilements et des lignes

Dans Tetris, le joueur essaie d’empiler les tetriminos sans laisser d’espaces vides. Lorsqu’une ligne est complète – les dix cases sont occupées par un carré issu d’un tetrimino – elle disparaît en donnant des points au joueur. Un coefficient multiplicateur est appliqué lorsque plusieurs lignes disparaissent en même temps, et les lignes supprimées sont immédiatement comblées avec les pièces des lignes supérieures. Le point sur lequel je bute est justement le dernier évoqué : dans mes précédents essais, je ne suis jamais parvenu a obtenir une suppression de lignes satisfaisante. Mais aujourd’hui est le jour de mon triomphe : je vais réussir !
Mais pour que les tetriminos s’empilent, il faut encore en avoir plusieurs. Et, pour des raisons de gameplay, je vais m’assurer que le tetrimino à venir est annoncé en marge. La scène affichera donc deux tetriminos, dont l’un hors-jeu (ne répondant pas au commandes claviers et restant immobile). Le tetrimino ainsi « en attente » sera au moment opportun mis en jeu et remplacé par un autre tetrimino en attente. Rien de compliqué au niveau de la logique.
Je commence par positionner deux game objects vides sur la scène : le premier en haut de la grille, centré (Spawn), le second dans la marge entre l’affichage du score et le titre (SpawnProchain). Au tour de Chat GPT a qui je demande de créer un état « en jeu » pour le tetrimino puis d’écrire le script réalisant ce qui a été expliqué dans le précédent paragraphe, dans le Game Manager évidemment. N’oublions pas d’appeler la fonction ainsi créée au démarrage de la partie. Une fois encore, le résultat obtenu est rapide et élégant.




Logiquement, l’apparition d’un nouveau tetrimino doit intervenir lorsque le tetrimino en jeu est posé, soit sur le « sol » de la grille de jeu, soit sur un autre tetrimino. Il faut donc déterminer un état « posé » du tetrimino : lorsque le tetrimino est posé, il n’est plus en jeu et la fonction NouveauTetrimino() est appelée. Je pourrai me contenter d’appeler la fonction lorsque le tetrimino atteint le bas de la grille et le mettre hors-jeu (pour qu’il ne bouge plus), mais je sais déjà qu’à l’étape suivante j’aurai besoin d’arrêter le tetrimino et d’appeler la fonction avant qu’il n’atteigne le bas de la grille (lorsqu’il se posera sur un autre tetrimino). Autant prévoir dès maintenant ce qui est nécessaire.


Je lance alors l’application qui se met à me parler méchamment :

Programmer (ou coder, c’est selon) se résume au final à deux choses simples : 1) Savoir trouver et lire la documentation et 2) Comprendre les messages d’erreur. Dans le cas d’espèce, la fonction NouveauTetrimino() semble invoquer un élément de tableau qui n’existe pas. Je regarde donc la ligne fautive :


Effectivement, pour passer du tetrimino en attente à gauche de la grille au tetrimino en jeu en haut de la grille, Chat GPT a considéré que le tetrimino en attente est un enfant du point de spawn. Le seul petit problème, c’est qu’il n’a jamais indiqué à Unity que le tetrimino instancié au point prochainSpawn devait en devenir l’enfant : le script cherche donc un élément dans le tableau des enfants de prochainSpawn, alors que ce dernier est vide (si vous n’avez rien compris, c’est que vous n’avez pas bien lu la documentation d’Unity !). Premier raté de Chat GPT, qui sera puni ! En attendant, il m’a semblé plus simple de corriger la logique « à la main » plutôt qu’essayer de formuler ma demande à Chat GPT. J’ai donc triché et modifié directement le script, mais ce sera notre petit secret !


Dernière étape de cette partie : gérer l’empilement des tetriminos. Dans Tetris, le tetrimino se fige lorsqu’un des blocs le constituant « touche » un bloc situé en-dessous, ce qui permet la création d’espaces vides, parfois clos, dont la bonne gestion est au cœur du gameplay. Il est donc nécessaire de garder en mémoire la position des quatre carrés de chaque tetrimino posé. Pour cela, la méthode la plus efficace – c’est celle utilisée dès les origines par Alexey Pajitnov – est celle du tableau à deux dimensions, également appelée matrice. Le principe de base est assez simple : la grille de jeu forme 10×20 cases (soit 200 – et je n’ai même pas eu besoin de calculatrice !) qui vont de 0,0 (en bas à gauche) a 9,19 (en haut à droite). Notez bien que cette numérotation est valable parce que, suivant les conseils de Valem, j’ai déplacé le bas inférieur gauche à la position 0,0. Bref, comme le tetrimino se déplace par unités complètes, les carrés qui le composent sont toujours « dans » une des cases de la grille. La programmation « classique » de Tetris est entièrement matricielle, la notre est hybride : la matrice n’est pas utilisée pour le déplacement, mais elle va être nécessaire pour gérer les « collisions » entre les tetriminos. Pour faire simple, il faut demander à Chat GPT de créer un tableau à deux dimensions représentant la grille, dont toutes les cases sont vides. Ensuite, il devra remplir les cases de ce tableau correspondant aux cases occupées par le tetrimino en jeu, à chaque mouvement. Lorsque le tetrimino ne sera plus en jeu, sa dernière position sera conservée dans le tableau : les tetriminos suivant devront vérifier si les cases visées par le prochain mouvement sont libres. Si ce n’est pas le cas, le mouvement sera impossible, et si le mouvement en question est vers le bas, le tetrimino sera posé et mis hors jeu. La grille est gérée par le GameManager et le déplacement du Tetrimino en fonction de la grille par le Tetrimino. Y’a plus qu’à ! Enfin, ça, c’est la théorie. En pratique, j’ai un peu galéré pour obtenir de Chat GPT ce que je voulais. Heureusement que j’avais un modèle à suivre avec la vidéo de Valem : j’ai corrigé à la main la grille créée par Chat GPT pour en faire un tableau de Transform (et non de nombres entiers comme l’IA l’avait suggéré), et j’ai réussi après plusieurs essais à trouver le prompt magique qui a fait comprendre à Chat GPT ce que je voulais obtenir. Mais quand on sait lui parler, c’est un gentil garçon !





Avec cette fonction, Bob vient d’atteindre son plafond de verre : mes essais sur la création d’un clone de Tetris se sont toujours achevés ici, et je n’ai jamais passé l’étape suivante, qui est aussi la dernière. Il est grand temps d’avaler un paquet de Granola (pour le courage) et d’affronter ma Némésis : la suppression de lignes !
Suppression de la ligne complète
Sur le papier, le fonctionnement est le suivant : lorsque le tetrimino est posé, on vérifie si une ligne est formée. Pour cela, il faut parcourir toutes les lignes depuis le haut et vérifier pour chacune si une case est nulle; si c’est le cas, il n’y a pas de ligne. Sinon, il faut effacer la ligne (toutes les cases de la ligne sont passées à « null ») puis baisser d’une ligne toutes les lignes situées au-dessus. Je vais pour cela appliquer la méthode de Valem, et je donne mes instructions à Chat GPT en ce sens :


Je lance le jeu et tout fonctionne… mal T_T La solution proposée par Valem, fidèlement reproduite par Chat GPT, ne prend pas en compte la suppression simultanée de plusieurs lignes, ou du moins la gère mal : après la première ligne, les tetriminos supprimés ne sont plus en jeu mais apparaissent toujours : du coup, les autres tetriminos passent à travers, et le jeu devient illisible. J’ai tout de suite identifié la cause du problème car je commence à avoir quelques heures de vol sur Unity : la mise à jour visuelle de la grille ne fonctionne pas correctement quand plus d’une ligne est supprimée en même temps. Deux solutions : 1) Chercher à optimiser l’algorithme pour que les appels soient effectués dans le bon ordre ou 2) Régler le problème salement en utilisant un tag attaché à chaque carré formant les tetriminos… Devinez l’option choisie par Bob le roi des fainéants !


Et là… magie ! Bob a vaincu sa Némésis et a programmé un Tetris fonctionnel ! Joie et bonheur… Le fait de découper la logique en toutes petites fonctions comme le montre Valem dans son tutoriel m’a permis d’éviter les fonctions alambiquées, et qui finissaient par se mordre la queue, testées dans mes précédents essais. La simplicité est souvent la meilleure voie en programmation. Quelques petites améliorations ne seraient pas de refus cependant.
Améliorations
La logique du jeu est en place et les petites améliorations que je veux apporter sont simples mais devraient améliorer le confort de jeu :
- Retour visuel et sonore lors de la suppression d’une ligne
- Musique de fond et retour sonore lors de la rotation et de la pose d’un Tetrimino
- Mise à jour du score, augmentation du niveau et de la vitesse
- Gestion et affichage du GameOver avec retour sonore
- Rotation avec la touche espace (en plus de la flèche haute)
Je commence par importer une musique de fond, ainsi que quatre clips audio pour la rotation, la pose d’une pièce, la suppression d’une ligne et le game over. A Chat GPT de finir le boulot, ce qu’il fait sans problème ou presque : comme il est un peu fainéant sur le retour visuel de la suppression de ligne (il créé une fonction vide et m’invite à la compléter…), je bricole un truc en une ligne; j’en profite pour incrémenter le nombre de lignes dans le Game Manager a chaque suppression de ligne, chose que j’ai oublié de demander à l’IA.





Pour la gestion du Game Over, c’est simple : on vérifie si un bloc se trouve sous le tetrimino. Si c’est le cas, on arrête le jeu et on affiche l’écran de fin de partie; je rajoute la lecture d’un son en modifiant directement le script obtenu.



Pour finir, je modifie légèrement le Game Manager pour augmenter de niveau (et de vitesse) toutes les 10 lignes.

Me voilà donc enfin avec un Tetris jouable et un peu finalisé; je pourrai continuer de l’améliorer, mais ce n’est pas le but de mon expérience, dont il faut désormais tirer les enseignements.
Conclusion

Quels enseignements retirer de cette expérience ? Premièrement, et ce n’est pas une surprise, l’Intelligence Artificielle n’est pas intelligente. Il s’agit d’un outil très intéressant et qui peut faire un bon assistant, mais ce n’est au final qu’un moteur de recherche très amélioré. Toute la réflexion doit passer par l’humain qui contrôle l’IA. Dans le cas de Tetris, mes précédents essais avec l’IA ne m’ont toujours mené dans une impasse. Il aura fallu que je m’inspire du travail d’un autre humain – la vidéo de Valem – pour comprendre mes erreurs et être capable d’obtenir de Chat GPT ce que je voulais : Chat GPT n’a jamais corrigé mes erreurs de logique. Ceci étant dit, dès que le concept est clair, il est beaucoup plus rapide et efficace d’obtenir un script rédigé par Chat GPT que d’aller fouiller dans la documentation pour construire son propre script. D’ailleurs, depuis un peu plus d’un an que je programme souvent avec l’aide d’AI toolbox, j’ai appris pas mal de choses : en exposant en langage naturel mes besoins à l’intelligence artificielle, cette dernière me propose des scripts qui, s’ils ne fonctionnent pas toujours du premier coup, utilisent des qu’il m’aurait été impossible de trouver de moi-même dans la documentation, faute de pouvoir nommer les choses correctement. En plus d’être une dactylo rapide et qui ne fait aucune coquille, Chat GPT est donc également un vecteur de découverte assez efficace. Attention toutefois : pour pouvoir bénéficier des bienfaits de l’IA dans la programmation, il faut déjà savoir programmer. Sans cela, impossible d’évaluer les scripts proposés, de comprendre les erreurs bloquantes et de les corriger. Et comme un bon ouvrier est celui qui sait manier ses outils, le bon programmeur assisté par l’IA est donc celui qui sait rédiger le prompts de façon à ce que Chat GPT les interprète correctement. Et ce n’est pas une tâche facile : il a fallu que je reformule au moins un tiers des demandes présentées dans cet article pour obtenir le résultat voulu, alors que j’utilise l’outil depuis plus d’un an. Bonne exécutante, l’IA a toujours besoin d’un humain au-dessus pour concevoir et vérifier son travail. En somme, et comme je l’ai déjà écrit auparavant, ce n’est pas l’Intelligence Artificielle qui volera votre boulot, mais les humains qui sauront s’en servir. A bon entendeur…
Bob Dupneu
Bob vous propose d’essayer ci-dessous le résultat de son expérience, j’ai nommé TetrIA (cliquez sur la fenêtre pour l’activer)

