TD1. Game On!

découverte de TIC-80, animer l’écran sans interaction

Auteur·rice·s
Affiliations

Mathieu Liedloff

Université d’Orléans

Nicolas Ollinger

Résumé

L’objectif de cette première séance est de découvrir TIC-80, son fonctionnement, ses commandes, son éditeur intégré et de mettre en place les premiers automatismes pour y développer des jeux vidéos rétro. Côté programmation, on commence doucement avec la production de cartouches non-interactives qui s’apparentent plus à des animations qu’à des jeux vidéos. En Python, on aborde la notion de programme, de variable, de conditionnelle et de boucle simple.

1 Bonjour TIC-80

TIC-80 est une console imaginaire (en anglais fantasy console). Voici ce qu’en dit wikipedia : « Une fantasy console (signifiant en anglais console imaginaire), ou fantasy computer (signifiant en anglais ordinateur imaginaire), sont des moteurs de jeux sous forme de machines virtuelles simulant des consoles aux capacités volontairement limitées. Ces limitations sont généralement inspirées des ordinateurs et consoles 8 bits : Pixel art avec une résolution volontairement basse, son et musique limités chiptune. Elle s’inscrit ainsi dans la démarche du retrogaming. »

Environnement de travail

Environnement de travail

Sans plus attendre, plongeons dans le vif du sujet !

À vous de jouer

Ouvrir le lien GameOn TIC-80 dans une autre fenêtre ou un autre onglet du navigateur. C’est votre environnement de travail pour toute la séance ! Garder cette fenêtre ouverte.

Attention

Attention à bien utiliser la version de TIC-80 fournie pour ce TP pas une autre. Cette instance contient des éléments spécifiques pour vous aider pendant les séances. Bien sûr, les cartouches produites seront ensuite utilisables dans toute instance de TIC-80.

1.1 Premiers pas

Au lancement, après une courte animation, TIC-80 affiche sa console. Un message multicolore nous informe de la version du logiciel et de l’existence de la commande help. Un prompt > et un curseur clignotant indique que le programme attend la saisie d’une commande.

La commande help permet d’obtenir des informations (en anglais) sur les commandes disponibles, les capacités de la machine et les fonctions disponibles pour programmer.

À vous de jouer

Taper la commande help et valider avec la touche Return. Lire le résultat. Recommencer avec la commande help welcome et lire le texte obtenu.

la commande help

L’invite de saisie de commandes a son charme mais TIC-80 c’est surtout un environnement intégré de conception de jeu vidéo rétro. À cette fin, TIC-80 propose trois grands modes de fonctionnement :

  • une console de saisie de commandes ;
  • un éditeur qui permet de modifier le programme, les sprites, la musique, etc ;
  • un mode exécution qui permet de joueur au jeu en cours de conception.

La touche Esc du clavier ainsi que la commande run et le raccourci clavier Ctrl+R permettent de naviguer entre ces différents modes comme l’indique la figure ci-dessous. En général, TIC-80 démarre en mode console.

Les différents modes de TIC-80

1.2 Configuration

Le comportement de TIC-80 peut être personnalisé de différentes manières (tout comme les couleurs de l’éditeur, etc). Nous allons nous contenter aujourd’hui d’activer le mode développement qui permet une navigation plus fluide entre le code source et l’exécution du programme. Très pratique en phase de conception.

À vous de jouer

Taper la commande menu pour accéder à la configuration de TIC-80. Activer le mode développement DEV MODE < ON >.

menu de configuration

Plus tard, c’est dans ce menu qu’il faudra revenir pour configurer les touches du clavier par exemple.

1.3 Commandes console

La commande help documente l’ensemble des commandes disponibles dans l’invite de commande. Il suffit d’invoquer help suivi du nom de la commande. Nous présentons ci-dessous rapidement les principales commandes qui vous serons utiles.

commandes disponibles

1.3.1 cls

cls permet d’effacer l’écran de la console.

1.3.2 ls, del, cd et mkdir

Pour naviguer dans les fichiers accessibles à TIC-80 :

  • ls affiche les fichiers et répertoires du répertoire courant ;
  • cd change de répertoire courant (sans paramètre, retourne à la racine) ;
  • mkdir crée un répertoire dans le répertoire courant ;
  • del supprime un fichier ou un répertoire vide.

1.3.3 new python

La commande new permet de créer une nouvelle cartouche (un nouveau projet). Elle réinitialise la console et remplace le programme courant par un programme Hello World dans le langage passé en paramètre. Elle réinitialise aussi les sprites, les sons, la musique, etc.

1.3.4 run

La commande run lance l’exécution du programme courant. Le raccourci clavier Ctrl+R fait la même chose. En mode exécution, il relance le programme courant.

1.3.5 save, load

La commande load charge une cartouche dans la machine, pour être ensuite exécutée et/ou modifiée.

La commande save sauvegarde le programme courant et ses ressources dans un fichier. Le raccourci clavier Ctrl+S fait la même chose une fois que le programme a déjà été sauvée une fois (et qu’il possède donc un nom de cartouche).

Attention

Ne pas oublier de sauvegarder régulièrement son travail pour éviter de tout perdre en cas d’arrêt intempestif de TIC-80.

1.3.6 folder, add et get

Les cartouches chargées et enregistrées le sont dans une arborescence de fichiers. Où sont stockés ces fichiers ?

Lorsque TIC-80 est utilisé en natif sur la machine avec le programme TIC-80, les fichiers sont stockés dans un répertoire. La commande folder permet d’ouvrir ce répertoire dans le navigateur de fichiers pour y accéder et y déposer ou y récupérer des fichiers.

Lorsque TIC-80 est utilisé dans le navigateur web (c’est le cas ici !), les fichiers sont stockés dans le système de stockage interne du navigateur. La commande get permet de récupérer un fichier, de le télécharger. La commande add permet de déposer un fichier dans ce stockage interne.

À vous de jouer

Utiliser la commande new python pour créer une nouvelle cartouche. Avec Esc aller dans le source pour modifier le message "HELLO WORLD!" en "Bonjour GameOn!". Retourner à la racine avec cd sans paramètre, puis sauvegarder votre cartouche avec save essai. Enfin, récupérer la cartouche sur la machine hôte avec get essai.tic.

Dans un deuxième temps, supprimer le fichier avec del essai.tic et vérifier qu’il n’est plus là avec ls.

Enfin, recharger le fichier avec add et vérifier que load essai.tic fonctionne.

Attention

En fin de séance, ne pas oublier d’utiliser la commande get pour récupérer les cartouches sauvegardées pour les stocker sur une clé USB ou autre. En début de séance, redéposer les fichiers nécessaires dans TIC-80 à l’aide de la commande add.

1.3.7 surf

La commande surf permet de naviguer dans les fichiers pour charger + exécuter une cartouche en une seule étape. Elle permet aussi de visualiser les jaquettes des jeux qui en possèdent.

D’autres part, surf permet de télécharger des cartouches depuis un serveur. La version officielle de TIC-80 permet de télécharger ainsi toutes les cartouches du site tic80.com. La version spéciale GameOn récupère les cartouches sur le serveur GameOn.

À vous de jouer

Utiliser la commande surf pour lancer la cartouche GameOn/TD1/bounce.tic. Une balle verte rebondit à l’écran. Grâce à Esc, afficher le code source et le parcourir rapidement.

1.4 Éditeur(s)

En mode édition, TIC-80 propose 5 éditeurs spécialisés chacun dans une tâche dédiée à la création de jeu vidéo. Aujourd’hui, nous nous concentrons uniquement sur l’éditeur de code. Les autres éditeurs seront traités dans des fiches ultérieures.

éditeur de code

éditeur de sprites

éditeur de carte

éditeur de sfx

éditeur de musique
Figure 1: Éditeurs de TIC-80

L’éditeur de code est plus riche qu’il n’y paraît au premier abord. Il permet de programmer une cartouche dans différents langages de programmation. La présence en début de fichier d’un commentaire indiquant script: suivi du nom du langage lui permet de déterminer le langage choisi. Pour nous, cette ligne sera toujours la même :

# script: python

Différents boutons utiles sont disposé en haut à droite de la fenêtre d’édition. Il peut être utile de connaître quelques raccourcis clavier pour travailler plus efficacement :

  • Ctrl+R lance l’exécution ;
  • Ctrl+A sélectionne l’ensemble du code (il suffit d’appuyer ensuite sur BACKSPACE pour tout effacer) ;
  • Ctrl+X, Ctrl+C, Ctrl+V permettent de faire des copier-coller (malheureusement dans la version Web de TIC-80, ces copier-coller ne communiquent pas avec l’extérieur de TIC-80) ;
  • Ctrl+Z et Ctrl+Y fournissent les bien utiles UNDO et REDO.

1.5 Exécution

En mode exécution, c’est le programme de la cartouche en cours qui a la main. La seule touche qui permet d’interrompre l’exécution est Esc. En dehors de cela, les frappes de touches, les boutons des différentes manettes de jeu (gamepad), ou encore la souris, sont gérés par le programme.

On peut configurer les touches du clavier associées au gamepad depuis le menu. Sur un clavier AZERTY, il est très utile d’aller modifier la configuration par défaut pour utiliser les touches W, X, Q et S en lieu et place des Z, X, A et S d’un clavier QWERTY.

configuration du gamepad

En cours d’exécution, quelques raccourcis clavier permettent de saisir l’instant :

  • F7 capture l’image actuelle pour en faire la jaquette de la cartouche ;
  • F8 prend une capture d’écran ;
  • F9 démarre/arrête l’enregistrement d’une vidéo au format GIF animé ;

1.6 Cartouches .tic

En TIC-80, un jeu vidéo, ou plus généralement un projet, est appelé une cartouche (en anglais cart). Il s’agit ici d’un fichier unique dont l’extension est habituellement .tic. Ce fichier contient le code source et toutes les ressources du jeu (sprites, musique, etc) ainsi que la jaquette. C’est lui qu’on charge avec load et qu’on sauvegarde avec save.

Les métadonnées d’une cartouche (auteur, titre, description, etc) sont déclarées en tête du code source.

À vous de jouer

Pour valider cette partie et vérifier que vous avez bien compris le fonctionnement de TIC-80 et la gestion des cartouches, il est temps de faire une pause ludique ! Télécharger la cartouche .tic d’un jeu TIC-80 de verysoftwares, par exemple ROWBYROW ou encore multiple maze (utiliser le bouton Download Now et pour prix cliquer sur No thanks, just take me to the downloads). Ajouter cette cartouche à votre TIC-80 avec la commande add puis charger la cartouche avec load et jouer une partie du jeu ! Ensuite, explorer les entrailles du jeu : le source (ce n’est pas du Python, pas la peine d’essayer de le lire), les sprites, etc. Faites une modification de sprite et relancer le jeu avec Ctrl+R pour la voir à l’écran.

2 Un peu de Python

Bon… on cause, on cause… mais comment est-ce qu’on crée un jeu avec TIC-80 ?

Regardons les spécifications à l’aide de la commande help spec.

spécifications de TIC-80

TIC-80 dispose d’un écran de 240 par 136 pixels et d’une palette de 16 couleurs, il gère des entrées, peut utiliser des sprites, des cartes, des sons et des musiques… et surtout chaque cartouche peut contenir jusqu’à 64Kio de code. Ce code, ce programme, interagi avec TIC-80 à travers une famille de fonctions qu’on appelle l’API de programmation de TIC-80. Elle a l’avantage d’être assez limitée en taille.

API de TIC-80

Un programme TIC-80 décrit un programme avec son initialisation et sa boucle de jeu. La boucle de jeu prend la forme d’une fonction TIC() qui est appelée 60 fois par secondes pour effectuer les trois tâches fondamentales d’un jeu vidéo : lire les entrées, mettre à jour l’état du jeu et gérer l’affichage à l’écran.

flowchart LR
  A["initialisation"]
  A --> B["input"]
  subgraph "60 fois par seconde"
  B --> D["update"]
  D --> E["draw"]
  E --> B
  end

la boucle de jeu : le rôle de la fonction TIC()

Nous avons choisi d’utiliser le langage de programmation Python pour coder nos jeux TIC-80. Voici un exemple simple de code Python valide pour TIC-80 :

# script: python
t=0
d=1
trace("Bonjour ! On demarre.")

def TIC():
  global t,d
  cls(0)
  clip(0,0,136,136)
  for i in range(20):
    e=i*0.5
    line(0, t*e, 135-t*e, 0, 12)
    line(t*e, 135, 0, t*e, 12)
    line(135, 135-t*e, t*e, 135, 12)
    line(135-t*e, 0, 135, 135-t*e, 12)
  t=t+d
  if t<0 or t>135:
    d=-d
    t=t+d

Comment est-ce que ça fonctionne ?

  • la ligne 1 est un commentaire qui indique à TIC-80 qu’on code en Python ;
  • les lignes 2 à 3 initialisent le programme ;
  • la ligne 4 affiche un message dans la console (pratique lors de la conception) ;
  • les lignes 6 à 19 définissent la fonction TIC().

L’expression en jaune ligne 4 est une chaîne de caractères. Les expressions en bleu clair un peu partout sont des constantes numériques. Les mots en orange sont des mots-clés du langage et en vert des fonctions de l’API TIC-80.

En Python, une ligne correspond généralement à une instruction à effectuer :

  1. modifier la valeur d’une variable, lignes 2, 3, 11, 16, 18 ou encore 19 ;
  2. appeler une fonction en lui passant des paramètres, lignes 4, 8, 9, 12 à 15.

Parfois une instruction a besoin d’un bloc d’instructions associées. La ligne déclarant l’instruction se termine alors par le symbole : et le bloc d’instructions associées apparaît en dessous, indenté vers la droite. C’est le cas dans notre exemple :

  1. pour déclarer la fonction TIC() lignes 6 à 19 ;
  2. pour la boucle lignes 10 à 15 ;
  3. pour l’instruction conditionnelle lignes 17 à 19.
Apprentissage de Python

Nous allons aborder Python avec une approche de type « observer, copier et modifier » en vous fournissant du code TIC-80 à modifier. Si cette approche ne vous convient pas, nous vous encourageons fortement à travailler en dehors des séances de TD avec futurecoder, un outil d’aide à l’apprentissage de Python.

3 Dessin et pixels

Aujourd’hui nous allons créer des cartouches simples, non-interactives, en utilisant l’API de dessin de TIC-80. Lors des séances suivantes nous introduiront progressivement les éléments spécifiques typés jeux vidéos rétro.

À l’aide de la commande surf vous pouvez accéder dans GameOn/TD1/ à des exemples proches des exercices ou parfois contenant la solutions aux exercices. Ils sont là pour vous fournir un visuel et parfois une aide. Il est intéressant de commencer par chercher par soi-même ! Dans le sous-répertoire bonus se trouvent des exemples un peu plus sophistiqués pour aller plus loin une fois les exercices terminés.

L’API contient quelques fonctions pour lire et écrire des pixels mais aussi effacer l’écran et tracer quelques figures élémentaires (segments, rectangles, cercles, etc). Nous vous avons concoté une petite cartouche de démonstration de l’API avec sa syntaxe (à ouvrir dans un onglet) :

API TIC-80 pour dessiner (cliquer pour en savoir plus)

API TIC-80 pour dessiner (cliquer pour en savoir plus)

3.1 Moirés

Explorons ensemble le troublant phénomène des moirés. Charger l’exemple GameOn/TD1/moire.tic à l’aide de la commande surf et observer le phénomène.

Voici un script Python à recopier dans une cartouche neuve (new python) :

# script:  python
def TIC():
  cls(0)
  x = 120
  y = 68
  for r in range(0, 500, 4):
    circb(x, y, r, 12)

Ce code efface l’écran, stocke les valeurs 120 et 68 dans les variables x et y puis effectue une boucle au cours de laquelle la variable r prend sucessivement les valeurs de 0 à 500 par pas de 4 (0, 4, 8, 12, 16, …). À chaque tour de boucle, il trace un cercle blanc (couleur 12) de centre (x, y) et de rayon r.

ronds imbriqués
À vous de jouer

Modifier le script Python pour qu’il affiche un deuxième réseau de cercles imbriqués. Jouer avec la position du centre pour obtenir un magnifique moiré.

Ajouter un troisème réseau ? Changer la couleur des cercles ? Modifier leur espacement ? Jouer avec les paramètres !

3.2 Rebonds

Créons un premier effet arcade. Charger l’exemple GameOn/TD1/bounce.tic à l’aide de la commande surf et observer l’animation. Cette animation repose sur deux effets : une trajectoire sur laquelle un disque se déplace au cours du temps et un effet d’effacement progressif qui crée une sorte de traîne de particules.

Voici un début du programme qui affiche un mot qui rebondit horizontalement :

# script: python
x=0
dx=1
co=0
cls(0)

def TIC():
  global x,dx,co
  w=print("GameOn",x,60,8+co,scale=3)
  x=x+dx
  if x<0 or x+w>240:
    dx=-dx
    x=x+dx
  co=(co+1)%5

Le mot-clé global est utilisé pour indiquer que les variables dont les noms suivent sont déclarées en dehors de la fonction (ici la fonction TIC()). Cela permet de conserver leurs valeurs entre deux appels de la fonction. Ici x mémorise la position horizontale du mot et dx le déplacement à effectuer à chaque étape. La conditionnelle if x<0 or x+w>240: permet de détecter les collisions avec le bord et d’inverser alors le sens de déplacement. La variable co permet de faire varier la couleur grâce à l’opérateur modulo % qui retourne le reste de la division euclidienne.

À vous de jouer

En partant de la cartouche contenant juste ce code, modifier le code pour ajouter un déplacement vertical (y, dy) avec des rebonds sur les quatre côtés de l’écran.

Pour ajouter un effet d’effacement progressif, nous allons effacer quelques milliers de pixels à chaque étape en les peignants dans la couleur de fond. Ces pixels seront tirés au hasard. Pour cela, en début de script, on importe une fonction de bibliothèque :

from random import randint

La fonction randint(a,b) retourne un nombre entier compris entre a inclus et b inclus. Pour effacer un point, on propose d’utiliser le code suivant :

pix(randint(0,239),randint(0,135),0)

Pour effacer 500 points, on ajoute une boucle autour :

for _ in range(500):
  pix(randint(0,239),randint(0,135),0)
À vous de jouer

Modifier la cartouche pour obtenir un magnifique effet de rebond avec effacement du texte. Choisir le nombre de pixels effacés qui correspond le mieux à l’effet souhaité. Jouer avec le code ! Changer les couleurs ! Le texte !

3.3 Horloge

Créons une horloge murale semblable à l’exemple wallclock (ne lisez pas son code source pour l’instant).

horloge murale

Voici un début du programme qui affiche un point pour chaque minute, ainsi que l’aiguille des secondes :

# title:   wall clock
# script:  python
from math import cos, sin, pi

def point(r,a):
  x = round(120+r*cos((a+45)*2*pi/60))
  y = round(68+r*sin((a+45)*2*pi/60))
  return (x, y)

def TIC():
  t = tstamp()+3600
  cls(0)
  for i in range(60):
    x,y = point(62, i)
    pix(x,y,13)
  s = t%60
  (x,y) = point(55, s)
  line(120, 68, x, y, 4)

Dans ce code, la variable t reçoit le nombre de secondes écoulées depuis le 1er janvier 1970. Le calcul s=t%60 met dans la variable s le reste de la division euclidienne de t par 60 : c’est le nombre de secondes de la minute courante !

Le centre de l’horloge occupe les coordonnées (120, 68). La fonction point(r,a) retourne les coordonnées du point situé à distance r sur le point des minutes d’index a.

À vous de jouer

En partant de la cartouche contenant juste ce code, écrire une cartouche qui réalise une horloge murale complète avec cadran et aiguilles des heures, minutes et secondes.

3.4 Onomatopées

Lorsqu’on omet d’effacer l’écran dans TIC(), les affichages successifs s’empilent. C’est ce qu’exploitent les exemples sier et bounce. On propose ici d’utiliser ceci de la manière suivante. On place un cls(0) dans l’initialisation du programme puis dans TIC() on ajoute à chaque étape une nouvelle onomatopée à l’écran.

À vous de jouer

Écrire une cartouche qui empile à l’écran des onomatopées dignes des meilleurs comic strip (CRIP! CRAP! BANG! VLOP! ZIP! SHEBAM! POW! BLOP! WIZZ!) en utilisant un arrière-plan composé avec des figures simples (cercles, triangles, segments) et un avant-plan composé avec print utilisant le paramètre scale.

Références

  1. Le site futurecoder pour débuter en Python en autonomie ;
  2. Le wiki officiel de TIC-80 ;
  3. Une sélection de cartouches TIC-80 non-interactives pour nourrir votre inspiration :

quadtree

fallspire

city - 2 : year 3021

inception

DNA

micro organisms 11
Figure 2: Sélection de cartouches TIC-80

Réutilisation