Dans cet article, je vous propose de réaliser ensemble la programmation d’un jeu pour Kitco. Il est préférable de connaître les concepts de base de la programmation (variables, boucles, tableaux)

Le jeu de Sokoban

Le jeu de Sokoban est un jeu où l’on se trouve, dans un petit labyrinthe, vu de dessus. Il y a des caisses dans le labyrinthe et on doit les ranger à certains emplacements. On ne peut que les pousser et jamais les tirer. Il faut donc bien réfléchir, sous peine de se voir bloqué. Pour vous faire une idée plus précise, allez donc faire une petite partie ici: Un jeu de Sokoban en ligne …

On va partir sur le template de code basique pour commencer un programme Kitco:

Menu Fichier/Exemples/Kitco/nouveau:

// Template de base pour tout programme Kitco:
// Nécessaire pour l'environnement Kitco
#include "kitco.h"


// La partie Setup concerne ce qui va être exécuté au démarrage de Kitco
void setup() {

 // Cette commande est nécessaire pour intialiser Kitco à son démarrage
 initialiserKitco(1);
 
}

// loop est la boucle principale: va se lancer en boucle après Setup
void loop() {

}

La boucle principale

Commençons par une question simple: « Que doit faire Kitco pendant le jeu? ». Ce n’est pas compliqué, Kitco doit:

  • afficher les graphismes
  • jouer les bruitage avec le buzzer
  • surveiller les touches
  • faire respecter la logique du jeu

La Kitco n’a qu’un seul processeur qui va devoir faire tout ça en même temps. Vous allez me dire que ce processeur ne peut faire qu’une seule chose à la fois et vous aurez raison. Alors comment faire? La réponse est simple, on va faire une chose à la fois mais pas longtemps !

afficheGraphismes();
joueBruitages();
surveilleTouches();
logiqueJeu();
afficheGraphismes();
joueBruitages();
surveilleTouches();
logiqueJeu();
afficheGraphismes();
joueBruitages();
surveilleTouches();
logiqueJeu();
etc...

On va s’arranger pour que chaque instruction ne dure que quelques millièmes de secondes, et donc, notre cerveau très très lent (par rapport à un microprocesseur) aura l’impression que Kitco fait les quatre choses en même temps! Et pour répéter cela indéfiniment,  on place le tout dans la fonction loop();

...
void loop() {
  afficheGraphismes();
  // joueBruitages();
  // surveilleTouches();
  // logiqueJeu();
 }

Maintenant, il va falloir détailler, car ces 4 fonctions ne sont pas connues de notre Kitco! J’ai mis les 3 dernières en commentaire car nous allons commencer par coder les graphismes.

Les graphismes

Les graphismes sont composés du niveau, du joueur et éventuellement du score. Pour simplifier, nous n’allons pas compter ni afficher le score. Le stockage du niveau en cours va se faire dans un tableau de char, chaque case du tableau sera une case du labyrinthe (un mur compte comme une case).

Element Caractère
Mur #
Joueur @
Joueur sur une destination +
Caisse $
Caisse sur une destination *
Destination .
Sol (Espace)

Par exemple, le niveau suivant:

capture-decran-2017-01-20-23-15-43

Sera représenté par le tableau suivant:

// Template de base pour tout programme Kitco:
// Nécessaire pour l'environnement Kitco
#include "kitco.h"

#define NB_LIGNES_NIVEAUX 8
#define NB_COLONNES_NIVEAUX 4

char niveau[NB_LIGNES_NIVEAUX][NB_COLONNES_NIVEAUX] = 
{ {'M','M','M','M'},
  {'M','@','.','M'},
  {'M','$',' ','M'},
  {'M',' ',' ','M'},
  {'M',' ','$','M'},
  {'M','.',' ','M'},
  {'M',' ',' ','M'},
  {'M','M','M','M'}};

// La partie Setup concerne ce qui va être exécuté au démarrage de Kitco
void setup() {
...

On peut donc alors écrire la fonction qui dessine le niveau:

...
 {'M','.',' ','M'},
 {'M',' ',' ','M'},
 {'M','M','M','M'}};

void afficheGraphismes() {

   // on efface l'écran
   effacerEcran(BLANC);

   // On affiche chacune des cases du niveau
   for (int ligne=0;ligne<NB_LIGNES_NIVEAUX;ligne++) {
     for (int colonne=0;colonne<NB_COLONNES_NIVEAUX;colonne++) {
       switch (niveau[ligne][colonne]) {
         case 'M': 
           dessineMur(ligne,colonne);
           break;
         case '@':
           dessineJoueur(ligne,colonne);
           break;
         case '+':
           dessineJoueurDestination(ligne,colonne);
           break;
         case '$':
           dessineCaisse(ligne,colonne);
           break;
         case '*':
           dessineCaisseDestination(ligne,colonne);
           break;
         case '.':
           dessineDestination(ligne,colonne);
           break;
         case ' ':
           // pour une case vide, on ne dessine rien
           break;
         default:
           break; 
         }
      }
   }
   
   // on affiche le résultat
   rafraichirEcran();
}


// La partie Setup concerne ce qui va être exécuté au démarrage de Kitco
void setup() {
...

Maintenant, nous allons devoir devoir choisir comment dessiner les différents types de cases (bonhomme, caisse, destination, mur, etc…). Déjà la taille d’une case: trop petite, cela sera peu lisible et trop grand, cela nous empêcherait d’afficher des niveaux trop grands… L’écran de la Kitco fait 84×48, avec des cases de 4pixels de côté, cela ferait un niveau pouvant atteindre 21×12 cases. Il occupera 252 octets de mémoire vive (21 multuplié par 12 car une case fait un caractère donc un octet).

Je vous propose de représenter les cases ainsi:

capture-decran-2017-01-22-10-22-48De gauche à droite: un mur, le joueur, le joueur sur une case destination, une caisse, une caisse sur une case destination, et une case de destination. Pour les cases vides, on laissera vide 🙂 .

On peut maintenant écrire les fonctions qu’on a appelées un peu plus haut: (à partir de la fonction creerRectangle de la librairie Kitco (pas besoin de la ré-écrire) :

creerRectangle(int x0, int y0, int x1, int y1, boolean fill, boolean bw)

Cette fonction trace un rectangle entre les points (x0,y0) et (x1,y1) de la couleur bw (NOIR ou BLANC) templi ou non (paramètre fill).

on utilisera aussi setPixel(int x, int y, boolean bw) qui affiche un pixel sur le point (x,y)

...
 {'M',' ',' ','M'},
 {'M','M','M','M'}};

//
// LES GRAPHISMES
//
void dessineMur(int ligne, int colonne) {
  creerRectangle(colonne*4,ligne*4,colonne*4+4,ligne*4+3,1,NOIR);
}
void dessineJoueur(int ligne, int colonne) {
  creerRectangle(colonne*4+1,ligne*4,colonne*4+2,ligne*4+3,1,NOIR);
  creerRectangle(colonne*4,ligne*4+1,colonne*4+3,ligne*4+2,1,NOIR);
  creerRectangle(colonne*4+1,ligne*4+1,colonne*4+2,ligne*4+2,1,BLANC);
}
void dessineJoueurDestination(int ligne, int colonne) {
  creerRectangle(colonne*4+1,ligne*4,colonne*4+2,ligne*4+3,1,NOIR);
  creerRectangle(colonne*4,ligne*4+1,colonne*4+3,ligne*4+2,1,NOIR);
}
void dessineCaisse(int ligne, int colonne) {
  creerRectangle(colonne*4,ligne*4,colonne*4+3,ligne*4+3,0,NOIR);
}
void dessineCaisseDestination(int ligne, int colonne) {
  creerRectangle(colonne*4,ligne*4,colonne*4+3,ligne*4+3,0,NOIR);
  setPixel(colonne*4+2,ligne*4+1,NOIR);
  setPixel(colonne*4+1,ligne*4+2,NOIR);
}
void dessineDestination(int ligne, int colonne) {
  creerRectangle(colonne*4+1,ligne*4+1,colonne*4+3,ligne*4+2,1,NOIR);
}

void afficheGraphismes() {
...

On peut déjà tester le résultat de l’affichage d’un niveau. Le code source de ce niveau est disponible dans le menu:

Menu Fichier/Exemples/Kitco/sokoban/sokobanEtape1

Le résultat sur la Kitco:

sokoban1.jpg

La suite, c’est par ici: Sokoban – Etape 2