Parachute HD (META)

Parachute hd meta


**Version en cours de réalisation**
  • Reprise du jeu G&W Parachute de Nintendo en 1981.
  • Le joueur contĂ´le la barque afin de la positionner sous les parachutistes afin de les rĂ©cupĂ©rer avant qu’ils ne tombent dans l’eau et se fassent dĂ©vorer par les requins.
  • Le joueur perd une vie Ă  chaque fois qu’un parachutiste tombe Ă  l’eau.

Point sur le développement. Je me suis approprié le squelette de programme de Steph et incorporé les sprites et le fond de Parachute.

J’ai commencé à implémenter le mécanisme du jeu (déplacement du bateau, lancement et déscente des parachutistes, chute dans l’eau et déplacement du noyé et du requin)
Le score, la pause (Appuie sur A ou sur B), la fin de partie.
Il me reste à ajouter quelques sons, les vie bonus lorsque l’on atteind certains scores si on en a perdu, la correction d’un bug d’affichage de “Pause” et “GameOver”
Si je peux, j’ajouterais peut être la gestion des hi-score, un menu, un écran de remerciements, un écran des meilleurs scores

Le programme est quasi fini, si vous voyez des améliorations à y faire, je suis preneur.

See more

1 Like

Cool :). Bon courage pour la suite du dev !

Am looking forward to trying it out.

1 Like

Pas mal le principe de la HD.
L’animation peut être améliorer par rapport à l’original ?
le rameur avec des animations au niveau du visage ?
des couleurs différentes entre l’hélico, les parachutistes et la barque.
une petite animation de l’eau et des feuilles des palmiers ?
à moins que tu veuilles être conforme à l’original…
Je n’ai pas encore bien compris le code pour faire de la HD, je te félicite pour cette prouesse :wink:

Bon développement…

Bonjour et merci Lysandre. Oui, là l’idée c’est vraiment de coller à l’original. Pour le moment, le jeu n’est pas fini. Je vais m’y mettre un peu ce soir. Je vais essayer d’ajouter l’affichage du score avant de me coucher. Donc non, il n’y aura pas d’animation de l’eau ou des feuilles dans cette version.
Par contre les pales de l’hélico vont bouger, il y aura un écran de démarrage et un menu avec lancer le jeu, le rependre, sauvegarder ou consulter les high score et peut être des options plus tard. Un écran de pause est prévu mais ce sera peut être le menu ou l’écran des high score à la place.Après il y aura aussi des miss qui disparaiteront quand on atteint certains score et pareil l’augmentation de la vitesse sera différente de l’original. Après on verra si j’ai oublié quelque chose mais surtout je passerais à un autre. On pourra toujours faire d’autre version plus tard.
Sinon pour la HD, j’utilise la structure faite par Steph, sa structure de programme est très simple et tu n’as pas à rentrer dans la mécanique de la HD, juste à dire quel sprite tu veux afficher. C’est du caviar et tu peux l’utiliser pour beaucoup de type de jeux. De mon côté, je n’ai pas trop de temps et je joue à d’autres jeux qui me bouffent du temps alors je ne vais pas me lancer dans trop de choses différentes avant d’avoir programmé quelques un de mes game & watch préféré, mais je ne les ferais pas tous, comme ça quelqu’un qui veut voir comment ça marche pourra en prendre un des nombreux restant et faire son adaptation du programme avec les bon graphiques en adaptant le code. :wink:

@LYSANDRE pour te resituer le contexte concernant la HD… parce-qu’il faut rendre à Cesar ce qui est à Cesar… et que les références originales se perdent trop souvent dans les nimbes des discussions si elles ne sont pas rappelées correctement in situ.

Le tout premier à nous avoir ouvert les portes de la HD dans cette communauté est Andy (aoneill), avec son article High Resolution without gb.display (qui date du mois de novembre 2018). Cet article fournit les routines magiques pour pouvoir utiliser le contrôleur DMA avec un mécanisme parallèle à double tampons pour le calcul d’un rendu graphique. Cette technique n’utilise pas les routines graphiques fournies par la bilbiothèque officielle avec l’API gb.display, mais directement l’API de bas niveau gb.tft qui établit un pont avec la bibliothèque originale d’Adafruit pour la gestion de l’écran de la META.

Lorsqu’Andy a sorti son article, il y a près d’un an maintenant, je lui ai immédiatement emboîté le pas pour essayer de comprendre la technique qu’il exposait (et à laquelle bien peu se sont intéressés manifestement…). J’ai décortiqué son article et ai eu l’idée de mettre en application ce que j’en avais compris sur un petit exercice qui consiste à effectuer le rendu d’une scène de jeu en travaillant sur l’éclairage de la scène par un jeu d’ombre et de lumière. J’ai alors souhaité en faire profiter la communauté en rédigeant un tutoriel complet sur la technique d’Andy et la réalisation d’un moteur de rendu HD pour la META. Là aussi… peu de personnes se sont vraiment intéressées à ces techniques à en croire le peu de commentaires recueillis… si ce n’est Alban qui a, par la suite, sorti son Project 88.

Il y a quelques mois, j’ai rédigé un autre tutoriel très complet sur la réalisation de jeux de type Platformers en exploitant la HD avec la META. Ce travail n’est, à ce jour, pas terminé… mais devant le manque d’activité flagrant de la communauté, j’ai suspendu ce chantier… et c’est bien dommage. Mais je ne sais pas si je trouverai le courage de le reprendre. Entre temps, je suis passé à bien d’autres choses de mon côté… toujours dans le domaine de la programmation sur microcontrôleurs.

Et puis @jicehel est revenu à la charge avec son projet de rélisation de jeux de type Game & Watch de Nintendo, nécessitant la HD … puisque les 80x64 pixels offerts par l’API gb.display ne sont pas suffisants pour ce type de jeu. Je lui ai donc proposé un embryon de code lui permettant de s’attaquer à ce type de jeu, en mettant en place tout ce qui concerne la technique de rendu graphique et la manière d’exploiter une spritesheet pour en extraire les postures adéquates des différents personnages à l’oeuvre dans le jeu. Ce code est disponible sur mon GitHub, et tu peux t’en inspirer librement pour tes propres réalisations. Comme le dit @jicehel, il a peu de temps… et un coup de main pour l’implémentation de quelques Game & Watch serait le bienvenu :wink:

Je tenais à rappeler cet historique, parce-que la communauté ne doit pas oublier que si, aujourd’hui, certains sont en mesure d’exploiter la HD sur la Gamebuino META, c’est bien grâce à Andy ! Et je trouve que, d’une manière générale, les contributeurs ont ici souvent tendance à oublier de citer leurs sources en donnant des références précises sur les travaux antérieurs qui leur ont permis d’aboutir…

1 Like

Dommage que la discussion initiale ait été clôturée, j’aurais pu la compléter directement… alors tant pis, je le fais ici :slight_smile:

En fait, je souhaitais revenir sur un point crucial que j’ai complètement oublié d’évoquer dans ma proposition initiale. L’usage de l’API gb.tft avec la technique d’Andy n’est nécessaire que si l’on souhaite exploiter pleinement l’espace colorimétrique RGB565 avec une résolution de 160x128, du fait de la limitation mémoire de la META.

En effet, il est tout à fait possible de s’en tenir à l’usage standard de l’API gb.display dans la mesure où on se restreint à un espace colorimétrique de 16 couleurs. Il suffit pour cela d’utiliser le mode d’affichage spécifique DISPLAY_MODE_INDEX de la META, qui correspond à une résolution de 160x128 en 16 couleurs indexées. Ce paramétrage doit être fixé dans le fichier config-gamebuino.h accompagnant le croquis de l’application avec la ligne suivante :

#define DISPLAY_MODE DISPLAY_MODE_INDEX

J’ai mis à jour mon dépôt GitHub de démo qui intègre désormais les deux approches :wink:

Désolé, je ne pensais pas que tu souhaiterais ajouter quelque chose comme tu avais déjà livré le squelette demandé. J’ai remis ton texte dans l’autre post. Normalement, je pense que tu as les droits pour ouvrir et fermer un sujet. J’ai fermé l’autre sujet comme il était résolu et qu’il n’y avait pas à priori de choses à y ajouter. Je ne sais pas si c’est utile de fermer les sujets. C’était aussi pour tester la fonctionnalité que j’ai découverte en voulant modifier le titre pour y faire figurer que la demande était résolue.
Tiens pendant que tu es là, je ne l’ai pas fait mais je vais sans doute afficher le score en allumant / éteignant des sprites représentant les ségments (comme pour les afficheurs 7 ségments) mais sinon, si l’on veut afficher un message avec ton moteur, pour toi, quelle serait la solution la plus simple ?

En ce qui concerne le score, dont la construction symbolique est dynamique, je m’appuierais sur une simple spritesheet incluant tous les chiffres nécessaires. Par exemple celle-ci (qu’il faudra adapter à la taille des chiffres que tu souhaites) :

7-segments

Nul besoin de t’embêter à afficher chacun des segments !.. Sauf si l’exercice t’amuse :joy:

En ce qui concerne les messages… tout dépend de leur nature :

  • S’ils sont syntaxiquement construits de manière dynamique, tu devras employer la mĂŞme technique que pour le score et prĂ©voir une spritesheet avec l’alphabet nĂ©cessaire, et ce sera Ă  toi de prĂ©voir une fonction de rendu spĂ©cifique qui prend une chaĂ®ne de caractères en entrĂ©e et qui calcule le rendu graphique de la chaĂ®ne sur le framebuffer (très amusant comme exercice aussi…).
  • S’ils sont prĂ©dĂ©finis, et qu’il n’y en a pas plus que de raison, prĂ©vois simplement un sprite par message :wink:

OK. Je vais regarder. J’insérerais les chiffres sur une des planches actuelles car j’utilise 4 planches déjà: Ecran de titre, le fond, la planche_A et la planche_B.
J’avais ajouté un écran de pause mais là, trop gourmand, il n’y avait plus de mémoire.
Après, il faudrait voir s’il est possible de charger des écrans dans une des images, ça pourrait être pratique d’avoir des images ou des spritesheet qui peuvent changer.
Par exemple, on aurait une image “écran” que l’on chargerait avec la page de titre, l’écran de pause ou celui des scores. Pareil, si l’on avait un jeu qui permettait de choisir quel jeu G&W on voulait lancer, on chargerait l’écran de titre, le fond et les planches correspondantes.
Bon en tous cas, merci pour les pistes, je vais voir ce que je mets en oeuvre.
Il faudrait quand même se trouver une solution sympa je pense pour pouvoir “générer” les sprites à afficher pour du texte, ça pourrait servir pour d’autres types de jeux, mais bon ce n’est pas utile dans mon cas. On verra bien quand le besoin se présentera. Pour le moment, je ne suis pas bloqué, je dois juste prendre un peu de temps pour bien finir ce jeu et après je m’attaquerait à Fire, puis comme tu as déjà fait une partie du boulot, je pense que je ferais Donkey Kong Jr. Bon ça fait déjà un bon petit programme, je vais essayer de faire ça avant d’en rajouter d’autres :wink:

Pour cette histoire de sujet clos, effectivement je ne trouve pas qu’il soit très utile de fermer les sujets personnellement. Meme si ta demande ou ta question a trouvé une réponse ça peut etre bien de laisser la possibilité à la discussion d’évoluer ;), d’autres peuvent se servir du sujet pour poser leur propre question, la réponse peut évoluer, etc…

Bon courage pour la suite de ton dev en tout cas, ça a l’air chouette !

Oui après réflexion, je suis d’accord, j’ai déverrouillé. Ce n’est en effet pas utile.

1 Like

Encore une question. Peut-on changer le mode d’affichage en cours dynamiquement pour passer du mode Haute définition à Basse résolution quand on en a besoin (Par exemple pour afficher un écran de remerciements ou un tableau des scores sans trop consommer de mémoire et en plus, autant je peux avoir un écran à charger pour les remerciements mais je dois trouver un moyen de gagner de la mémoire car j’occupe déjà tout, autant je ne peux pas prévoir de sprites pour le tableau des scores, alors je pense au plus simple qui serait d’utiliser les bons vieux print). A moins qu’il y ait d’autres solutions auxquelles je ne pense pas.

Non… Tu dois, dès le départ, déterminer quel sera le mode d’affichage avec lequel tu souhaites travailler.

  • Soit tu utilises l’API standard gb.display en haute dĂ©finition (160x128) (en dĂ©finissant la macro DISPLAY_MODE avec la valeur DISPLAY_MODE_INDEXED dans le fichier config-gamebuino.h). Et Ă  ce moment lĂ , tu peux bĂ©nĂ©ficier de toutes les fonctions prĂ©dĂ©finies par cette API comme gb.display.drawImage(), gb.display.print(), etc. Mais tu es limitĂ© Ă  16 couleurs au total.

  • Soit tu tournes le dos Ă  l’ensemble de cette boĂ®te Ă  outils et tu te retrousses les manches pour effectuer tes tracĂ©s bit par bit sur des framebuffers partiels (les fameuses tranches horizontales qui sont calculĂ©es une Ă  une pour effectuer le rendu global de la surface de l’écran) avec l’API de bas niveau gb.tft. Mais dans ce cas, tu profites des 65 536 couleurs que t’offre l’espace colorimĂ©trique RGB565.

Dans ton cas, la première solution est sans doute la plus simple, d’autant plus qu’avec 16 couleurs t’es déjà laaaarge pour faire du Game & Watch ! Par contre, si tu rencontres des limitations mémoire, il faudra optimiser tes ressources graphiques pour limiter au maximum l’occupation de la RAM au moment d’invoquer la fonction gb.display.drawImage(). Tu noteras au passage, que dans le code que je t’ai proposé, je n’instancie les objets Image qu’à l’intérieur de la fonction qui effectue le rendu de l’élément graphique concerné… De cette manière, l’objet Image n’occupe de la place en RAM que pendant la durée de l’exécution de la fonction ! En effet, tous tes éléments graphiques sont déclarés comme des tableaux d’entiers constants. Ils seront donc hébergés dans la mémoire Flash. C’est seulement au moment où tu crées une instance de Image que les données sont copiée en RAM. D’où l’intérêt de ne pas les faire subsister trop longtemps, sinon tu atteindras rapidement la limite de la mémoire disponible…

En jonglant correctement avec l’hébergement volatile de tes ressources graphiques en RAM, tu devrais pouvoir gérer tous les écrans que tu souhaites sans problème !

En aucun cas il ne faut déclarer tes instances de Image comme des variables globales !!!..

J’espère que je suis assez clair dans mes explications :blush:

Si tu ne l’as pas déjà fait, regarde attentivement le code que j’ai ajouté sur mon GitHub, dans le dossier with-gb-display. Si tu l’as déjà fait, relis-le avec plus d’attention :wink:

OK, bon de toute façon, je continue un peu à coder ce soir et je posterais mon code. Comme ça tu pourras jeter un œil si tu as le temps et me dire si je peux améliorer des choses.
Pour le moment, du coup, je vais essayer de faire le jeu simplement et on verra après si on peut améliorer avec tout ceux qui veulent regarder et qui voudront m’aider à faire mieux. Dans un premier temps, il faut que je termine cette partie du code (le score) et ajouter la fin de partie et le regain de vie a certains scores pour finir le jeu avant de partager le code pour l’améliorer.

OK, version source MAJ sur Github - je fais une MAJ de la création avant d’aller dormir.
La version inclue la gestion de la Pause par A ou B, l’affichage du score et du Game Over.
Bon, il y a un petit bug sur la procédure d’affichage de Pause et GameOver mais pas très gênant et comme il est tard je rechercherais la prochaine fois sauf si quelqu’un trouve entre temps.

Voilà, si vous regardez le code et voyez des améliorations à faire, je prends… :wink:

Hello @jicehel ! Et désolé de te répondre si tard…

Bon, globalement c’est pas mal du tout ! Le rendu est plutôt satisfaisant :wink:

Pour pinailler un peu … je trouve que tu te compliques un peu la vie au niveau du code et qu’on peut le simplifier… mais c’est déjà très bien que tu aies réussi à surmonter les difficultés (surtout d’ordre mathématiques et logiques) liées au calcul de rendu sur les framebuffers partiels !

Je ne vais pas reprendre tout ton code, mais je voudrais néanmoins t’apporter un éclairage sur le bug d’affichage des messages “PAUSE” et “GAME OVER”.

Il a fallu que je fasse un peu de reverse-engineering sur tes spritesheets (car les assets de ton dépôt ne correspondent pas tout à fait aux tableaux d’entiers 16-bits que tu utilises dans ton code). J’me suis fait un p’tit script rapidos pour reconstruire l’image originale que tu as transcodée pour obtenir ton tableau SPRITESHEET_A, que voici (agrandie 2x) :

Pour l’affichage des textes, la méthode de calcul du rendu diffère légèrement de celle utilisée pour isoler les autres sprites. En effet, les sprites sont déjà positionnés sur la spritesheet à l’endroit où ils sont censés apparaître à l’écran. Mais ça n’est pas le cas pour les textes… d’où la nécessité d’appliquer une autre méthode de calcul. Pour cela, j’ai écrit une nouvelle fonction drawText() en modifiant légèrement ce que j’avais fait pour la fonction drawSprite(). Cette nouvelle fonction drawText() vient remplacer ta fonction drawSpriteXY() (que tu peux fouttre à la poubelle du coup :joy:).

En premier lieu, j’ai relevé une petite erreur de positionnement (en y) de ton texte Sprite_pause. Tu peux corriger la ligne 124 ainsi :

Sprite Sprite_pause = { SC_A, 1, 9, 28, 7 }; // y = 9 et pas 8...

Ensuite, modifie la ligne 445 ainsi :

// remplace :
drawSpriteXY(Sprite_gameOver, sliceY, buffer, 53, 60);
// par :
drawText(Sprite_gameOver, sliceY, buffer, 53, 60);

MĂŞme chose Ă  la ligne 456 :

// remplace :
drawSpriteXY(Sprite_pause, sliceY, buffer, 66, 60);
// par :
drawText(Sprite_pause, sliceY, buffer, 66, 60);

Puis remplace ta fonction drawSpriteXY() Ă  la ligne 577 par la nouvelle fonction drawText() :

void drawText(Sprite sprite, uint8_t sliceY, uint16_t* buffer, uint8_t x, uint8_t y) {
  if (sliceY < y + sprite.h && y < sliceY + SLICE_HEIGHT) {
    uint8_t xmin = x;
    uint8_t xmax = x + sprite.w - 1;
    uint8_t ymin = y < sliceY ? sliceY : y;
    uint8_t ymax = y + sprite.h >= sliceY + SLICE_HEIGHT ? sliceY + SLICE_HEIGHT - 1 : y + sprite.h - 1;

    uint8_t  px, py, sx, sy;
    uint16_t color;

    for (py = ymin; py <= ymax; py++) {
      sy = py - y + sprite.y;
      for (px = xmin; px <= xmax; px++) {
        sx = px - xmin + sprite.x;
        color = SPRITESHEET_A[sx + sy * SCREEN_WIDTH];
        if (color != TRANS_COLOR) {
          buffer[px + (py - sliceY) * SCREEN_WIDTH] = color;
        }
      }
    }
  }
}

Tu vois que le calcul est légèrement différent pour aller chercher les bons pixels sur la spritesheet.

Tu peux recompiler et exécuter ton code sur ta META, tu verras que cette fois, les textes “PAUSE” et “GAME OVER” sont correctement reproduits :wink:

D’une manière plus générale sur le rendu global du jeu, plutôt que de multiplier les “écrans” et les personnalisations ostensibles, j’aurais personnellement préféré que tu essaies de reproduire le plus fidèlement possible la planche LCD originale :

Fais du Game & Watch jusqu’au bout :wink:

Mais globalement, c’est un bon résultat pour une première virée dans la dark side of gb.tft…

Cool. Pour la planche unique c était compliqué car les rectangles qui entouraient les sprites se recouvraient alors j aurais pu les réduire mais je voulais garder les sprites le plus gros possible

Merci pour la correction de la fonction. J aurais dĂ» y passer du temps je pense et pour le moment je ne m y suis pas encore remis.

Je fais la man et j ai pensé à une solution: recréer la fonction print en intégrant les caractères et quelques ponctuations. Ca permettrait de générer facilement l ecran de menu et de remerciements. Une fois le jeu fini dans sa première version, j essayerais.
Merci pour ton aide et n hésites surtout pas pour les conseils comme de toute façon je passerais plus de temps sur ce premier g&w les prochains allant réutiliser bcp des mêmes fonctions

Je t’avais déjà apporté une réponse concernant la possibilité d’utiliser une spritesheet unique…

Pour les sprites dont l’enveloppe rectangulaire a une intersection non vide avec celles de ses voisins, il suffisait simplement d’utiliser une autre couleur pour les distinguer. Dans tous les cas, au moment du rendu, le code couleur à utiliser pour écrire dans le framebuffer sera le noir 0x0000, donc tu peux te permettre d’ajouter une propriété à la structure Sprite qui correspond à la couleur qui le caractérise sur la spritesheet de manière à pouvoir l’identifier facilement au moment de sa copie lors du calcul de rendu.

Quant à la fonction de rendu d’une chaîne de caractères, c’est un bon exercice auquel se frotter :wink: