Skip to content

thlg057/mo5-space-invaders-tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Développer un Space Invaders pour Thomson MO5 en C avec CMOC

Ce tutorial montre comment développer un shoot'em up vertical sur Thomson MO5, étape par étape, en C compilé avec CMOC. Chaque étape correspond à un tag Git.

Prérequis

  • CMOC installé et fonctionnel
  • Émulateur MO5 (par exemple YAME)
  • Repo de base : https://github.com/thlg057/mo5_template
  • Notions de base en C (pointeurs, tableaux statiques)

La machine

Caractéristique Valeur
CPU Motorola 6809 @ ~1 MHz
RAM utile 48 Ko
Résolution 320x200 pixels
Couleurs 16 couleurs
Compilateur CMOC (C pour 6809)

Deux règles fondamentales s'appliquent à tout le code.

Pas de malloc. Toute la mémoire est allouée statiquement à la compilation. Les tableaux d'ennemis, de balles, de sprites -- tout est dimensionné à l'avance avec des #define.

Pas de float, pas de division si possible. Le 6809 ne dispose pas d'unité virgule flottante. On préfère les décalages (>> 1 au lieu de / 2) et l'arithmétique sur unsigned char (8 bits natifs) plutôt que int (16 bits).

Contrainte graphique : 2 couleurs par bloc de 8 pixels

La VRAM du MO5 est organisée en deux banques sélectionnées via le registre PRC :

  • Banque couleur : chaque octet encode la couleur de fond (bits 0-3) et la couleur de forme (bits 4-7) pour un groupe de 8 pixels horizontaux.
  • Banque forme : chaque bit correspond à un pixel -- 1 affiche la couleur de forme, 0 affiche la couleur de fond.

Un groupe de 8 pixels ne peut afficher que 2 couleurs. Les sprites respectent cette contrainte en variant les couleurs ligne par ligne. Le script png2mo5.py vérifie et encode cette règle lors de la génération des .h.

SDK maison

Fichier Rôle
mo5_defs.h Registres hardware, palette, dimensions écran
mo5_video.h Init video, clear écran, fill rectangle
mo5_sprite_bg.h Sprites transparents (fond conservé)
mo5_sprite_form.h Sprites forme seule
mo5_sprite.h Sprites opaques
mo5_actor_dr.h Dirty rectangle : save/restore zone VRAM
mo5_font6.h Affichage de texte - 6 pixels de haut
mo5_font8.h Affichage de texte - 8 pixels de haut

Pipeline de conversion sprite :

make convert IMG=./assets/player.png
# génère include/assets/player.h

Pour ce projet, on utilisera les fonctions de mo5_sprite_bg.h, qui permettent de gérer la transparence (le fond est celui du décor)

Sprites disponibles

Fichier Taille Description
player.png 24x24 Vaisseau joueur, bleu/rouge/jaune
enemy.png 16x16 Alien insecte, vert/jaune
bullet_player.png 8x8 Tir joueur, cyan/blanc
bullet_enemy.png 8x8 Tir ennemi, rouge/orange

Structures de données

unsigned char partout où la valeur tient sur 8 bits.

typedef struct {
    MO5_Actor     actor;
    unsigned char active;
} ActiveActor;

typedef struct {
    MO5_Actor     actor;
    unsigned char active;
    unsigned char hp;
} EnemyActor;

Les coordonnées x sont en octets (1 unité = 8 pixels), les coordonnées y sont en pixels. Cette distinction est imposée par la VRAM.

Architecture du jeu

Le jeu repose sur une boucle principale simple :

  1. Lecture des entrées clavier
  2. Mise à jour joueur
  3. Mise à jour balles
  4. Mise à jour ennemis
  5. Détection collisions
  6. Attente VBL
  7. Dessin

Principe fondamental MO5 :

  • Pas d'allocation dynamique
  • Structures statiques dimensionnées à la compilation
  • Utilisation prioritaire de unsigned char
  • Synchronisation à 50 Hz (PAL)

Organisation des sources

Structure du projet :

mo5-spaceinvaders/
├── Makefile
├── src/
│   ├── main.c
│   └── game.c
├── include/
│   ├── game.h
│   └── assets/
│       ├── player.h
│       ├── enemy.h
│       ├── bullet_player.h
│       └── bullet_enemy.h
├── assets/
│   ├── player.png
│   ├── enemy.png
│   ├── bullet_player.png
│   └── bullet_enemy.png
├── output/
└── tools/

Rôles

  • main.c : point d'entrée minimal (initialisation + appel game_loop())
  • game.c : toute la logique du jeu (moteur, update, collisions, HUD)
  • game.h : interface publique minimale (void game_loop(void);)
  • include/assets/ : sprites générés automatiquement depuis les PNG

Utilisation avec GitHub Codespaces

Créer un Codespace

Depuis le dépôt GitHub : - Cliquer sur use this template et sélectionner Open in a codespace

Installer l'environnement

Dans le terminal :

make setup-codespace

Cette commande installe automatiquement :

  • CMOC (compilateur C 6809)
  • lwtools (assembleur)
  • Python 3 + Pillow
  • Dépendances nécessaires au SDK

Installation du SDK

Une seule fois ou après une mise à jour du SDK.

make install

Cela : - Télécharge BootFloppyDisk - Compile le sdk_mo5 - Installe les outils dans tools/

Build du projet et génération des images *

make

Tags Git

Tag Contenu
step-01-player Joueur, déplacement, tirs joueur
step-02-score HUD score et vies
step-03-enemies Ennemis, formation, tirs ennemis
step-04-collisions Collisions, points de vie, game over

Étape 1 -- step-01-player -- Joueur, déplacement et tirs

Afficher le vaisseau joueur en bas de l'écran, le déplacer avec Q/D, et tirer des balles vers le haut avec Espace.

Étape 2 -- step-02-score -- Affichage du score

Afficher le score et les vies en haut de l'écran, mis à jour à chaque événement (ennemi détruit, vie perdue).

Étape 3 -- step-03-enemies -- Ennemis et leurs tirs

Afficher une vague d'ennemis en formation, les faire osciller horizontalement, descendre au rebord, et tirer périodiquement.

Étape 4 -- step-04-collisions -- Collisions, points de vie et fin de partie

Détecter les impacts, gérer les points de vie, l'invincibilité temporaire du joueur, le game over et la victoire.

Récapitulatif des optimisations MO5

Règle Pourquoi
unsigned char plutôt que int Opérations 8 bits natives sur 6809
while (n--) plutôt que for (i=0; i<n; i++) Flag Z automatique après décrémentation
*p++ plutôt que tab[i] LEAX 1,X au lieu d'un calcul d'index
static sur les fonctions internes Inlining possible, symboles non exportés
Compteur de frames pour les vitesses Indépendant du nombre de sprites actifs
Pas de row_offsets[] Économise 400 octets RAM
Flag score_dirty pour le HUD Redessinage uniquement en cas de changement
#define internes dans game.c Pas dans game.h si personne d'autre n'en a besoin

Packages

 
 
 

Contributors

Generated from thlg057/mo5_template