Seuls les membres ayant 30 points peuvent parler sur le chat.

Forum Casio - Vos tutoriels et astuces


Index du Forum » Vos tutoriels et astuces » Tutoriels d'utilisation de gint
LephenixnoirEn ligneAdministrateurPoints: 15785 Défis: 136 Message

Tutoriels d'utilisation de gint

Posté le 15/07/2017 13:53

Pas de commentaires sur ce topic ! Merci de poster par ici.

Bien le salut, développeur ! Cette série de tutoriels présente l'utilisation de gint et du fxSDK pour écrire des add-ins.

Pour reproduire les manips' réalisées ici, il te faut au préalable avoir installé :

Un cross-compilateur pour la calculatrice ;
Le fxSDK ;
Le noyau gint (important ).

Plutôt que de vous embêter avec un catalogue de fonctions qui ne serait amusant ni pour vous ni pour moi, je vous propose d'utiliser gint pour monter un petit jeu de stratégie en développant au fur et à mesure le code et les ressources. C'est pas un tutoriel de pixel art donc je vous parachuterai tout ce qui s'éloigne du code, mais c'est l'idée.

Il n'est pas question de donner tout le code et toutes les commandes shell (ce serait beaucoup trop indigeste), mais de s'arrêter sur le développement de différents points-clés intéressants, prétextes pour utiliser les fonctionnalités du fxSDK et pour parler un peu de game design. Je penserai à mettre le code sur un dépôt Git.

Enfin, pour garder les différents posts (qui seront peut-être un peu longs) ensembles et dans l'ordre sur ce topic, je vous demanderai de ne pas commenter ici mais sur le topic suivant :

Tutoriels d'utilisation de gint (commentaires)

Sur ce, il est temps de passer aux choses sérieuses. Bonne lecture !

Tutoriels existant à ce jour (en cours)

01 : "Hello, World!", encore et toujours



LephenixnoirEn ligneAdministrateurPoints: 15785 Défis: 136 Message

Citer : Posté le 15/07/2017 13:56 | # | Fichier joint



01 : "Hello, World!", encore et toujours

Je vous propose de commencer cette série par l'écran d'accueil du jeu et un peu de gestion de projet. Normalement il faudrait coder le moteur d'abord, mais ce serait trop brutal. Voilà ce qu'on va réaliser à la place :


Image 1 : un accueil chaleureux, mais attention aux crabes !

Une police facile à dessiner, un titre vendeur (des monstres ! ) et un palmier mutant (qui a une bonne tête de boss de fin), rien de bien extravagant. J'ai ajusté les dimensions sur l'image pour que le texte passe partout (même si le joueur choisit comme nom WWWWWWWW, ce qu'au moins l'un de vous fera juste pour m'embêter).

À gauche donc, les trois sauvegardes du jeu. À droite, les informations sur la partie sélectionnée, ou une nouvelle partie. Les sauvegardes ce sera pas pour tout de suite, donc on va se coltiner une nouvelle partie à chaque test pendant quelques temps (quitte à commenter le menu pour aller plus vite).

Création du projet

Commençons par créer les fichiers dont on a besoin. Le fxSDK fournit un modèle de projet avec tout ce qu'il faut pour compiler, via l'outil fxsdk. Mettez-vous dans un dossier de votre choix (pour moi ~/Programs) et créez un nouveau projet :

% fxsdk new monster-island
Creating a new project in folder 'monster-island'.

Full project name ? (at most 8 characters)
> MoIsland
Internal name ? ('@' followed by at most 7 uppercase letters)
> @MISLAND

Your project 'MoIsland' has been created.

Type 'fxsdk build-fx' or 'fxsdk build-cg' to compile the program.

Le fxSDK vous demande quelques informations sur votre add-in. Le premier est le nom de l'add-in tel qu'on le voit dans l'onglet VERSION de l'application SYSTEM, et le second et le nom interne qui sert notamment à attribuer des dossiers dans la mémoire principale. Si vous ne savez pas quoi mettre ou avez un doute vous pouvez le laisser vide, ce sera modifiable plus tard.

Maintenant voyons voir ce qu'il y a dans ce dossier !

% tree monster-island
monster-island
├── assets-cg
│   ├── icon-cg-sel.png
│   └── icon-cg-uns.png
├── assets-fx
│   └── icon-fx.png
├── Makefile
├── project.cfg
└── src
    └── main.c

Le fxSDK a créé un certain nombre de dossiers et fichiers. Voici à quoi ils servent :

assets-cg contient toutes les images, polices et autres ressources pour la Graph 90+E. Le fxSDK permet de programmer pour la Graph 90+E, et même de faire un add-in pour la Graph 35+ et la Graph 90+E en même temps. Ici, on va programmer uniquement sur Graph 35+, donc je vais le supprimer.
assets-fx contient les images, polices et autres ressources pour la Graph 35+. C'est là qu'on va mettre la plupart de nos données !
• Le Makefile est un fichier indiquant comment compiler l'application. Quand vous tapez "make" dans le terminal, c'est lui qui donne toutes les instructions.
project.cfg est un fichier de configuration créé par le fxSDK. Le Makefile va lire certaines informations ici, vous pouvez donc personnaliser votre add-in en le modifiant au lieu de toucher au Makefile.
src contient comme d'habitude tous les fichiers de code. Le fxSDK a copié un main.c avec un code d'exemple.

Hello, World!

C'est parti ! Commençons avec un "Hello, World!" de gint :

#include <gint/display.h>
#include <gint/keyboard.h>

int main(void)
{
    dclear(C_WHITE);
    dtext(1, 1, "Sample fxSDK add-in.", C_BLACK, C_NONE);
    dupdate ();

    getkey();
    return 1;
}

Pour le réaliser, on a besoin de deux en-têtes de gint, <gint/display.h> (dessin et affichage) et <gint/keyboard.h> (gestion du clavier). Ces en-têtes listent toutes les fonctions qui gint propose et également des types de données dont le compilateur a besoin. Vous aurez certainement des erreurs de compilation si vous en oubliez !

Ensuite, on y va gaillardement pour dessiner.

dclear(C_WHITE) efface la VRAM et remplit tout en blanc. C'est comme Bisp_AllClr_VRAM() excepté que vous pouvez changer de couleur.
dtext(x,y,str,fg,bg) affiche une chaîne de caractères à la position indiquée et avec la couleur spécifiée. La position est en pixels, avec (0,0) en haut à gauche. Ce sera le cas pour toutes les fonctions sans exception aucune ! fg est la couleur du texte et bg la couleur de fond. C_NONE signifie transparent. Cette fonction ressemble à PrintXY(), sauf qu'on a plus de choix de couleurs et que plus tard on pourra changer la police !
dupdate() affiche les contenus de la VRAM à l'écran, c'est l'équivalent de Bdisp_PutDisp_DD().

Une fois que tout ça est fait, on ne veut pas que l'add-in s'arrête et revienne au menu tout de suite sinon on ne verra rien.

getkey() met le programme en pause jusqu'à ce que l'utilisateur appuie sur une touche, et renvoie un événement indiquant quelle touche a été pressée, quand, et d'autres informations utiles. Chaque touche a un nom, que vous pouvez trouver dans <gint/keycodes.h>.

J'aimerais insister sur trois choses au sujet de getkey() pour éviter toute confusion.

1. getkey() attend. Le code qui suit (le return) ne sera pas exécuté tant que l'utilisateur n'aura pas appuyé sur une touche, peu importe si ça lui prend des heures !
2. getkey() renvoie un événement, alors que GetKey() modifie un pointeur qu'on lui passe en argument.
3. getkey() ne rafraîchit pas l'écran, contrairement à GetKey() qui appelle Bdisp_PutDisp_DD() avant de se mettre en attente. Il faut appeler dupdate() explicitement.

Compiler et tester

La compilation d'une application de ce genre est un peu compliquée... heureusement le modèle de projet du fxSDK contient de quoi le faire à votre place. Pour compiler votre application pour Graph 35+, utilisez la commande "fxsdk build-fx". (Dans le fxSDK, "fx" signifie Graph 35+ tandis que "cg" signifie Graph 90+E. Naturellement il existe aussi "fxsdk build-cg" pour compiler une version Graph 90+E.)

% fxsdk build-fx

:: Making into build-fx

sh3eb-elf-gcc -c src/main.c -o build-fx/src/main.o -mb -ffreestanding -nostdlib -Wall -Wextra -fstrict-volatile-bitfields -std=c11 -Os -m3 -DFX9860G -MMD -MT build-fx/src/main.o -MF build-fx/src/main.d -MP
sh3eb-elf-gcc -o build-fx/src/MoIsland.elf build-fx/src/main.o  -mb -ffreestanding -nostdlib -Wall -Wextra -fstrict-volatile-bitfields -std=c11 -Os -m3 -DFX9860G  -Tfx9860g.ld -lgint-fx -lgcc -Wl,-Map=build-fx/map
sh3eb-elf-objcopy -O binary -R .bss -R .gint_bss build-fx/src/MoIsland.elf build-fx/src/MoIsland.bin
fxg1a build-fx/src/MoIsland.bin -o MoIsland.g1a -i "assets-fx/icon-fx.png" -n "MoIsland" --internal="@MISLAND"

Pendant la compilation, deux nouvelles choses sont apparues dans votre dossier de projet :

• Un dossier build-fx qui contient tous les fichiers compilés. Vous pouvez le supprimer à tout moment, mais il permet de recompiler l'application plus vite en récupérant le code déjà compilé quand vous ne l'avez pas modifié. En général vous voulez donc le laisser tranquille. Toutefois il n'est pas apprécié sur un dépôt Git donc ajoutez-le dans votre .gitignore !
• Le fichier MoIsland.g1a qui est notre add-in compilé !

Et c'est terminé ! Il ne reste qu'à envoyer l'add-in sur votre calculatrice par votre méthode préférée. Je suis sur Graph 35+E II donc ce sera par USB. Un outil de choix sous Linux est l'utilitaire P7 de Cakeisalie5. Une fois transféré, l'add-in apparaît dans le menu et on peut observer le résultat attendu :


Image 2 : Yeah!


Sur ce, il est temps de passer aux choses sérieuses !

Les assets

Voici les assets que l'on va utiliser : une icône pour l'add-in, l'image du titre avec le palmier, et la police de caractères pour écrire le texte. On ne va pas utiliser celle par défaut de gint, qui manque un peu de style. Les flèches sont dans la police, donc on a tout. Le PNG est fortement conseillé et même obligatoire pour l'icône.



Image 3 : J'ai noté "ISLAND" mais c'est surtout les monstres qui vont tabasser le joueur.



Image 4 : Ce palmier est vraiment creepy.



Image 5 : Une police qui a du caractère !


Les images ci-dessus sont agrandies, bien sûr pour le projet il vous faut les originaux. Vous pouvez les télécharger dans une archive zip ici :

tuto-gint-1.zip (téléchargement direct)

Comme vous pouvez le voir, la police qu'on utilise est vraiment une image. C'est juste une grille de caractères. Pour la convertir on va utiliser fxconv, l'un des outils du fxSDK, et lui indiquer la taille de la grille et d'autres informations. J'ai remplacé "<" et ">" par des flèches "" et "" qui seront plus utiles !

Décompressez les trois fichiers dans assets-fx. Cela doit remplacer l'icône par défaut du fxSDK par celle du projet, créer un dossier "img" avec title.png dedans, et créer un dossier "fonts" avec island.png dedans.:

% tree assets-fx
assets-fx
├── fonts
│   └── island.png
├── icon-fx.png
└── img
    └── title.png

Pourquoi des sous-dossiers ? Cela permet au fxSDK de savoir tout de suite ce qui est une image et ce qui est une police. Si vous tapez "fxsdk build-fx" maintenant, vous verrez que fxconv va automatiquement convertir l'image et la police. Mais cela va échouer sur la police avec l'erreur suivante :

Exception: size of grid unspecified or invalid

fxconv ne sait tout simplement pas comment notre police est construite. En particulier, il ne connait pas les dimensions de la grille. Il faut qu'on le lui indique ! Pour cela, modifions le fichier de configuration du projet, "project.cfg". Vous pouvez le modifier comme n'importe quel fichier texte ou fichier C.

#---
# fxSDK project configuration file for MoIsland
#---

# Project name, should be at most 8 bytes long.
NAME = MoIsland
# Internal name, should be '@' followed by at most 7 uppercase letters.
INTERNAL = @MISLAND

# fx-9860G icon location
ICON_FX = assets-fx/icon-fx.png
# fx-CG 50 icon locations
ICON_CG_UNS = assets-cg/icon-cg-uns.png
ICON_CG_SEL = assets-cg/icon-cg-sel.png

# Additional compiler flags
CFLAGS = -std=c11 -Os
# Additional linker flags
LDFLAGS =

Le fichier contient une liste de paramètres qui ont un nom et une valeur. Vous retrouvez NAME et INTERNAL qui sont les deux noms que le fxSDK vous a demandé au moment de créer le projet. Vous pouvez les modifier ici autant de fois que vous le voulez puis recompiler l'add-in pour observer les changements. Les trois paramètres suivants indiquent le chemin des icônes ; notre icône est actuellement dans assets-fx/icon-fx.png. Ces paramètres sont utiles si vous voulez la mettre ailleurs, ce qui est une pure question de goût. Les deux derniers paramètres sont des options à passer au compilateur et au linker. L'option "-std=c11" permet de travailler avec du C moderne et "-Os" demande au compilateur d'optimiser le programme pour que le fichier g1a soit petit.

Pour convertir les polices, fxsdk va chercher automatiquement les informations dans ce fichier. Notre fichier de police s'appelle island.png, on indiquera donc les informations dans un paramètre nommé "FONT.island.png". Ajoutez cette ligne à la fin du fichier :

FONT.island.png = charset:print grid.size:5x7 grid.padding:1 proportional:true

Voyons voir ensemble ce que ces paramètres veulent dire.

• "charset:print" indique quels sont les caractères qui sont dessinés. "print" c'est l'ensemble des caractères affichables de l'ASCII, il y en a 95 qui commencent par l'espace et se terminent par le tilde. (Le carré en bas à droite sera ignoré.) Avec cette information, fxconv sait que le troisième caractère de la troisième ligne est "B".

• "grid.size:5x7" indique quelle taille fait chaque caractère. Comme vous pouvez le voir, il faut indiquer une taille assez grande pour tous les caractères à la fois. La plupart des caractères font moins de 5 pixels de large, mais M, W et quelques autres nous obligent à indiquer au moins 5. Pour la hauteur, la plupart des caractères font 6 pixels mais il y a des caractères comme g ou la virgule qui descendent une ligne plus bas que les autres, portant le total à 7.

• "grid.padding:1" indique qu'autour de chaque caractère, j'ai laissé un cadre blanc de 1 pixel de large. Je l'ai fait pour pouvoir espacer les caractères. J'ai mis en valeur les cadres sur l'image suivante (en bleu et en orange) :



Image 6 : Il y a un pixel de padding autour de chaque caractère.

• "proportional:true" signifie qu'on veut une police à largeur variable : on veut que chaque caractère prenne juste la place qui est nécessaire pour le dessiner. Ainsi, même si M ou W prennent 5 pixels, I fera quand même 1 pixel et A 4 pixels.

Vous n'avez pas besoin de comprendre tous les détails de comment les polices marchent pour l'instant. Si des choses vous échappent, vous aurez l'occasion d'y revenir plus tard.

Vous pouvez maintenant recompiler avec "fxsdk build-fx" et observer que l'image et la police sont converties ! Si vous en avez l'habitude, vous pouvez aussi juste taper "make", ce qui a exactement le même effet.

Dessiner un menu principal

Grâce à notre image de titre et à notre police, on peut réaliser facilement le début de notre menu principal :

int main(void)
{
    extern image_t img_title;
    extern font_t font_island;

    dfont(&font_island);

    dclear(C_WHITE);
    dimage(0, 1, &img_title);
    dtext(9, 31, "New Game", C_BLACK, C_NONE);
    dtext(9, 40, "New Game", C_BLACK, C_NONE);
    dtext(9, 49, "New Game", C_BLACK, C_NONE);
    dupdate();

    getkey();
    return 0;
}

Il y a pas mal de choses à dire sur cette nouvelle fonction. D'abord, les deux premières lignes :

extern image_t img_title;
extern font_t font_island;

Ce sont des déclarations de variables. La première est du type image_t (probablement notre image de titre), et la seconde du type font_t (probablement notre police ). Les deux sont marquées extern, ce qui est très important : ça signifie qu'on ne crée pas de variable, on indique seulement au compilateur que ces variables existent ailleurs et on lui promet de les lui fournir quand il en aura besoin. Ces variables sont en fait créées par fxconv et elles représentent l'image et la police que vous avez converties.

Désormais, plus besoin de tableaux longs et moches du genre const unsigned char title[256] = { }, il vous suffit de créer l'image au bon endroit et de l'appeler ensuite par son nom :

• Pour une image, "img_" suivi du nom du fichier. Par exemple "title.png" devient "img_title".
• Pour une police, "font_" suivi du nom du fichier. Par exemple "island.png" devient "font_island".

Ce sont les noms par défaut mais vous pourrez les changer plus tard.

Ensuite, on change de police avec un appel à la fonction dfont(). Vous noterez qu'il faut donner l'adresse de la police en question (il y a un "&" devant le paramètre). Dès que vous utiliserez une image ou une police provenant de l'extérieur du programme il faudra mettre ce "&". Et c'est tout ! Désormais dtext() affiche du texte avec notre nouvelle police.

Puis, le dessin de l'image :

dimage(0, 1, &img_title);

Comme pour dtext(), les coordonnées sont dans l'ordre (x,y), en pixels en partant d'en haut à gauche. Et comme pour dtext(), x et y sont les deux premiers paramètres. Ce sera toujours le cas ! Comme je l'avais annoncé, il faut donner l'adresse de l'image, donc il y a encore un "&" devant "img_title". Contrairement à MonochromeLib vous n'avez plus besoin d'indiquer la dimension de l'image !

Et bien sûr, on n'oublie pas d'actualiser l'écran avec dupdate(), ce que getkey() ne fait pas pour nous. Et c'est gagné !


Image 7 : Le menu principal prend forme !

Le curseur et la description

Il ne nous reste plus qu'à afficher le curseur (les deux flèches) et la description de l'entrée sélectionnée à droite. Lorsqu'il y aura des sauvegardes, on pourra y mettre le nom du joueur, son niveau et l'avancement dans l'exploration de l'île, mais pour l'instant on n'a que des nouvelles parties, donc on va afficher tout le temps le texte de démarrage de nouvelle partie.

int main(void)
{
    extern image_t img_title;
    extern font_t font_island;
    int entry_selected = 0;

    dfont(&font_island);

    while(1)
    {
        dclear(C_WHITE);
        dimage(0, 1, &img_title);
        dtext(9, 31, "New Game", C_BLACK, C_NONE);
        dtext(9, 40, "New Game", C_BLACK, C_NONE);
        dtext(9, 49, "New Game", C_BLACK, C_NONE);

        dline(61, 33, 61, 52, C_BLACK);
        dtext(64, 33, "Start from", C_BLACK, C_NONE);
        dtext(64, 40, "the beginning", C_BLACK, C_NONE);
        dtext(64, 47, "of the story.", C_BLACK, C_NONE);

        dtext(3, 31 + 9 * entry_selected, ">", C_BLACK, C_NONE);
        dtext(50, 31 + 9 * entry_selected, "<", C_BLACK, C_NONE);
        dupdate();

        switch(getkey().key)
        {
        case KEY_UP:
            if(entry_selected) entry_selected--;
            break;
        case KEY_DOWN:
            if(entry_selected < 2) entry_selected++;
            break;
        case KEY_EXE:
            return 0;
        }
    }

    return 0;
}


Image 8 : C'était pas si difficile !

Il y a plusieurs nouvelles choses à remarquer ici :

• J'ai utilisé la fonction dline(x1,y1,x2,y2,color) pour tracer une ligne. Les deux extrémités sont incluses dans la ligne !
• Pour les flèches j'ai customisé ">" et "<" dont on ne servira pas.
getkey() renvoie un événement avec plusieurs informations comme la touche pressée, à quel moment on a appuyé dessus (utile pour les jeux en temps réel), si [SHIFT] ou [ALPHA] avaient été pressés avant... là je ne regarde que la touche pressée. On reviendra sur les informations utiles renvoyées par getkey().
• L'écran est redessiné même si on presse une touche inutile comme [4]. C'est pas génial, mais je voulais garder le code court.
• Arrêter le programme quand on appuie sur [EXE] peut sembler bizarre, mais en fait ce menu va être dans une fonction qui renverra entry_selected, donc c'est normal !
• Pour le reste du jeu je préférerai utiliser [SHIFT], mais ce n'est pas encore possible car getkey() s'en sert comme modifieur pour faire des combinaisons comme [SHIFT][×] → [{]. Je vous montrerai comment désactiver ça plus tard !
• Même si la boucle est infinie, on peut toujours quitter l'add-in en appuyant sur [MENU] puis revenir ensuite, comme avec le GetKey() de fxlib. (TODO : Pas encore dans la dernière version, je pédale pour l'ajouter... huff huff...)

Conclusion

C'est un menu très schématique et qu'on pourrait facilement améliorer : animation d'entrée du titre, déplacement progressif du curseur, peut-être un fondu d'entrée/sortie sur la description, une bordure décorée au lieu d'une simple ligne, gérer la touche [SHIFT], et plus encore.

Ce tutoriel n'est qu'une brève introduction sur les fonctions fournies par gint mais décrit la grande majorité de la gestion routinière d'un projet. J'en parlerai très peu dans la suite, et ça devrait être plus fun.

Planète Casio v42 © créé par Neuronix et Muelsaco 2004 - 2019 | Il y a 102 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd