Image et map

General

Bulleo

6 months ago

Bonjour, je me demande comment ajouter des images et créer une map.

Pour être plus claire au sujet de la map , je voudrais savoir comment créer une map comme pico monster ou UFO race et ne pas me simplement limiter à l'écran comme dans un casse-brique ou un pong.

Merci d'avance.

deeph

NEW 6 months ago

Bon je comptais faire un jour un tutoriel complet là dessus, mais en attendant je te montre un petit exemple rapide basé sur picomon et qui resservira sans doute plus tard.

La technique qu'on utilise pour afficher ce type de cartes à l'écran c'est le tilemapping : en gros tu as une carte orthonormée pour laquelle chaque valeur est associée à une petite image (appellée tile en anglais, qu'on peut traduire par tuile en français).

Avant tout il faut préparer ton jeu de tuiles (tileset en anglais) ; donc choisir la largeur/hauteur des tuiles (généralement on part sur du 8*8 car ça s'adapte bien à la résolution de l'écran en mode half res), dessiner tes tuiles, puis les empiler verticalement sur une même image (c'est nécessaire pour la fonction setFrame()). Afin d'optimiser la taille des données de tes tuiles après conversion, je te conseil aussi d'opter pour le mode indexé (= avec palette donc seulement 16 couleurs).

Pour cet exemple j'ai donc choisi cette image :

Lorsque ton tileset est prêt, tu peux commencer à dessiner ta carte, et pour ça je te conseil d'utiliser Tiled, puis d'exporter ta carte en .csv.

Ensuite concernant la conversion de ton tileset en code, le plus simple est de recourir à cet outil : https://gamebuino.com/fr/creations/png-to-code (mode = index, frame loop = 0, numbers of frame = 4 dans cet exemple, et attention à ne pas lui fournir autre chose que du .png car apparement il ne fonctionne pas toujours très bien avec les .bmp).

Une fois que tout ça est fait, il suffit de tout regrouper et d'ajouter quelques lignes de code pour réaliser un tilemapper :

#include <Gamebuino-Meta.h>

// largeur & hauteur des tuiles en pixel
#define TUILE_LARGEUR 8
#define TUILE_HAUTEUR 8

// données des tuiles, obtenues à partir de https://gamebuino.com/fr/creations/png-to-code
const uint8_t tuiles_donnees[] = {
  8, 8, // hauteur et largeur des tuiles
  4, 0, // nombre de tuiles (codé sur 2 octets en little-endian)
  0,    // nombre d'animations (0 = aucune)
  0xff, // couleur transparente (0xff = 255 > 0x0f = 15 donc pas de transparence)
  1,    // mode de couleur (1 = indexé = avec palette)
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xbf, 0xbf, 0xbf, 0xbf,
  0x3b, 0x3f, 0x3b, 0x3f,
  0xf3, 0xff, 0xf3, 0xff,
  0xff, 0xff, 0xff, 0xff,
  0xbf, 0xbf, 0xbf, 0xbf,
  0x3b, 0x3f, 0x3b, 0x3f,
  0xf3, 0xff, 0xf3, 0xff,
  0xf0, 0x0f, 0xf0, 0x0f,
  0x07, 0x70, 0x07, 0x70,
  0x00, 0x00, 0x00, 0x00,
  0x05, 0x50, 0x05, 0x50,
  0x06, 0x60, 0x06, 0x60,
  0x06, 0x60, 0x06, 0x60,
  0x07, 0x70, 0x07, 0x70,
  0x60, 0x06, 0x60, 0x06,
  0xff, 0xf3, 0xbf, 0xff,
  0xff, 0x33, 0xb3, 0xff,
  0xff, 0xb3, 0x3b, 0xff,
  0xf3, 0xb3, 0x3b, 0x3f,
  0xfb, 0x33, 0x33, 0xbf,
  0x3b, 0x33, 0x33, 0xb3,
  0xf3, 0xb3, 0x3b, 0x3f,
  0xff, 0x33, 0x33, 0xff
};
Image tuiles = Image(tuiles_donnees);

// données de la carte, obtenues à partir de Tiled (https://www.mapeditor.org/), en exportant en .csv et en prennant garde à ajouter les virgules en fin de ligne si nécessaire
const uint8_t carte[] = {
  0, 0, 2, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 1, 2, 3, 3,
  0, 0, 2, 1, 1, 1, 1, 1, 2, 0, 0, 2, 1, 1, 1, 1, 1, 2, 3, 3,
  0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 3, 3,
  0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 3,
  0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 0, 2, 3, 3,
  0, 0, 2, 0, 0, 3, 0, 0, 3, 0, 0, 3, 0, 0, 0, 0, 0, 2, 1, 3,
  3, 0, 2, 0, 3, 0, 0, 0, 3, 0, 3, 3, 3, 3, 3, 0, 0, 2, 1, 3,
  2, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 2, 3, 3,
  0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 3, 3, 0, 0, 3, 3, 3, 2, 3, 3,
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3,
  2, 2, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 2, 3, 3,
  3, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 2, 3, 3,
  3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 2, 3, 1,
  0, 0, 2, 3, 3, 0, 1, 1, 1, 1, 1, 0, 0, 3, 3, 0, 0, 2, 3, 3,
  0, 3, 2, 3, 3, 0, 3, 3, 1, 1, 1, 1, 1, 3, 3, 0, 0, 2, 2, 2,
  3, 0, 2, 3, 3, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 3,
  0, 0, 2, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 0, 0, 0, 0, 3, 3,
  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0,
  3, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 3, 0,
  3, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 3, 3, 3
};

// variables pour retenir les coordonnées de la caméra (= portion de la carte que l'on souhaite afficher), ainsi que la largeur et hauteur de la carte (20*20 tuiles ici)
uint8_t camera_x = 0, camera_y = 0, carte_largeur = 20, carte_hauteur = 20;

void setup() {
  gb.begin();
}

void loop() {
  // ici on calcul les coordonnées de la carte, en prennant garde à ne pas sortir des limites de la carte (en multipliant par le résultat de tests booléens, c'est-à-dire 0 ou 1)
  camera_x += -gb.buttons.repeat(BUTTON_LEFT, 1) * (camera_x > 0) + gb.buttons.repeat(BUTTON_RIGHT, 1) * (camera_x < (carte_largeur * TUILE_LARGEUR - gb.display.width()));
  camera_y += -gb.buttons.repeat(BUTTON_UP, 1) * (camera_y > 0) + gb.buttons.repeat(BUTTON_DOWN, 1) * (camera_y < (carte_hauteur * TUILE_HAUTEUR - gb.display.height()));

  // le tilemapper en lui même tient dans ces quelques lignes : il faut scanner de gauche à droite et de bas en haut notre carte et afficher les tuiles qui correspondent
  for (uint8_t x = 0; x <= gb.display.width() / TUILE_LARGEUR + 1; x++) {
    for (uint8_t y = 0; y <= gb.display.height() / TUILE_HAUTEUR + 1; y++) {
      // on cherche d'abord à savoir grossièrement vis-à-vis de la carte quelle tuile se trouve aux coordonnées de la caméra
      tuiles.setFrame(carte[(camera_y / TUILE_HAUTEUR + y) * carte_largeur + (camera_x / TUILE_LARGEUR + x)]);
      /* ensuite on calcul les coordonnées de la tuile à l'écran (comme il s'agit d'un "smooth scrolling", en gros "déplacement doux" pixel par pixel,
      les tuiles peuvent être en partie en dehors de l'écran donc avec des coordonnées négative, d'où l'utilisation cette fois-ci d'entiers signés)
      le smooth scrolling en lui même est obtenu ici en ajoutant le reste d'une division (modulo = %)*/
      int8_t tuile_x = x * TUILE_LARGEUR - camera_x % TUILE_LARGEUR;
      int8_t tuile_y = y * TUILE_HAUTEUR - camera_y % TUILE_HAUTEUR;
      // on affiche la tuile sélectionnée aux bonnes coordonnées
      gb.display.drawImage(tuile_x, tuile_y, tuiles);
    }
  }

  // pour éventuellement debugger on affiche les coordonnées de la caméra en haut à gauche
  gb.display.setColor(WHITE);
  gb.display.setCursor(0, 0);
  gb.display.println(camera_x);
  gb.display.println(camera_y);

  while (!gb.update());
}

Et voilà ce qu'on obtient sur la gamebuino :

Je ne suis pas trop rentré dans les détails donc n'hésite pas à poser des questions. Je te conseil aussi de lire le tuto sur les images qui explique aussi pas mal de choses à ce sujet.

Voici les fichiers de cet exemple : tilemapper.zip

jicehel

NEW 6 months ago

Super Deeph et j'espère que tu auras le temps de faire une série de tutos avec des étapes pour compliquer les choses progressivement. Bulleo, si ça t'aide, tu peux aussi regarder le code de mon sokoban: https://gamebuino.com/fr/creations/sokoban-partie-1-preparons-notre-jeu

Je pense (j'espère que ça peut t'aider), c'est une façon de faire parmi d'autre. J'aime beaucoup l'affichage de la carte de Deeph. Dans la série de tuto, tu verras d'autres points, comme la gestion des événements sur la carte de Deeph que tu devras implémenter pour détecter les collisions avec les zones infranchissables, les bords etc... et comme il disait, s'il te manque des infos etc... n'hésites pas à nous poser des questions. Je suis peu dispo en ce moment comme beaucoup avec les fêtes mais bon on te répondra même si ça pend plus longtemps que d'habitude  ;)

Bulleo

NEW 6 months ago

j'ai rapidement regardé les réponses et se ne me semble pas trop complexe. Je vais essayer sa tout de suite. Merci de votre aide ;)

jicehel

NEW 6 months ago

Pas de problème et on a toujours hâte de voir les jeux auxquels vous pensez  ;)  

Bonne programmation