~ S'évader de la banalité... Et entrer dans l'imaginaire ! ~
 
AccueilGuelnika, le site de E-m !S'enregistrerConnexion

Partagez | 
 

 Faire des jeux sur DS

Aller en bas 
AuteurMessage
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Faire des jeux sur DS   Mer 28 Fév 2018, 22:22

Salut à tous. Vous le savez déjà, je fais des programmes et des jeux sur Nintendo DS. L'idée, c'est que tout ce que j'ai fait devrait permettre à d'autres d'en faire autant. J'ai commencé une repasse sur mon code pour montrer petit à petit comment se servir de mes outils et de mon moteur de jeu.

Pour ça, il vous faudra d'abord le kit de développement non-officiel pour NDS et GBA. Ils ont fait du bon travail et il y a un installeur automatique pour ceux qui travaillent sous Windows.

De mon côté, j'ai préparé une structure d'accueil pour les programmes. Règles de génération des ROMs nds à partir des sources et des données du jeu, les petites bibliothèques supplémentaires pour faire de la musique, etc. Et un un premier programme à faire tourner sur DS. Evidemment, on est sur une machine "bare metal", sans système d'exploitation, donc il y a un peu plus de code d'initialisation qu'à l'habitude, mais le fait de créer un objet "Engine" fait déjà une grande part du travail.

Code:

void setactive() {
    FileDataReader fd("efs:/sndtrk.xm");
    ntxm9->stop();
    u16 err = ntxm9->load(&fd);
    ge.setWindow(active);
    if (err!=0) iprintf("ntxm says %x\n",err);
}
Un premier morceau, qui charge un morceau de musique (on en trouve d'autres du genre sur modarchive.org). Il sera joué sur le processeur secondaire de la console, l'ARM7. L'objet ntxm9 nous permettra de transmettre des commandes du genre "passe moi la fanfare de fin de niveau" ou "joue un bruit d'explosion" au fil du jeu.

Je propose deux manière d'interagir avec les boutons et l'écran tactile de la console: l'un pour la partie "action" du jeu (pas encore dans le tuto), et l'autre qui me sert pour les éditeurs: ge.setWindow() a défini notre objet window comme étant l'activité actuelle, donc le moteur appellera la fonction ci-dessous chaque fois qu'on pousse sur un des boutons.
Code:

bool handle(uint& keys, Event evt) {
    if (keys & KEY_A) {
      ntxm9->play();
    }
    if (keys & KEY_Y) {
      ntxm9->stop();
    }
    return true;
}

Allez, la prochaine fois je vous raconterai comment mettre des images à l'écran
Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Re: Faire des jeux sur DS   Sam 03 Mar 2018, 17:05

Bon, avant de voir comment le moteur 'GEDS' peut charger des images dans la mémoire vidéo de la Nintendo DS, il faut que je vous explique un peu comment son processeur graphique construit les images que l'on voit à l'écran. J'utilise le mode "texte", ici, où les images sont composées d'élément de 8x8 pixels appelés "tiles" (prononcez 'taïlesz') que l'on dispose sur une grille.

Vous avez tous déjà utilisé un éditeur de donjons RPG où l'on travaille carré par carré (je crois qu'on dis volontiers des 'chips' ?) plutôt que de mettre un arbre ou une maison d'un coup. Le mode texte de la DS va un cran plus loin: la mémoire de la machine elle-même est découpée en une région pour retenir des pavés de 8x8 (le 'tileset') et une région pour indiquer quel pavé montrer à quel endroit (la 'map' de l'écran, couvrant généralement 256x256 pixels pour la DS). Parfois, on mettra le même tile à plusieurs endroit de l'écran (en inscrivant juste son numéro dans plusieurs cases de la map), et parfois un tile ne sera pas repris (pour l'instant). C'est une technique a peu près aussi vieille que les machines 8-bit et qui a perduré pendant toute la période 16-bit (mais ça, c'est une autre histoire). Ce qui a changé au fil du temps, c'est le nombre de couleurs autorisées par tile (de 3 pour la NES à 255 pour la NDS) et le nombre de calques que l'on peut superposer pour obtenir l'image souhaitée (jusqu'à 4 sur la NDS).

Les fichiers .spr créés par le SpriteEditor pour DS sont principalement une sauvegarde du contenu de la mémoire vidéo tel qu'on voudrait l'avoir pendant le jeu. Du coup, il n'y a vraiment pas grand-chose à faire pour pouvoir les importer dans son programme.
Code:

  SpriteRam myRam(WIDGETS_CHARSET(512));
  SpriteSet mySet(&myRam, BG_PALETTE);

  mySet.Load("efs:/bg.spr");
Et voilà. quelques précisions pour dire au moteur de jeu où mettre les graphismes (ici, sur l'écran "du haut", en laissant 512 emplacement pour une police de caractère et pour les 'maps' des différents calques) et où mettre la palette de couleur présente dans le fichier .spr (également dans la mémoire de palette de l'écran supérieur). La classe SpriteSet du moteur de jeu s'occupe de manipuler le fichier et d'en reconnaître le format. On pourrait aussi prendre le contrôle de toute la mémoire vidéo en utilisant directement myRam(BG_GFX), mais c'est un peu moins confortable pour la suite.

Bon, malheureusement, avoir des graphismes en mémoire ne suffit pas pour les avoir à l'écran. La démo n°2 doit aussi configurer la puce graphique pour qu'elle utilise nos données et remplir la grille/map d'un des calques.

Code:

REG_DISPCNT|=DISPLAY_BG2_ACTIVE;
REG_BG2CNT=BG_MAP_BASE(GEBGROUND)|BG_TILE_BASE(0)|BG_COLOR_256;
La configuration, on va régler ça en programmant directement les registres de la puce graphique. C'est tellement facile sur DS Wink. J'active le bit correspondant au calque n° 2 (j'l'aime bien, celui-là) dans le contrôle principal de l'écran (REGister_DISPlayCoNTrol), puis je donne les paramètres de ce calque dans son registre à lui: les données des tiles seront interprétées comme ayant 256 couleurs, quelle grille utiliser comme map, et si je veux ajouter automatiquement un décalage à tous les numéros de tiles de la map (BG_TILE_BASE) par rapport à la position dans la mémoire du tileset (ce que je ne fais pas ici).

La bibliothèque 'libgeds' donne des paires de noms à différentes grilles: un nom pour la configuration de BG_MAP_BASE, et un nom pour le tableau correspondant dans la mémoire vidéo (WIDGETS_BACKGROUND). Du coup avec la configuration qu'on vient de faire, on peut changer le pavé en haut à gauche de l'écran en écrivant dans WIDGETS_BACKGROUND[0]. Dans celui en haut à droite avec WIDGETS_BACKGROUND[31] (parce qu'il y a 32x8 dans 256 ^^) et WIDGETS_BACKGROUND[32] sera le pavé juste en-dessous de WIDGETS_BACKGROUND[0]. Et ainsi, ligne après ligne. Bref, avec un peu de sucre et une feuille de papier, vous arriverez rapidement à voir que WIDGETS_BACKGROUND[32*ligne+colonne] vous permet de modifier n'importe quel emplacement de l'écran.

Code:

for (int l=0; l<32; l+=2) {
  for (int b=0; b<8; b+=2) {
    WIDGETS_BACKGROUND[b+l*32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +1 ]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +32]=tile++;
    WIDGETS_BACKGROUND[b+l*32 +33]=tile++;
  }
}
Moi, j'avais envie de montrer l'ensemble des graphismes de mon fichier .spr, tels qu'on les voit dans l'éditeur. Et dans le quart le plus à gauche de l'écran (une zone de 64x192 pixels). Il reste un petit truc à régler: l'éditeur travaille par blocs de 16x16 pixels, pour le confort du graphiste. En interne, un bloc est composé de 4 tiles de 8x8 pixels, agencés eux aussi suivant le mode "une ligne, puis l'autre". Si je veux que les blocs ne se retrouvent pas coupés en 2, je dois respecter cet agencement au moment de remplir la grille:
Code:

/* 0 1
 * 2 3
 */
D'où les boucles qui passent une ligne sur deux et les quatres écritures à WIDGETS_BACKGROUND par itération.

Voilà. Le code est sur github, donc. Avec le fichier .spr (creative common)


N'hésitez pas à me ralentir avec quelques questions si ça va trop vite pour vous.
Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Re: Faire des jeux sur DS   Mer 07 Mar 2018, 21:58

Oh, j'ai un troisième petit tuto, cette fois-ci sur les les sprites. Ça intéresse quelqu'un que je continue ?
Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
Relm
Comant on enleve le vert autoure du hero??? Lv 0,5
Comant on enleve le vert autoure du hero??? Lv 0,5
avatar

Nombre de messages : 40865

MessageSujet: Re: Faire des jeux sur DS   Jeu 15 Mar 2018, 17:55

Je pense que personne va jamais programmer un jeu sur DS ici, malheureusement.
En fait, je pense que personne va jamais faire un jeu tout court, désormais. A part, peut être Linky qui est encore un jeune passionné.

Tu as du remarquer que ce forum est mort, la seule activité est dans le Slack, et 99% n'est pas relié à la création de jeu.

Tu devrais économiser ton temps donc, et publier ces infos sur un site plus actif et accès sur le développement console.

____________
Alex RE a écrit:
C'est comme utiliser une hache pour trancher du pain. Je suis peut-être trop vieux pour ça.
Revenir en haut Aller en bas
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Re: Faire des jeux sur DS   Ven 16 Mar 2018, 00:15

moui, j'avais un peu eu cette impression-là aussi ...
Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
Linky439
E-magination Maker Lv 36
E-magination Maker Lv 36
avatar

Nombre de messages : 2001
Age : 23

MessageSujet: Re: Faire des jeux sur DS   Ven 16 Mar 2018, 23:06

Pour être honnête, je trouve ça intéressant, mais je sais déjà que je n'aurai surement jamais le temps de programmer sur DS. Ceci dit, je trouve l'initiative très intéressante (ne serait-ce que par pur curiosité du fonctionnement de la bête), mais effectivement, je suis pas sur que le forum soit le lieu par excellence Sad

____________
Cliquez pour accéder aux topics dédiés !
   
Revenir en haut Aller en bas
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Re: Faire des jeux sur DS   Ven 06 Avr 2018, 17:50

Un des éléments les plus importants dans un jeu vidéo (2D), ce sont sans doute les sprites. Rien à voir avec une boisson pétillante, il s'agit du terme consacré pour les objets graphiques librement déplaçable à l'écran, y compris  le personnage principal, les adversaires, mais aussi certains power-ups ou des effets spéciaux.

Les sprites ont besoin de données graphiques (des valeurs de couleurs) tout comme les décors, et ces données sont de nouveau constituées de "tiles". On va utiliser surtout des blocs de 16x16 pixels ici (et donc constitués de 2x2 tiles) mais la DS peut en réalité utiliser des sprites de 8x8 à 64x64 pisxels (avec quelques restrictions quand-même).

Mettre à jour la mémoire vidéo pour que les sprites s'affichent à l'écran (quels graphismes, quels réglages, etc) est délégué à la classe SpritePage dans la libgeds, et la fonction "sync()" de GuiEngine fera le nécessaire pour mettre à jour les coordonnées en respectant les timings de la puce vidéo (et faire en sorte que ça ne clignote pas, par exemple).

Les SpritePages ajoute un niveau de correspondance entre les identifiants logiques des graphismes (ceux que le développeur utilise, "c'est sur la page 3, deuxième ligne, première colonne) et les emplacement "physiques" dans la mémoire vidéo (42eme bloc sur 256 en mémoire). Bref, le contenu de la SpriteRam est généralement un joyeux chaos résultant des créations et supressions de blocs alors que chaque SpritePage est organisée exactement comme l'utilisateur le décide.

--
< le brol de la SpriteRam -- la SpritePage, aussi organisé que vous >

Code:

class Hero : private UsingSprites {
  NOCOPY(Hero);
  const SpritePage *page;
  unsigned x, y;
  oamno_t oam;
public:
  Hero(const SpritePage *pg) : page(pg), x(128), y(96),
         oam((oamno_t) gResources->allocate(RES_OAM))
  {
    page->setOAM((blockno_t)2, sprites);

  }

  void move(int dx, int dy) {
    x += dx; y += dy;
    iprintf("(%u,%u)", x, y);
    page->changeOAM(sprites + oam, x, y, (blockno_t) 4);
  }
};

Notre petite classe 'Hero' montre tout ce qu'il faut pour avoir un objet mobile:
- se souvenir des coordonnées (le bon mot pour parler de la position à l'écran) actuelles;
- une SpritePage qui sait comment mettre à jour les entrées de la "MAO" (ou Mémoire des Attributs d'Objets -- Object Attribute Memory -- le terme de  Nintendo pour parler des blocs de contrôle des sprites);
- avoir réservé une entrée de MAO et en retenir le numéro.

En disant que notre classe dérive de "UsingSprites", on obtient l'accès au tableau des MAOs (le tableau 'sprites[]') que le moteur de jeu va utiliser pendant la fonction sync(), mais aussi au gestionnaire de ressources (`gResources`) qui nous donne notre numéro de MAO. Du coup, la SpritePage a tout ce qu'il lui faut pour faire son travail.

Code:

void setactive() {
   SpriteRam myRam(WIDGETS_CHARSET(512));
   SpriteSet mySet(&myRam, BG_PALETTE);

   mySet.Load("efs:/bg.spr");
/*+*/ sprSet.Load("efs:/hero.spr");

  // rest of MetaWindow::setActive() as defined in previous tutorial
/*+*/ hero = new Hero(sprSet.getpage(PAGE0));
}
Charger les graphismes des sprites en mémoire vidéo ressemble très fort à ce qu'on a déjà fait pour les décors dans le tutoriel précédent. Sauf que cette fois, il faut s'assurer que les objets "SpriteSet" et "SpriteRam" resteront 'en vie' au moins aussi longtemps que notre Hero (qui les utilisera à travers la SpritePage). Du coup, on en fait des membres de la MetaWindow, plutôt que des variables temporaires. Ça signifie aussi qu'il nous faut attendre que les données soient chargées avant de pouvoir créer notre Héro.

Puis il n'y a plus qu'à tester l'état de la croix directionnelle (et les transmettre par des appels à la fonction 'move()') pour pouvoir déplacer le personnage en réaction aux mouvements imprimés par le joueur. Bon, ne vous attendez pas à quelque-chose de fluide ici: j'utilise toujours l'interface utilisateur prévue pour les éditeurs du projet "GEDS" qui ne produit un 'évèment DPAD' que lorsqu'on appuie sur une nouvelle direction. On arrangera ça la semaine prochaine avec les Animators.

Code:

if (keys & KEY_UP) {
  hero->move(0, -4);
}
if (keys & KEY_DOWN) {
  hero->move(0, 4);
}
if (keys & KEY_LEFT) {
  hero->move(-4, 0);
}
if (keys & KEY_RIGHT) {
  hero->move(4, 0);
}

Les détails sont sur github, comme toujours.

Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
PypeBros
Petit Maker Lv 3
Petit Maker Lv 3
avatar

Nombre de messages : 54
Age : 39

MessageSujet: Re: Faire des jeux sur DS   Ven 06 Avr 2018, 17:53

Bon, il est temps de vous montrer ce que libgeds peut faire pour ceux qui n'ont pas le C++ dans le sang. Charger des fichiers, définir des animations, positionner les ennemis dans le niveau, tout ça peut être fait à partir de commandes dans des scripts texte lus et transformés en objets C++ par la bibliothèque.

Je vais commencer par un sous-script qui décrit le comportement d'un personnage. On va commencer très simple, avec une seule animation, et toujours le même comportement: ne pas bouger. Voici donc "xdad.cmd"
Code:

# this is xdad.cmd behaviour description
anim1 0 {
  spr0 4
  delay 3
  spr0 5
  delay 3
  spr0 6
  delay 3
  spr0 7
  delay 3
  spr0 8
  delay 3
  spr0 9
  delay 3
  spr0 a
  delay 3
  spr0 b
  delay 3
  loop
}

state0 :anim1

end

Le bloc 'anim'  donne utilise une page du SpriteSet et construit une animation en indiquant les images à utiliser (dans cette page) et combien de temps attendre entre chaque deux images. On peut ensuite l'attacher à un état, c'est à dire une unité élémentaire de comportement . Bon, évidemment, pour l'instant, avec un seul état, il ne se passera pas grand-chose. C'est un peu notre 'hello world'.

Un fichier comme xdad.cmd, on en créera un par type de personnage (imaginez "goomba.cmd", "koopa.cmd", etc.) Maintenant, il va nous falloir un script qui décrit un niveau. Ce sera demo.cmd, pour nous.
Code:

#demo.cmd, resource management
print "loading tileset"
bg0.load "../bg.spr"
print "loading sprites"
spr.load "../hero.spr":1
On y retrouve des commandes gérant le chargement des fichiers de données qui remplace les SpriteSet::Load().

Code:

#demo.cmd, use 'character' description
input "xdad.cmd"
import state 0
On y retrouve aussi évidemment des commandes pour réutiliser les fichiers comme xdad.cmd, évidemment. la commande 'import state 0' mérite quelques mots d'explication supplémentaires. Pour un vrai personnage de jeu vidéo, il y aura bien sûr de nombreux états... On peut en compter au moins 21 par direction dans Super Mario world, par exemple.

Pourtant, seuls un ou deux de ces états sont nécessaires pour décrire le niveau (commencer tourné vers la droite ou vers la gauche, par exemple, ou éventuellement par une glissade). Geds propose donc un jeu d'identifiants pour l'ensemble des états d'un personnage (tous les états d'un goomba, par exemple) qui sera utilisé dans xdad.cmd, et l'ensemble des états utilisables pour créer des nouveaux objets (un goomba, mario, un koopa rouge ou un koopa vert), qui sera utilisé dans demo.cmd.
Une fois le traitement xdad.cmd terminé, la commande 'import state 0' indique de prendre le premier état de l'ensemble de xdad et d'en faire l'état numéro 0 pour demo.cmd.

Code:

# creating gobs
gob0 :state0 (128, 100)
end
Enfin, on peut constuire un nouveau personnage (le Game object) avec cet état, en donnant les coordonnée du personnage à l'écran.

Comme on le voit sur github, on laisse tomber la classe Hero: il s'agit maintenant d'un GameObject construit et contrôlé directement par la bibliothèque suite au commandes du script.

La classe 'MetaWindow', point de départ de notre démo, a pas mal changé aussi.
Code:

#include <GameWindow.hpp>
class MetaWindow : public DownWindow {
  NOCOPY(MetaWindow);
  Window *active;
  InputReader* reader;
  LoadingWindow loadwin;
  GameWindow gamewin;
public:
  MetaWindow(): active(0),
   reader(0),
   loadwin(&reader),    gamewin(this, &reader, &loadwin)  {
     ntxm9 = new NTXM9(); // for the sound, remember ?
     active = &gamewin;
   }
C'est la classe GameWindow de libgeds qui va créer, charger et traiter les scripts, et assurer la gestion de tous les objets qui en découlent, les animations, les personnages, etc. Sa compagne, LoadingWindow sert lors des changement de niveaux (on y reviendra). Pas grand chose à dire sur le constructeur puisqu'à ce moment-là, les fichiers intégrés à la ROM ne sont pas encore disponibles. L'initialisation, la vraie, se passera dans 'setactive()'.

Code:

   void setactive() {
     FileDataReader fd("efs:/sndtrk.xm");
     reader = new FileReader("efs:/demo.cmd");
     ntxm9->stop();
     u16 err = ntxm9->load(&fd);
     ge.setWindow(active);
     restore(); // just to have the tileset shown again.
     if (err!=0) iprintf("ntxm says %x\n",err);
   }
Par le simple fait de demander au moteur de jeu de passer le contrôle à GameWindow, le chargement commence automatiquement à travers le 'FileReader' (lecteur de fichiers, donc) qu'on vient de construire.
Et c'est tout. A la prochaine fois pour rendre ses déplacement à notre petit père Noël.

Donc, à partir de maintenant je vais me concentrer dans ces tutoriels sur ce qui se passe au niveau des scripts, un élément à la fois. Le même code C++ de base pourra charger n'importe quel jeu pourvu que l'écran d'accueil corresponde à "demo.cmd". En réécrivant simplement ce petit fichier (et d'autres .cmd, et en ajoutant des .spr puis -- plus tard -- des .map), on pourra faire son jeu à soi à partir du moteur GEDS.
Revenir en haut Aller en bas
http://sylvainhb.blogspot.com
Contenu sponsorisé




MessageSujet: Re: Faire des jeux sur DS   

Revenir en haut Aller en bas
 
Faire des jeux sur DS
Revenir en haut 
Page 1 sur 1

Permission de ce forum:Vous ne pouvez pas répondre aux sujets dans ce forum
E-magination :: ~ Forums de création de jeux ~ :: Projets en cours-
Sauter vers: