Pokémon-Distribution Forum Index

Pokémon-Distribution
Voici un forum de pokémon sympa avec des distribution, des soluces, des film à voir et de la bonne humeur !

 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Créer un jeu DS

 
Post new topic   Reply to topic    Pokémon-Distribution Forum Index -> Divers -> Espace communautaire
Previous topic :: Next topic  
Author Message
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:48 (2010)    Post subject: Créer un jeu DS Reply with quote

Installation de MicroLua
Avant de commencer à programmer, on va installer µLua !


Tout d'abord, de quoi avons-nous besoin ?
  • D'une DS(i)
  • D'un linker
  • De NanoLua 2.4, disponible ici
  • D'un éditeur de texte (Bloc-Notes, Notepad, Vim, Gedit, LuaEdit, etc...)


En décompressant l'archive de NanoLua, vous obtenez un dossier Nano Lua 2.4, qui contient :
  • Un dossier Examples : vous y trouverez donc... les exemples
    Si vous ne savez pas trop comment utiliser telle ou telle fonction, allez y faire un tour
  • Un dossier lua : c'est ce dossier qui contient les fichiers nécessaires au bon fonctionnement de NanoLua
  • Un dossier Utilities : vous trouverez dans ce dossier divers utilitaires, permettant de tester directement sur votre PC vos programmes, de convertir une police spéciale pour µLua, de créer une banque de son et de compiler vos scripts Lua
  • Trois fichiers nanolua.nds, nanolua.sc.nds et nanolua.ds.gba : ce sont les trois versions différentes de NanoLua, à choisir en fonction de votre linker
  • Un fichier Readme : il contient un release note et un lien vers le site officiel.


Suivant votre linker, choisissez microlua.nds (le plus souvent), microlua.sc.nds (pour les SuperCard) ou microlua.ds.gba (pour les linkers GBA).
Copiez ce fichier ainsi que le répertoire lua à la racine de votre linker.


Copiez bien le dossier lua à la racine de votre linker ! En revanche, vous pouvez mettre où vous voulez le fichier nano.nds, nano.sc.nds ou nano.ds.gba.


Le dossier lua contient une longue arborescence qui permet en fait d'assurer la compatibilité entre différentes versions (et notamment la séparation avec MicroLua originel). Il y a donc un premier dossier nano, qui contient les différentes versions de NanoLua (ici, le dossier "24" désigne la version 2.4). Ce dossier contient deux autres dossiers, libs et scripts. Le dossier libs contient donc... les librairies de NanoLua, et scripts est le dossier dans lequel il est conseillé de mettre vos scripts.

Vous devriez avoir une arborescence comme ceci :

  • Racine de votre carte
    • lua
      • nano
        • <dossier de version>
          • libs
          • scripts

Et votre fichier nano.nds ou dérivé quelque part dans votre carte.

Test de MicroLua
Nous allons maintenant vérifier le bon fonctionnement de µLua.


Créez le fichier test.lua dans le dossier lua/nano/<version>/scripts, et copiez/collez-y le code suivant :

Code : Lua
Code:
12345

Code:
while not Keys.held.Start do   screen.print(SCREEN_UP, 0, 0, "O.K. !")   render()end




Ne vous inquiétez pas de la signification de ce code : nous verrons ça plus tard.
Démarrer votre DS(i) et lancez votre linker.

Lancez le fichier nano.nds (ou celui qui correspond à votre linker) puis sélectionnez le fichier test.lua et appuyez sur A.

Si vous voyez "O.K. !" sur l'écran du haut c'est que tout fonctionne : vous pouvez alors éteindre votre DS(i), sauter de joie et courir partout dans votre maison, et même à poil dans la rue (nan, mais revenez quand même
).

Ça marche pas !

En général, MicroLua marche tout de suite correctement. Cependant, il est possible que vous ayez l'erreur "could'nt open libs.lua". Elle signifie que MicroLua ne peut pas trouver le fichier libs.lua, qui doit être placé dans le dossier /lua/nano/<version>/libs. Vérifiez donc que votre arborescence soit correcte.


Si vous avez essayé MicroLua par le biais du No$GBA Tester (inclus dans le dossier Utilities), les fichiers contenus dans lua/nano/<version>/libs doivent être placés dans le dossier fat, qui se trouve dans le dossier no$gba Tester.



On a maintenant installé µLua et nous l'avons testé, il ne nous reste donc plus qu'à apprendre à programmer


Back to top
Visit poster’s website
Publicité






PostPosted: Wed 17 Mar - 18:48 (2010)    Post subject: Publicité

PublicitéSupprimer les publicités ?
Back to top
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:49 (2010)    Post subject: Créer un jeu DS Reply with quote

Les bases de la programmation en Lua (1)
Cette partie explique les bases de la programmation en Lua. Vous n'y apprendrez rien qui concerne directement µLua, cependant c'est indispensable. Les connaisseurs du langage Lua peuvent quant à eux directement passer à la partie "Et pour MicroLua ?".


Les commentaires


Pour écrire un commentaire en Lua, c'est très simple :

Code : Lua
Code:
123456

Code:
-- Ca, c'est un commentaireIci, des instructions      -- Et là, un commentaire en fin de ligne--[[ Et ça, c'estun commentaire sur plusieurs lignes ]]--





Les variables


En Lua, comme dans la plupart des langages, on affecte une variable de cette façon :

Code : Lua
Code:
1

Code:
variable = valeur




Il est aussi possible d'affecter plusieurs variables en même temps :

Code : Lua
Code:
123

Code:
i, j = 1, 2-- Et on peut même échanger les valeurs en une seule ligne !i, j = j, i




Et comme dans la plupart des langages (tous ?), Lua est sensible à la casse, c'est-à-dire que variable, VARIABLE et vARiaBlE sont trois variables différentes.

A la base, toutes les variables sont globales, mais vous pouvez définir une variable locale à un bloc d'instructions (voir à la partie suivante) grâce au mot clé local :

Code : Lua
Code:
12345

Code:
variableGlobale = valeurdo   local variableGlobale = valeur    -- Et oui, vous pouvez donner le même nom à cette variable qu'à la première !end





Ne vous souciez pas de do <...> end pour l'instant, comprenez juste que ça délimite un bloc d'instructions.


Comme vous le voyez, on peut très bien donner le même nom à une variable globale qu'à une variable locale ; il n'y aura pas de conflit, cependant, seule la variable locale sera accessible.



Les nombres

Rien de bien particulier :

Code : Lua
Code:
12

Code:
variable = 12variable2 = 45.72




Mis à part le fait qu'il n'y a pas de moyen pour incrémenter ou décrémenter une variable rapidement (variable++ ou variable--). Vous serez obligés de faire :

Code : Lua
Code:
12

Code:
variable = variable + 1variable = variable - 1





Les chaînes de caractères

Les chaînes de caractères (ou strings) sont délimitées par des guillemets (""), des apostrophes (''), voire même des doubles-crochets ([[]]). Cette dernière notation permet de présenter des strings sur plusieurs lignes.

Comme dans de nombreux langages, on représente le retour à la ligne avec "\n".

Un petit mot sur la concaténation : ce terme barbare signifie que l'on rassemble plusieurs variables en une seule. Elle peut se faire pour des tables grâce à une fonction, mais c'est surtout utile pour les strings. Pour concaténer deux chaînes, on fait comme ceci :
Code : Lua
Code:
1

Code:
string = chaine.."du texte"..chaine2



Comme vous le voyez, on utilise deux points ".." pour relier les chaînes.


Les tableaux

Les listes, ou tableaux, sont appelés tables en Lua, et sont délimités par des accolades. Les éléments sont séparés par des virgules.
Lua est très souple, vous pouvez mettre n'importe quel type de variable dans les tables (nombres, strings, d'autres tables, et même des fonctions, qui sont considérées en Lua comme des variables).
Vous pouvez accéder à un élément de la table en faisant :

Code : Lua
Code:
1

Code:
table[index]





Index peut être de n'importe quel type. En effet, vous pouvez associer une valeur à un string, voire même à une fonction :

Code : Lua
Code:
12345

Code:
table = {stringCle = valeur, fonction = valeur2}-- Et pour y accéder :table["stringCle"]table[fonction]






Les booléens

Les booléens en Lua, c'est deux valeurs : true et false.

Code : Lua
Code:
123

Code:
vrai = truefaux = false-- Attention, il n'y a pas de guillemets autour !





Les userdatas

Les userdatas sont la représentation en Lua des structures en C (il faut savoir que Lua est très lié au C, il possède par exemple une API complète de contrôle en C). Elles contiennent donc des variables. Et comme les fonctions sont des variables... les userdatas peuvent être utilisées comme des classes d'objet pour une orientation POO de Lua

Vous trouverez donc des variables du style :
Code : Lua
Code:
123

Code:
Objet.attribut.sousAttribut    -- Un objet avec plein d'attributsObjet.methode()                 -- Un objet avec une méthodeObjet:methode2()                -- Une autre façon d'appeler une méthode





Le nil

nil, c'est la valeur vide. Si une variable vaut nil, elle ne vaut rien. C'est un peu le NULL des pointeurs en C, sauf que nil s'utilise pour toutes les variables.



La doc officielle de Lua décrit aussi le type thread, qui représente un sous-processus du programme en Lua, mais il n'a pas d'utilité sur la Nintendo DS(i), qui a une architecture différente de celle d'un PC (et qui a surtout un processeur à 66MHz
).


Les bases de la programmation en Lua (2)
Les opérateurs


Mathématiques

En Lua, il y a les cinq opérateurs de calcul "classiques" :
  • addition : +
  • soustraction : -
  • division : /
  • multiplication : *
  • modulo : %

Il y a aussi "^", pour représenter une puissance.


De comparaison

  • Est égal à : ==
  • Est différent de : ~=
  • Est supérieur à : >
  • Est inférieur à : <
  • Est supérieur ou égal à : >=
  • Est inférieur ou égal à : <=



L'opérateur d'égalité comporte DEUX signes égal "=". Notez aussi que contrairement à beaucoup de langages, l'opérateur "différent de" est "~=" et non pas "!=".



L'opérateur de longueur

Cet opérateur est particulier à Lua : le symbole dièse "#" représente la longueur d'une variable possédant des éléments, autrement dit la longueur d'une table ou d'un string.

Exemple :
Code : Lua
Code:
12345

Code:
chaine = "bla bla"tableau = {0, "Hey !", 36.12, fonction}#chaine    -- Donne 7#tableau   -- Donne 4





L'opérateur de concaténation

Ce n'est pas un "+" ; en Lua, on effectue une concaténation avec ".." :

Code : Lua
Code:
1234

Code:
chaine1 = "Bonjour, "chaine2 = "ça va ?"chaine3 = chaine1.."est-ce que "..chaine2    -- chaine3 vaut "Bonjour, est-ce que ça va ?"





Opérateurs logiques

Ce sont les mots anglais pour dire "ou", "et", et "non" :
  • Ou : or
  • Et : and
  • Non (inverser le résultat de l'expression) : not



Les mots-clés des blocs d'instructions


Un bloc d'instruction est un ensemble d'instructions plus ou moins séparées des autres. Un bloc délimite aussi la "zone" dans laquelle une variable locale est accessible.


Blocs conditionnels

Une condition se construit de cette façon :

Code : Lua
Code:
123456789

Code:
if <condition> then        -- si <condition> alors   <instructions>elseif <condition2> then   -- sinon si <condition2> alors   <instructions>elseif <condition3> then   <...>else                       -- sinon   <instructions>end                        -- fin de la condition





Boucles
Il y a en tout trois types de boucles en Lua. Tout d'abord, deux première que j'appellerai "classiques" :
Code : Lua
Code:
1234567

Code:
while <condition> do      -- tant que <condition> faire   <instructions>end                       -- fin de la bouclerepeat                    -- répéter   <instructions>until <condition>         -- jusqu'à ce que




Ces deux boucles sont sensiblement identiques, sauf que dans le cas de la seconde, la condition de sortie de la boucle est évaluée à la fin de chaque tour, et non au début. Ce qui signifie que, quoi qu'il arrive, les instructions de la boucle repeat ... for seront exécutées au moins une fois.

La troisième boucle est la boucle for :
Code : Lua
Code:
123

Code:
for variable [= <borne>, <borne>, <pas>] [in iterateur] do    -- Pour variable [qui prend les valeurs <borne> à <borne>, en allant de <pas> en <pas>] [dans iterateur] faire   <instructions>end




Celle-ci est un peu particulière.
Tout d'abord, voyons le cas sans itérateur : à chaque tour de boucle, variable va prendre une nouvelle valeur (sa valeur précédente plus le pas, qui peut être négatif). On sort de la boucle dès que l'on a atteint la deuxième borne.

Et avec un itérateur...

Houlàààààà, c'est quoi un itérateur ?


En fait, je vous enjoins à lire cette page (en anglais, désolé), qui vous explique le fonctionnement de la fonction next ; cette fonction permet de "traverser une table ou assimilé". En fait, à chaque fois que cette fonction est appelée, avec en argument une table, elle retourne la valeur suivante de la table ainsi que son index. On appelle ça un itérateur. Regardez aussi les fonctions ipairs et pairs (sur le même site).
Ainsi, pour comparer avec ce qu'on a dit plus haut, à chaque tour variable prend la valeur suivante dans la table. On sort de la boucle quand on a fait un tour de boucle avec la dernière valeur.

Enfin, sachez que toutes ces boucles peuvent être "cassées" à l'aide de l'instruction break, c'est-à-dire qu'elles sont arrêtées.


Il y a aussi le bloc d'instructions do <instructions> end, qui... ne fait rien si ce n'est exécuter les instructions. Il ne sert qu'à délimiter un bloc.


Les fonctions

Les fonctions, c'est tout simple :

Code : Lua
Code:
12345678

Code:
-- Déclaration de la fonctionfunction nomDeLaFonction(arguments, attendus)   <instructions>   return variable, autreVariable     -- instruction pour retourner une voire PLUSIEURS variablesend-- Appel de la fonctionretour1, retour2 = nomDeLaFonction(arg1, arg2)





Vous avez pu apercevoir une autre des libertés de µLua : une fonction peut retourner plusieurs valeurs. Mais elle peut très bien n'en retourner qu'une seule, ou même aucune





Bien, je crois n'avoir rien oublié. C'est un peu condensé, peut-être pas très clair, mais je dois vous apprendre µLua moi, pas le Lua ! Namého.
...
Quoiqu'il en soit, si vous avez besoin d'aide, deux sites utiles : la doc officielle de Lua (en anglais) et des tutoriaux sur le wiki Lua (en anglais). Et bien sûr, le forum du SdZ


Et pour MicroLua ?
Et pour MicroLua, deux choses :


Détruisez vos variables à la fin de vos programmes !


DESTRUCTION !!!!

Mouahahahaha... ahaha... ah

Bref.


Il faut savoir que notre pauvre DS(i) ne possède pas beaucoup de mémoire, du moins pas assez pour la gâcher. Il faut donc la libérer à la fin de vos programmes, pour la laisser libre aux autres.

Vous vous souvenez de nil ? La "valeur rien". Et bien, c'est ici qu'elle va nous être utile.
En effet, pour détruire une variable, il suffit de faire :

Code : Lua
Code:
1
Code:
variable = nil




A la fin du code, et ce pour toutes les variables globales (les variables locales sont détruites automatiquement à la fin de leur bloc d'instructions). Il y a aussi des façons spécifiques à certains types de variables spéciales pour les détruire, qui seront décrites en temps voulu.



D'autres types de variables

MicroLua définit d'autres types de variables relativement variés :


Color

Ouaip, ces variables contiennent une couleur. On verra ça plus loin...


Image

MicroLua définit un type pour les images. On verra ça plus loin...


Font

Ca, c'est une variable de police d'écriture. On verra ça plus loin...


Map et ScrollMap

Ces deux types de variables correspondent à des cartes et cartes défilantes. On verra ça plus... comment vous avez deviné ?



Canvas et Canvas object

Nous verrons plus loin ces variables qui correspondent respectivement à des canevas (des zones pour le dessin ultra-rapide) et des objets de canevas.
(vous voyez je change un peu
)


DateTime

Objet représentant... une date ! On verra ça plus loin...


Voilà donc les types de variables spécifiques à MicroLua.
(vive le copier/coller ! \o/ Nan, je rigole)


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:50 (2010)    Post subject: Créer un jeu DS Reply with quote

Afficher du texte à l'écran
Repérage dans l'écran

Déjà, pour afficher quelque chose, faut savoir où le mettre.
Pour se situer sur les écrans de la DS, on utilise les abscisse et les ordonnées, en partant du coin en haut à gauche de l'écran. Ces écrans sont larges de 256 pixels et hauts de 192 pixels.

La démo en image
:



(il va de soi que c'est la même chose pour l'écran du bas
)

Vous remarquerez aussi que ce tuto ne brille pas par la qualité de ses images



Attends, y a un problème : si ça commence à zéro, et s'il y a 256px de long sur 192 de haut, les coordonnées maximales devraient être 255 et 191, et non pas 256 et 192 !

Oui mais non. Imaginez une feuille quadrillée (ou prenez-en une, comme ça vous pourrez voir par vous-mêmes
) ; on prend une partie de cette feuille qui fait dix carreaux de long sur quatre de haut. Chaque carreau représente un pixel. Les coordonnées désignent logiquement les intersections des lignes ; à partir de là, je pense que vous voyez logiquement où je veux en venir : si le point tout en haut à gauche est (0, 0), alors le point tout en bas à droite est (10, 4), ce qui correspond bien à la taille du rectangle.

Convaincus ? Non ?

Bon, alors essayez ça (vous allez voir bientôt la signification de ce code) :
Code : Lua
Code:
12345

Code:
while true do   screen.drawRect(SCREEN_UP, 0, 0, 256, 192, Color.new(31, 31, 31))   screen.drawRect(SCREEN_UP, 0, 0, 255, 191, Color.new(31, 0, 0))   render()end



Ce code dessine deux rectangles vides, l'un blanc et l'autre rouge, de coordonnées respectives (coin haut-gauche puis coin bas-droit) ((0, 0),(256, 192)), et ((0, 0),(255, 191)). Que remarque-t-on ? Que le rectangle blanc colle au bord de l'écran, contrairement au rectangle rouge


Maintenant que nous avons mis les choses au point, nous pouvons continuer.

Pour se repérer entre les deux écrans, c'est plus facile :

- L'écran du haut est SCREEN_UP
- Celui du bas est SCREEN_DOWN


Ces variables sont en fait des constantes prédéfinies par µLua. Toutes les constantes sont décrites au début de la doc.


Attention à bien taper ces variables tout en majuscules !



Afficher du texte

Voici donc la commande :

Code : Lua
Code:
1

Code:
screen.print(écran, abscisse, ordonnée, "Texte à afficher")




Exemple :
Code : Lua
Code:
12345

Code:
screen.print(SCREEN_DOWN, 0, 0, "TEST !")render()-- Affiche TEST ! sur l'écran tactile en haut à gauche





N'oubliez pas la fonction render() en fin de script ! Sans elle, rien ne sera affiché, car elle commande la mise à jour des écrans.


Allez-y, créez un nouveau fichier avec l'extension .lua dans le sous dossier scripts et entrez cette commande (vous pouvez modifier l'écran, l'abscisse, l'ordonnée et le texte).



Haaaaaaaaaaaaa !
Je lance mon script et il disparait ?
Comment quoi qu'ça s'fait ?
?


C'est normal, nous n'avons pas "demandé" à notre script de se mettre en pause pour que l'on puisse voir le texte.
Il n'existe pas de fonction pause() alors nous allons utiliser une boucle qui continuera jusqu'à ce qu'on appuie sur un bouton.

J'ai choisi le bouton START !

Notre code devient donc :
Code : Lua
Code:
1234567

Code:
while not Keys.held.Start do   screen.print(SCREEN_DOWN, 0, 0, "TEST !")   render()   -- Affiche TEST ! sur l'écran tactile en haut à gaucheend





Ne vous occupez pas de la condition de la boucle, on verra ça dans "Utiliser les contrôles de la Nintendo DS(i)".


Maintenant la DS(i) attendra que l'on appuie sur START pour arrêter le script.


Beurk !
Mais c'est quoi ce blanc sur noir immonde de console !


Bon, ça va j'ai compris : on passe à la couleur !


Avec de la couleur, c'est mieux !


Il faut créer une couleur avec des valeurs rgb (red, green, blue – rouge, vert, bleu – qui vont de 0 à 31) :

Code : Lua
Code:
1

Code:
couleur = Color.new(r, g, b)




Voici une petite liste de quelques couleurs :

  • bleu = Color.new(0, 0, 31)
  • rouge = Color.new(31, 0, 0)
  • vert = Color.new(0, 31, 0)
  • orange = Color.new(31, 17, 0)
  • noir = Color.new(0, 0, 0)
  • blanc = Color.new(31, 31, 31)
  • jaune = Color.new(31, 31, 0)



Voici la nouvelle commande :

Code : Lua
Code:
1

Code:
screen.print(écran, ordonnée, abscisse, "Texte à afficher", couleur)




Exemple :
Code : Lua
Code:
 1 2 3 4 5 6 7 8 910111213

Code:
bleu = Color.new(0, 0, 31)rouge = Color.new(31, 0, 0)vert = Color.new(0, 31,  0)orange = Color.new(31, 17, 0)noir = Color.new(0, 0, 0)blanc = Color.new(31, 31, 31)jaune = Color.new(31, 31, 0)while not Keys.held.Start do   screen.print(SCREEN_DOWN, 0, 0, "TEST !", jaune) -- Affiche TEST ! sur l'écran tactile en haut à gauche en jaune   render()end




Il n'existe pas de commande pour changer la couleur du fond de l'écran ; pour cela on va créer un rectangle plein de la couleur que l'on veut.

Voici la commande :

Code : Lua
Code:
1

Code:
screen.drawFillRect(écran, abscisse1, ordonnée1, abscisse2, ordonnée2, couleur)




Exemple :
Code : Lua
Code:
 1 2 3 4 5 6 7 8 91011121314

Code:
bleu = Color.new(0, 0, 31)rouge = Color.new(31, 0, 0)vert = Color.new(0, 31  0)orange = Color.new(31, 17, 0)noir = Color.new(0, 0, 0)blanc = Color.new(31, 31, 31)jaune = Color.new(31, 31, 0)while not Keys.held.Start do   screen.drawFillRect(SCREEN_DOWN, 0, 0, 256, 192, bleu) -- Met le fond d'écran en bleu   screen.print(SCREEN_DOWN, 0, 0, "TEST !", jaune) -- Affiche TEST ! sur l'écran tactile en haut à gauche en jaune   render()end




Et n'oubliez pas de supprimer les couleurs (à mettre en toute fin de script) !

Code : Lua
Code:
1234567

Code:
bleu = nilrouge = nilvert = nilorange = nilnoir = nilblanc = niljaune = nil





Astuce pour les couleurs : si vous n'utilisez une couleur qu'une seule fois (on va prendre ici le jaune), vous pouvez faire directement :
Code : Lua
Code:
1

Code:
screen.print(SCREEN_DOWN, 0, 0, "TEST !", Color.new(31, 31, 0))



au lieu de passer par une variable couleur. Ca va plus vite, et ça marche pour tout




Zone de texte


Avant de voir les images, il faut connaître l'existence de la fonction
Code : Lua
Code:
1

Code:
screen.drawTextBox(ecran, x1, y1, x2, y2, texte[, couleur])



qui affiche le texte dans une zone de texte. Concrètement, ça fait quoi ? Ça affiche le texte en ne l'affichant que dans la zone définie, en effectuant un retour à la ligne quand le texte atteint le bord droit de la zone. Si le texte est trop long, il sera coupé (il n'y a pas d'ascenseur intégré aux TextBox).


Et voila, on en a fini avec la gestion du texte !

On se rejoint tout de suite avec les images.

Afficher des images à l'écran
Bon maintenant passons aux images
!


Chargement de l'image

Il vous faut d'abord savoir que la DS à deux mémoires :

  • la VRAM (video RAM) (mémoire vidéo) qui est de 600 Ko
  • la RAM (mémoire vive) qui est de 4Mo



La VRAM a peut-être beaucoup moins de place, c'est celle-là que vous devez utiliser pour vos images. Lorsqu'on charge une image dans la RAM, on a parfois (j'ai eu
) des problèmes.


MicroLua supporte actuellement les formats PNG (transparence non supportée), JP(E)G et GIF (non animés | transparence supportée).


MicroLua ne gère actuellement de tranparence que sur les GIF, pas sur les PNG. Attention donc.


D'abord voici la commande pour charger l'image :

Code : Lua
Code:
1

Code:
image = Image.load("chemin_de_l'image", destination)




Image.load() retourne donc une "variable image".

Le chemin de l'image peut-être un chemin relatif ou absolu et la destination est VRAM ou RAM (deux constantes comme SCREEN_UP et SCREEN_DOWN).


Conseil pour les zéros : je vous conseille de créer un dossier images comme ça vous n'aurez à mettre comme chemin que images/nom_de_l_image.extension_de_l_image



Affichage de l'image

Maintenant affichons l'image, voici la commande :

Code : Lua
Code:
1

Code:
screen.blit(écran, abscisse, ordonnée, image)





N'oubliez surtout pas de charger l'image avant !


Exemple :
Code : Lua
Code:
 1 2 3 4 5 6 7 8 910111213

Code:
-- On charge l'image dans la VRAMimage = Image.load("image.png", VRAM)while not Keys.held.Start do   -- On affiche l'image en haut à gauche de l'écran tactile   screen.blit(SCREEN_DOWN, 0, 0, image) -- Affiche l'image      render()end-- Et on efface l'image de la mémoireImage.destroy(image)image = nil




Les deux dernières lignes sont pour effacer l'image de la mémoire.

Code : Lua
Code:
12

Code:
Image.destroy(image)image = nil





D'abord on décharge l'image de la mémoire, PUIS on détruit sa variable, et pas l'inverse, sinon on ne peut plus la décharger !


Et en cadeau 2 petites fonctions :

Code : Lua
Code:
12

Code:
longueur = Image.width(image) largeur = Image.height(image)




La première sert à connaître la longueur d'une image en pixels, la seconde pour obtenir sa largeur.


Et voila, on a fini avec les bases des images ! Dans la partie avancée on en verra plus sur les images (rotation, agrandissement, et plus !).


A tout de suite pour : Les contrôles de la console
!

Utiliser les contrôles de la Nintendo DS(i)
Comme vous devez le savoir la DS(i) à un écran tactile, 8 boutons (sans le power et le son) ainsi que un pad directionnel en croix qui en comporte 4.




Pour réagir en fonction des actions de l'utilisateur, on va utiliser... les conditions ! Bravo

Mais d'abord, il faut savoir sur quoi l'utilisateur a appuyé ! Il faut mettre à jour les contrôles grâce à la fonction :

Code : Lua
Code:
1
Code:
Controls.read()




Elle est à appeler à chaque fois qu'il faut mettre à jour les contrôles pour réagir en fonction de l'utlisateur.


Maintenant, on peut donc tester la valeur de Keys.[Etat].[Bouton] ou de Stylus.[Etat] selon ce que l'on veut. Ces variables sont des booléens.

[Bouton]

  • A : A
  • B : B
  • X : X
  • Y : Y
  • L : L
  • R : R
  • Start : Start
  • Select : Select
  • Flèche directionnelle haut : Up
  • Flèche directionnelle bas : Down
  • Flèche directionnelle gauche : Left
  • Flèche directionnelle droite : Right



Faites attention aux majuscules, elles peuvent être sources d'erreurs car indispensable (ça plante si vous n'en mettez pas !)


[Etat]

  • Etat appuyé : held
  • Etat relâché : released
  • Etat nouvelle pression : newPress



Sachez aussi qu'avec le Stylet, on peut récupérer quatre informations :
  • Abscisse : Stylus.X
  • Ordonnée : Stylus.Y
  • Augmentation de X dans ce mouvement : Stylus.deltaX
  • Augmentation de Y dans ce mouvement : Stylus.deltaY


Exemple :
Code : Lua
Code:
 1 2 3 4 5 6 7 8 9101112
Code:
Controls.read()if Keys.newPress.A then-- A faire si A est re-presséendif Stylus.held then-- A faire si le stylet est appuyéend





Ah ah ! T'as oublié la condition !


Non, non. Car ces variables sont des booléens. Le bloc if teste si la condition qu'on lui donne est vraie. Donc, si on on remplace les variables par leur valeur (on admet qu'on fait une nouvelle pression sur A et que le stylet n'est pas appuyé) :

Code : Lua
Code:
 1 2 3 4 5 6 7 8 9101112
Code:
Controls.read()if true then  -- Teste si true est vrai (si vrai est vrai ^^ )-- A faire si A est re-presséendif false then  -- Teste si false est vrai (si faux est vrai ^^ )-- A faire si le stylet est appuyéend





Et ça marche avec d'autres types ?

Pour Lua, tout ce qui n'est pas nil ou qui ne vaut false vaut true. Par conséquent, 0 vaut true, "" (un string vide) vaut true, une table vide vaut true, etc.

Vous vous souvenez de la "boucle de pause" ? Maintenant, vous pouvez la comprendre :
Code : Lua
Code:
1
Code:
while not Keys.held.Start do




Elle signifie "tant qu'on n'appuie pas sur le bouton Start".

Et voilà, c'est fini avec les commandes !


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:51 (2010)    Post subject: Créer un jeu DS Reply with quote

Le dessin classique
Pour dessiner, la façon la plus simple et intuitive est d'utiliser les fonctions associées à Screen.


Toutes les fonctions que je vais aborder ici n'auront aucun effet si elles ne sont pas suivies de l'instruction render(). Je ne le mettrai pas, à vous d'y penser



Tracer une ligne

On commence en douceur, avec la fonction de tracé d'une ligne :
Code : Lua
Code:
1
Code:
screen.drawLine(ecran, x1, y1, x2, y2, couleur)





Notez que pour toutes ces fonctions, l'argument couleur est obligatoire, contrairement à screen.print().


C'est à mon avis très simple à comprendre : on choisit l'écran, on indique les coordonnées de début (x1, y1) et les coordonnées de fin (x2, y2), et enfin on choisit une couleur.

Si vous avez déjà parcourue la doc, vous aurez remarqué qu'il n'y a pas de fonction pour afficher un simple pixel. L'astuce consiste alors à utiliser la fonction screen.drawLine() en lui donnant deux fois les mêmes coordonnées. Tout bêtement


Tracer des rectangles

Vous avez à votre disposition trois fonctions pour dessiner un rectangle.

Rectangle simple
La fonction
Code : Lua
Code:
1
Code:
screen.drawRect(ecran, x1, y1, x2, y2, couleur)



dessine un rectangle "vide", dont le coin haut-gauche se trouve en (x1, y1) et le coin bas-droite en (x2, y2).

Rectangle plein
La seconde fonction est :
Code : Lua
Code:
1
Code:
screen.drawFillRect(ecran, x1, y1, x2, y2, couleur)




Cette fonction dessine un rectangle plein de la couleur passée en argument. Les coordonnées suivent la même logique que Screen.drawRect().

Rectangle dégradé
La troisième et dernière fonction est la plus intéressante et la plus originale.

Code : Lua
Code:
1
Code:
screen.drawGradientRect(ecran, x1, y1, x2, y2, couleur1, couleur2, couleur3, couleur4)





Hein ? Il y a quatre couleurs ?

Et oui ! Si vous avez une certaine connaissance de l'anglais, vous aurez certainement compris ce que fait cette fonction : elle affiche un rectangle dégradé.

C'est en fait très simple : chaque couleur correspond à un coin du rectangle, de cette façon :



Et si on veut un dégradé monochrome ou bichrome ?

Dans ce cas là, il faut passer deux fois la même couleur dans les bons coins. Pour le monochrome, il va falloir passer la couleur du fond, ce qui empêche de faire un dégradé sur une image de façon propre... Mais de toute façon, MicroLua ne gère pas la transparence alpha, donc c'est impossible de faire ça.

Le dessin avec un Canevas
Présentation des Canevas


Donc, si j'ai bien compris, il y a deux façons de dessiner ? Mais pourquoi ?


C'est une bonne question ; à première vue, les fonctions de Screen suffisent. C'est d'ailleurs celles-ci que vous utiliserez la plupart du temps.
L'intérêt des Canevas est situé dans un aspect plus technique :

  • il offre une bien meilleure vitesse d'affichage que les fonctions classiques
  • il permet de manipuler les dessins


Vous pouvez apprécier les capacités d'affichage des Canevas en exécutant l'exemple canevas dans le dossier "Examples" fourni dans le pack de téléchargement de MicroLua.

Ce qui paraît plus attrayant, c'est la "manipulation" des dessins. Mais d'abord, nous allons voir comment utiliser les Canevas.


Vie et mort d'un Canevas

Pour créer un canevas, rien de plus simple ; il suffit d'écrire en instruction :
Code : Lua
Code:
1
Code:
canevas = Canvas.new()





J'attire votre attention sur le fait que si le nom français est "canevas", le nom anglais est "canvas" (sans le "e"). Ceci peut être source d'erreurs parfois difficiles à trouver.


La destruction d'un canevas est tout aussi simple :
Code : Lua
Code:
12
Code:
Canvas.destroy(canevas)canevas = nil




On détruit le canevas à l'aide de Canvas.destroy(), fonction à laquelle on passe en argument le canevas à détruire. Il ne faut pas oublier ensuite de détruire la variable en elle-même, en y donnant la valeur nil.

Maintenant, comment se passe l'affichage d'un canevas ?
On utilise la fonction Canvas.draw(), de cette façon :
Code : Lua
Code:
12
Code:
Canvas.draw(ecran, canevas, x, y)render()




C'est assez explicite, remarquez juste que l'on ne donne que les coordonnées du coin haut-gauche, ce qui signifie que le canevas remplira toute la partie de l'écran situé entre ce point et le coin inférieur droit de l'écran indiqué.
N'oubliez pas non plus le render() à la fin !



Dessiner sur un canevas


C'est bien beau tout ça, mais comment fait on pour afficher du dessin ?


Cela se déroule en deux étapes : d'abord, on crée un objet Canevas, puis on l'ajoute au canevas approprié.
Je ne vais pas détailler toutes les fonctions de création d'objets canevas, elles sont tout à fait compréhensibles dans la doc et sont quasiment les mêmes que les "classiques". Sachez juste qu'il existe une fonction pour afficher un simple point.

Je vais donc plutôt décrire cet exemple :
Code : Lua
Code:
1234
Code:
-- On crée l'objet canevas (ici un rectangle)objet = Canvas.newRect(x1, y1, x2, y2, couleur)-- On l'ajoute au canevasCanvas.add(canevas, objet)




Comme vous le voyez, c'est très simple : on appelle une fonction Canvas.newXXX() selon l'objet que l'on veut ; cette fonction retourne un Canvas Object (c'est un type spécial de µLua), qui sert de handler (de gestionnaire) pour cet objet (vous verrez plus loin quelle en est l'utilité). Ensuite, on appelle Canvas.add(), qui ajoute l'objet au canevas spécifié.
Lors du prochain appel de la fonction Canvas.draw() (et après le render()), un rectangle des coordonnées et de la couleur demandées sera affiché.


Manipuler les dessins

Depuis le temps que j'en parle... on y arrive enfin !
La grand utilité des Canevas est que les Canvas Objects sont modifiables. Concrètement, ça veut dire quoi ? Cela signifie que vous pouvez changer les coordonnées d'un rectangle, la couleur d'un texte... vous pouvez changer toutes les propriétés de tous les objets du canevas !

Pour changer une propriété, on utilise :
Code : Lua
Code:
1
Code:
Canvas.setAttr(objet, nomPropriete, nouvelleValeur)




C'est tout



Et comment on connaît le nom de la propriété ?

Ces noms sont indiqués au début de la doc ; ils sont de la forme ATTR_XXX, où XXX va être :

  • X1 : abscisse 1
  • Y1 : ordonnée 1
  • X2 : abscisse 2
  • Y2 : ordonnée 2
  • X3 : longueur de la zone à prendre dans la source (pour une Image)
  • Y3 : hauteur de la zone à prendre dans la source (pour une Image)
  • COLOR : couleur
  • COLOR1 : couleur 1
  • COLOR2 : couleur 2
  • COLOR3 : couleur 3
  • COLOR4 : couleur 4
  • TEXT : texte
  • IMAGE : image soure
  • FONT : police spéciale
  • VISIBLE : état visible ou non de l'objet


Bien entendu, tous les objets n'ont pas les mêmes attributs ; le tableau ci-dessous indique quels attributs possèdent tels objets.
ObjetX1Y1X2Y2X3Y3COLORCOLOR1COLOR2COLOR3COLOR4TEXTIMAGEFONTVISIBLE
LineCoordonnéeCoordonnéeCoordonnéeCoordonnée//Couleur///////Est visible
PointCoordonnéeCoordonnéeCoordonnéeCoordonnée//Couleur///////Est visible
RectCoordonnéeCoordonnéeCoordonnéeCoordonnée//Couleur///////Est visible
FillRectCoordonnéeCoordonnéeCoordonnéeCoordonnée//Couleur///////Est visible
GradientRectCoordonnéeCoordonnéeCoordonnéeCoordonnée///CouleurCouleurCouleurCouleur///Est visible
TextCoordonnéeCoordonnée/////////Texte//Est visible
TextFontCoordonnéeCoordonnée/////////Texte/Police spécialeEst visible
TextBoxCoordonnéeCoordonnéeCoordonnéeCoordonnée///////Texte//Est visible
PointCoordonnéeCoordonnéeCoordonnée dans l'image sourceCoordonnée dans l'image sourceLongueur dans la sourceHauteur dans la source//////Ressource image/Est visible


Sachez aussi que vous pouvez récupérer la valeur d'un attribut grâce à :
Code : Lua
Code:
1
Code:
valeur = Canvas.getAttr(objet, attribut)



Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:52 (2010)    Post subject: Créer un jeu DS Reply with quote

TP1 : L'image qui bouge
Dans ce premier TP vous allez devoir faire bouger une image grâce au stylet.

On va utiliser cette image (enfin, vous prenez ce que vous voulez !) :



(pour l'enregistrer, faites Clic droit - Enregistrer (l'image) sous...)


On réfléchit d'abord !

Avant de se lancer corps et âme dans le code, on va réfléchir un peu.

On va faire bouger l'image en fonction des déplacements du stylet, donc les coordonnées de l'image vont bouger. Le plus simple est donc de stocker l'abscisse et l'ordonnée de l'image dans des variables.
Les valeurs de ces variables seront donc les coordonnées du stylet.


N'oubliez pas d'initialiser les variables à zéro avant la boucle !

En fait, ça n'est pas vraiment gênant si vous ne le faites pas, mais c'est une bonne habitude à prendre (par exemple si vous essayez un jour un langage plus typé que Lua).


Maintenant, vous pouvez lâcher le codeur qui est en vous !


3, 2, 1, Partez !


C'est bon
?


C'était pas trop dur, non
?
Allez voici ma correction :

Secret (cliquez pour afficher)

Code : Lua
Code:
 1 2 3 4 5 6 7 8 91011121314151617181920212223242526

Code:
image = Image.load("tp.png", VRAM) -- On charge l'imagex = 0 --  On crée les variables abscisse et ordonneey = 0while not Keys.held.Start do -- On crée la boucle de pause    Controls.read() -- On met à jour les commandes    if Stylus.held then -- La condition "si le stylet est appuyé"    -- Alors les variables x et y prennent la valeur des coordonnées du stylet        x = Stylus.X         y = Stylus.Y    end    screen.blit(SCREEN_DOWN, x, y, image) -- On affiche l'image    render()end-- On efface l'image de la mémoireImage.destroy(image)image = nil-- On efface nos variables abscisse et ordonneex = nily = nil







Si vous n'avez pas fait la même chose (enfin, ça doit pas être bien différent
) mais que ça marche, c'est bien !
Si vous n'avez pas réussi, relisez ce code pour bien le comprendre, et votre cours.


Des améliorations

Si le cœur vous en dit, vous pouvez très bien améliorer ce script :
  • On peut aller plus vite, et sans passer par des variables ! (réfléchissez-y avant de regarder
    )
    Secret (cliquez pour afficher)
    Code : Lua
    Code:
     1 2 3 4 5 6 7 8 9101112

    Code:
    image = Image.load("tp.png", VRAM)while not Keys.newPress.Start do    Controls.read()       screen.blit(SCREEN_DOWN, Stylus.X, Stylus.Y, image)       render()endImage.destroy(image)image = nil




  • Ce script est pas mal, mais ça serait peut-être mieux si on pouvait bouger l'image par son centre ?
    Aide :
    Secret (cliquez pour afficher)
    Aidez-vous de Image.width() et Image.height() !


    Secret (cliquez pour afficher)
    Code : Lua
    Code:
     1 2 3 4 5 6 7 8 9101112

    Code:
    image = Image.load("tp.png", VRAM)while not Keys.newPress.Start do    Controls.read()       screen.blit(SCREEN_DOWN, Stylus.X - Image.width(image) / 2, Stylus.Y - Image.height(image) / 2, image)       render()endImage.destroy(image)image = nil



    Ce code repose sur une astuce tout bête : on obtient le centre de l'image avec la moitié de la longueur et de la largeur ; pour bouger le centre, on additionne ces moitiés aux coordonnées correspondantes.


  • Allez, et on peut aussi, pourquoi pas, afficher les coordonnées !
    Bon, là je ne vous mets pas de correction, vous êtes grands hein ?



TP2 : Un morpion
En deuxième TP, je vous propose le classique mais néanmoins efficace jeu du morpion.


Etude préliminaire

Avant de coder, on réfléchit un peu...

Déroulement général
Pour ceux qui ne connaîtraient pas le principe, le but du morpion est d'aligner trois croix (ou trois ronds) dans une grille de 3*3 cases, horizontalement, verticalement, ou en diagonale. Les deux joueurs jouent chacun leur tour. Les joueurs posent le premier symbole à tour de rôle.
On va convenir que le premier joueur a les croix, le second a les ronds.
On va se contenter d'un mode Deux joueurs, parce que c'est déjà un bon entraînement que de faire ça, et ensuite, la conception d'une IA est beaucoup plus longue. De plus, l'algorithmique n'est pas le but de ce TP.

Maintenant, comment va se dérouler exactement une partie ? A chaque tour, le joueur qui commence pose son symbole dans la case qu'il veut. Puis c'est à l'autre joueur. Dès que trois symboles sont alignés, la partie s'arrête.

Point de vue technique
Je pense que le plus simple pour choisir l'endroit où l'on met sa croix ou son rond est encore l'utilisation de l'écran tactile

Le joueur va toucher une case pour désigner l'endroit où il veut poser le symbole. Il faudra donc déterminer à partir des coordonnées du stylet la case désignée SI le stylet est appuyé (j'insiste là-dessus, sans cette précaution ça peut faire des choses bizarres
).


Si vous avez visité le forum µLua, vous aurez certainement entendu parler de la lib StylusBox de killer01. Elle fait exactement ce que l'on va faire ici, cependant je pense qu'il est bien plus intéressant de le faire à la main
(et c'est aussi plus rapide, si vous trouvez la bonne façon de faire).


Cependant, il faut aussi vérifier que la case n'est pas déjà prise. Ce qui nous amène à une autre question : comment stocker dans des variables les symboles ? On va utiliser ce que l'on appelle un tableau à deux dimensions.


Gné ?
Cékoissa ?

C'est en fait très simple : on a une table, dont chaque élément va, par exemple, représenter une ligne (on peut très bien faire par colonne). Dans notre cas, cette table aura donc trois éléments. Cependant, chaque ligne a elle-même trois cases. Les éléments de la première table seront donc des tables de trois cases chacune. Vous avez compris ?


On revient au stockage des symboles : les cases contiendront des Strings, "X" pour les croix, et "O" pour les ronds.
Si le stylet est pressé entre telle et telle valeur en ordonnée, c'est qu'on est dans telle ligne. S'il est pressé entre telle et telle valeur en abscisse, c'est qu'on est dans telle case. Et maintenant qu'on sait quelle case a été choisie... je vous laisse faire



Bon, d'accord. C'était pas si compliqué. Mais j'ai une question : comment on sait si on a aligné trois symboles ?

Ah, ça je vous laisse réfléchir

Si vraiment vous ne trouvez pas, il y a un peu d'aide plus bas... Mais n'allez pas voir tout de suite !


Et l'affichage de la grille, et des symboles ?

Cessez de poser tant de questions ! Vous tracez quatre lignes, vous faites deux boucles l'une dans l'autre, et c'est bon !


A vos éditeurs de texte !

L'heure est venue de coder !

Prenez votre temps, ce script est relativement simple à mettre en place. Si vous bloquez, réfléchissez bien à la façon dont se déroule la partie.

Vous ne trouvez pas comment vérifier si trois symboles sont alignés ? Vous avez pourtant réfléchi toute la journée, sans succès ? Vous êtes désespéré au point de vous jeter par la fenêtre ?
Alors avant de sauter, regardez plutôt ça :
Secret (cliquez pour afficher)
Il y a, pour chaque symbole, huit configurations possibles de victoire :
  • la diagonale haut-gauche / bas-droite, qui correspond donc à la première case de la première ligne, la seconde case de la seconde ligne, et la troisième case de la troisième ligne
  • la diagonale haut-droite / bas-gauche, qui correspond à la troisième case de la première ligne, etc.
  • les lignes
  • les colonnes (première case de la première ligne, première case de la seconde ligne, etc.)


Quand le joueur qui a les croix a fini de jouer, on regarde si des croix correspondent à cette configuration ; et pareil pour les ronds.
Si avec ça vous ne trouvez pas...





3, 2, 1, Partez !

Correction

*son de cloche* C'est fini !

Alors, vous y êtes arrivés ?
Voici ma version du code ; bien sûr, si vous n'avez pas la même mais que ça marche, c'est bien !

Code : Lua
Code:
  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
Code:
symboles = {{"", "", ""}, {"", "", ""}, {"", "", ""}}joueur = "X"quitter = false-- Couleurblanc = Color.new(31, 31, 31)bleu = Color.new(0, 0, 31)rouge = Color.new(31, 0, 0)function alignes(symboles, joueur)   -- On inverse le  symbole du joueur reçu, car on reçoit le joueur suivant, pas celui qui vient de jouer   local joueurPrecedent = ""      if joueur == "X" then      joueurPrecedent = "O"   else      joueurPrecedent = "X"   end      -- Teste si on a un alignement sur une ligne   for i, ligne in ipairs(symboles) do      if ligne[1] == joueurPrecedent and ligne[2] == joueurPrecedent and ligne[3] == joueurPrecedent then         return true      end   end   -- Teste si on a un alignement sur une colonne   for i = 1, 3 do      if symboles[1][i] == joueurPrecedent and symboles[2][i] == joueurPrecedent and symboles[3][i] == joueurPrecedent then         return true      end   end   -- Teste si on a un alignement sur la diagonale haut-gauche / bas-droite   if symboles[1][1] == joueurPrecedent and symboles[2][2] == joueurPrecedent and symboles[3][3] == joueurPrecedent then      return true   end   -- Teste si on a un alignement sur la diagonale haut-droite / bas-gauche   if symboles[1][3] == joueurPrecedent and symboles[2][2] == joueurPrecedent and symboles[3][1] == joueurPrecedent then      return true   end   -- Si on est arrivé jusqu'ici, c'est qu'un n'a pas trouvé d'alignement, donc on renvoie false   return falseendwhile not quitter and not alignes(symboles, joueur) do   --[[\\ AFFICHAGES DIVERS //]]--      -- Notez que j'ai fait des cases de 20*20, c'est totalement arbitraire   -- J'admets qu'un caractère fait 5px de large sur 8px de haut      -- Affichage des lignes verticales   screen.drawLine(SCREEN_DOWN, 20, 0, 20, 60, blanc)   screen.drawLine(SCREEN_DOWN, 40, 0, 40, 60, blanc)      -- Affichage des lignes horizontales   screen.drawLine(SCREEN_DOWN, 0, 20, 60, 20, blanc)   screen.drawLine(SCREEN_DOWN, 0, 40, 60, 40, blanc)      -- Affichage des symboles   for i, elem in ipairs(symboles) do                          -- Utiliser la boucle for de cette façon est un choix personnel, on aurait tout aussi bien pu faire "for i = 1, 3 do"      for j = 1, 3 do                           -- Pour chaque case de la ligne...         screen.print(SCREEN_DOWN, 7+20*(j-1), 6+20*(i-1), elem[j])      -- Les calculs bizarres, c'est pour centrer à peu près les symboles dans les cases (c'est pas grave si vous ne les comprenez pas, mais c'est à mon sens la seule façon de les centrer)      end      end      -- Affichage du joueur qui doit jouer   screen.print(SCREEN_DOWN, 0, 100, "C'est au joueur des "..joueur.." de jouer.", bleu)      screen.print(SCREEN_DOWN, 0, 180, "Appuyer sur Start pour quitter.")      render()   --[[\\ AFFICHAGES DIVERS //]]--      --[[\\ GESTION DES EVENEMENTS //]]--   Controls.read()      if Stylus.held then      for y = 1, 3 do         if Stylus.Y >= 20*(y-1) and Stylus.Y < 20*y then            for x = 1, 3 do               if Stylus.X >= 20*(x-1) and Stylus.X < 20*x then                  if symboles[y][x] == "" then                     symboles[y][x] = joueur                     if joueur == "X" then                        joueur = "O"                     else                        joueur = "X"                     end                  end               end            end         end      end   end      if Keys.newPress.Start then      quitter = true   end   --[[\\ GESTION DES EVENEMENTS //]]--end-- Si on sort de la boucle, c'est qu'un joueur a gagnéwhile not quitter and not Keys.newPress.Start do   Controls.read()      local joueurPrecedent = ""      if joueur == "X" then      joueurPrecedent = "O"   else      joueurPrecedent = "X"   end      -- Affichage des lignes verticales   screen.drawLine(SCREEN_DOWN, 20, 0, 20, 60, blanc)   screen.drawLine(SCREEN_DOWN, 40, 0, 40, 60, blanc)      -- Affichage des lignes horizontales   screen.drawLine(SCREEN_DOWN, 0, 20, 60, 20, blanc)   screen.drawLine(SCREEN_DOWN, 0, 40, 60, 40, blanc)      -- Affichage des symboles   for i, elem in ipairs(symboles) do      for j = 1, 3 do         screen.print(SCREEN_DOWN, 7+20*(j-1), 6+20*(i-1), elem[j])      end      end      -- Affichage du gagnant   screen.print(SCREEN_DOWN, 0, 100, "LE JOUEUR DES "..joueurPrecedent.." A GAGNE !", rouge)      render()endsymboles = niljoueur = nilblanc = nilbleu = nilrouge = nil




Voilà, voilà.
Pour déterminer l'endroit où l'on choisit de mettre le symbole, la première chose qui vient à l'esprit est de faire plusieurs if, mais c'est long, et on répète plusieurs fois la même chose ; et ça, en programmation, saymal. Alors que si l'on réfléchit un minimum, on s'aperçoit qu'un schéma est visible. On n'a plus qu'à le mettre en place avec deux boucles !

Mine de rien, avec le peu qu'on a appris, on peut faire beaucoup de choses !

Améliorations

On ne fait pas de TP sans améliorations à proposer !

  • Faites en sorte que l'on puisse rejouer après avoir fini la partie. N'oubliez pas qu'il faut changer de premier joueur à chaque partie !
  • Mettez en place un système de score ; chaque partie gagnée rapporte un point
  • Vous pouvez aussi améliorez l'esthétisme de ce morpion (parce que là, j'veux pas dire, mais c'est moche
    )
  • Si vous vous en sentez le courage, programmez une IA ! C'est un excellent exercice de réflexion
  • Et tant que vous y êtes, concevez un menu pour choisir entre le mode Un joueur et Deux joueurs !



Vous avez vu, c'est pas trop difficile si on connait bien son cours, non
?

Allez, vous pouvez vous reposer. Vous avez bien travaillé !


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:53 (2010)    Post subject: Créer un jeu DS Reply with quote

Préparation de la map
Présentation

Tout d'abord, il faut savoir ce qu'est une map.

Une map, c'est une carte (traduction littérale du mot anglais
). Et cette carte est constituée de tiles (ou tuiles en français), qui correspondent en fait à des cases.

Avec MicroLua, un map est constituée de deux fichiers : une image PNG, qui contient les images des tuiles, et un fichier .map, qui contient la structure de la carte. On y reviendra.
Du point de vue du script ensuite : la map peut être modifiée (on peut changer une tuile depuis le programme très facilement) et bougée (on peut la faire défiler). On l'affiche et la détruit comme l'on manipulerait une image.

Les images des tiles

Premièrement, il nous faut un fichier qui contient les images des tiles.

C'est un simple fichier PNG de taille carrée, qui a en général comme longueur et largeur des multiples de 8. La raison est que les écrans de la DS ont eux-mêmes des longueurs multiples de 8 (256 / 8 = 32 et 192 / 8 = 24), ainsi en affichant la map, on est sûr qu'elle prendra bien tout l'espace.

Ce fichier contient dons les tiles. Ce sont des carrés en général de 8*8px (vous savez donc pourquoi).
Si vous ne prenez pas tout l'espace de l'image avec vos tuiles, ça n'est pas grave, vous pouvez laissez l'espace vide tel quel.

Le fichier .map

Mais qu'est-ce donc que cet obscur fichier .map ?
Ça n'est rien de plus qu'un simple fichier texte qui contient comme je l'ai dit plus haut la structure de la map. Et comment il fait ?

Chaque ligne représente une ligne de la carte. Et chaque ligne est constituée de chiffres, séparés par un pipe (caractère sur la touche du chiffre 6 sur la partie alphanumérique, accessible via Alt Gr. + 6). Les chiffres correspondent aux numéros des tiles dans le fichier PNG. Notez que la numérotation commence à 0, et se fait de gauche à droite sur chaque ligne.
En schéma c'est mieux :



Ce fichier ressemble donc à quelque chose comme :
Code : Autre
Code:
123456789101112131415
Code:
1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|0|0|1|2|3|1|2|3|1|1|1|1|1|1|1|0|0|1|1|1|1|1|1|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|1|2|3|





Pour la suite de ce tutoriel, et pour ceux qui voudront tester les fonctions étudiées, vous pouvez utiliser l'exemple fourni dans le dossier "Examples->maps", qui contient un fichier map et son fichier PNG associé.

Utilisation dans vos programmes
Vie et mort de la map

Première chose à faire pour utiliser notre map : la charger !

D'abord, on charge le fichier PNG comme une image :
Code : Lua
Code:
1

Code:
tiles = Image.load("tiles.png", VRAM)



Ensuite, on charge le fichier map :
Code : Lua
Code:
1

Code:
map = Map.new(tiles, "map.map", 15, 15, 32, 32)



"15, 15", ce sont la longueur et la largeur de la map, en tiles.
"32 , 32", ce sont les dimensions d'une tile, en pixels.

Comme vous le voyez, utiliser des tiles carrées n'est pas une obligation, mais c'est en général ce qui est utilisé.

Pour détruire la map, on fait comme cela :
Code : Lua
Code:
12

Code:
map = Map.destroy(map)map = nil



N'oubliez pas de détruire aussi l'image des tiles


Affichage de la map

C'est la fonction :
Code : Lua
Code:
1

Code:
Map.draw(SCREEN_DOWN, map, 10, 10, 5, 5)



Avec dans l'ordre : l'écran, la map à afficher, les coordonnées X et Y du coin haut-gauche de la map, et le nombre de tiles à afficher, sur la longueur et sur la hauteur.

Manipulation de la map

Il est possible de modifier deux choses dans une carte :
  • l'espace entre les tiles :
    Code : Lua
    Code:
    1

    Code:
    Map.space(map, longueur, hauteur)



    Très facile donc, on donne l'espace sur la longueur (entre deux tiles voisines horizontalement) et sur la hauteur (entre deux tiles voisines verticalement), tout ça en pixels bien sûr.
  • la valeur d'une tile :
    Code : Lua
    Code:
    1

    Code:
    Map.setTile(map, x, y, valeur)



    On donne à la fonction la map, puis le numéro de la colonne, puis de la ligne de la tile à changer ; enfin, on passe en dernier argument le nouveau numéro de la tile.


Notez qu'il existe la fonction Map.getTile(), qui à l'image de setTile(), permet d'obtenir la valeur d'une tuile.
Code : Lua
Code:
1

Code:
Map.getTile(map, x, y)




Faire défiler la map

Ah, enfin quelque chose d'utile !


D'abord, petite explication sur comment les jeux avec un système de map sont faits : au centre de l'écran, le sprite du personnage, qui ne bougera jamais. L'image change suivant les actions du joueur (vue de dos, pendant qu'il attaque, etc.). Seule la carte bouge. Par exemple, si on appuie sur la flèche droite, le personnage semble aller à droite ; en fait, c'est la carte qui défile vers la gauche.

Pour faire défiler notre map, on utilise la fonction :
Code : Lua
Code:
1

Code:
Map.scroll(carte, x, y)



"x" représente le nombre de tiles à faire défiler horizontalement, et "y" le nombre de tiles verticalement.
Bien entendu, x et y peuvent être négatif : si x est négatif, alors la carte défile vers la gauche, et si y est négatif, elle défile vers le haut.

Les Scrollmaps
T'as parlé de Scrollmaps dans le titre. C'est quoi la différence avec les maps normales ?


C'est un peu comme le dessin classique et les canvas : les scrollmaps sont plus rapides à afficher, et on peut les faires scroller (défiler) pixel par pixel. Cependant, on y perd aussi les fonctions setTile(), getTile() et space(). De plus, elles ne peuvent être affichées qu'en plein écran.

Pour les fonctions qui restent, les différences sont donc que ce n'est plus Map.fonction() mais ScrollMap.fonction().
La fonction ScrollMap.draw() ne demande plus que la map à afficher (puisque l'on est forcé de l'afficher en plein écran), et ScrollMap.scroll() demande des valeurs en pixels et non plus en tiles.

A vous de voir ce qui vous intéresse le plus ; pour ma part, je pense que c'est bien de gagner la rapidité d'affichage, mais seulement si l'on est sûr que l'on n'aura pas besoin de modifier la composition de la map pendant le programme.


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:53 (2010)    Post subject: Créer un jeu DS Reply with quote

Les fichiers
µLua permet de faire deux choses : renommer et supprimer un fichier.

System.rename()

Pour renommer un fichier ou un dossier vide, la fonction est System.rename(), utilisée de cette façon :
Code : Lua
Code:
1

Code:
System.rename(ancienNom, nouveauNom)




Je pense que je n'ai rien de plus à dire là-dessus


System.remove()

C'est donc la fonction de suppression de fichier ou de dossier vide. Le seul argument requis est (logiquement) le nom du fichier ou du dossier vide à supprimer.
Rien de plus à dire là non plus


Il y a en fait plus de fonctions au niveau des dossiers, ce que nous allons voir maintenant.

Les dossiers
System.makeDirectory()

Ça, c'est la fonction pour créer un dossier. Tout ce que vous avez à faire, c'est de lui donner le nom du dossier.


A partir de là, on va voir des fonctions pour naviguer et se repérer dans les dossiers, ce qui est bien plus intéressant


System.changeDirectory()

Cette fonction sert à se déplacer dans l'arborescence. On lui donne un chemin, et on y est


Ce chemin peut très bien être relatif (c'est-à-dire par rapport à la position actuelle) ou absolu (c'est-à-dire par rapport à la racine du linker). Notez que la notation est de type Unix, par conséquent on utilise les slashes "/" et non pas les anti-slashes de Windows "\". La racine (le "premier grand dossier" qui contient tous les autres) est désignée par le slash "/" au début du chemin. Vous pouvez aussi utiliser "fat:/", ce qui revient au même. Enfin, sachez que "." (un point seul) correspond au dossier courant, et que ".." (deux points simples) correspond au dossier qui contient le dossier courant.

System.currentDirectory()


Fuaaaa, j'me suis perduuuuuu



Rien de grave, utilisez System.currentDirectory(), cette fonction vous retournera le dossier en cours (chemin absolu).

Sytem.listDirectory()

Cette fonction retourne, sous forme de table, la liste de tous les fichiers et dossiers du dossier passé en argument (là aussi, ça peut être un chemin relatif ou absolu).

A moins d'être à la racine, les deux premières entrées de la table seront toujours "." (dossier courant) et ".." (dossier contenant le dossier courant). D'ailleurs, sachez que la fonction classe automatiquement les dossiers au début et les fichiers à la fin.
La table contient en fait des tables, qui possèdent elle-mêmes deux entrées : l'une correspond au nom du fichier (ou dossier), et l'autre est un Booléen qui permet de savoir si c'est un fichier ou un dossier.

Code : Lua
Code:
 1 2 3 4 5 6 7 8 91011121314

Code:
files = System.listDirectory(System.currentDirectory())    -- On obtient la liste du contenu du dossier courantwhile not Keys.newPress.Start do    for i, elem in pairs(files) do    -- C'est à mon sens la façon la plus maligne d'exploiter la liste        if elem.isDir then    -- Si c'est un dossier...            screen.print(SCREEN_UP, 0, i*8-8, elem.name, Color.new(31, 0, 0))    -- On affiche son nom en rouge        else    -- Si au contraire c'est un fichier...            screen.print(SCREEN_UP, 0, i*8-8, elem.name, Color.new(0, 0, 31))    -- On affiche son nom en bleu        end    end    render()endfiles = nil



Ce bout de code présente donc une façon très simple d'utiliser la table retournée par listDirectory().
Vous voyez aussi comment on accède au nom et à la variable qui permet de savoir si c'est un dossier ou un fichier : elem.name donne le nom, et elem.isDir est un booléen qui vaut true si c'est un dossier (et donc false si c'est un fichier
). Bien entendu, vous pouvez accéder à ces variables sans passer par une boucle :
Code : Lua
Code:
12

Code:
nom = files[2].namedossier = files[2].isDir




TP : utilisation des fichiers INI
Cette partie est un TP-tuto, qui va vous permettre d'appréhender les fonctions sur les fichiers INI, mais aussi d'utiliser les fonctions vues précédemment (enfin, surtout celles sur les dossiers
).

But du TP

On va faire quelque chose de très simple : en nous basant sur un fichier INI, on va accueillir l'utilisateur en affichant son nom dans la couleur donnée par le fichier INI. On va aussi lui permettre de modifier son nom depuis le programme.


Les fichiers INI
C'est quoi ?

Déjà, c'est un fichier dont l'extension est ".ini".


C'était pas dur à deviner en même temps


On sait jamais.

Ces fichiers servent à conserver la configuration et la personnalisation de programmes. Ce type de fichier a été introduit par Windows dès les premières versions de l'OS, bien que maintenant ils aient été pour la plupart remplacés par le Registre.

Ils ont tous la même structure :
Code : Autre
Code:
1234
Code:
[catégorie]; Commentairevariable=valeurvariable2=autreValeur ; Commentaire



Quel que soit le type de valeur (chaîne de caractères ou nombre), il n'y a pas de guillemets ou de notation spéciale (de toute façon, vous verrez que pour les fonctions de µLua, c'est tout du String
).


Les utiliser avec µLua


Parce que c'est bien beau tout ça, mais on sait toujours pas comment nous en servir dans nos homebrews !

On y arrive


µLua met à notre disposition deux fonctions : une pour lire le fichier, et l'autre pour enregistrer les données.
Code : Lua
Code:
1234

Code:
config = INI.load(fichier)    -- Chargement du fichierparam = config["catégorie"]["variable"]    -- Accès à la valeur de "variable" dans la catégorie "catégorie" (j'ai vraiment trop d'imagination pour les noms moi :p )config["catégorie"]["variable2"] = "blabla"    -- On change la valeur de "variable2" dans la catégorie "catégorie"INI.save(fichier, config)    -- On sauvegarde la config





Avec Micro Lua Simulator le .ini devra se trouver dans la dossier de Micro Lua Simulator et non dans celui du script.


Voilà, INI.load() sert à lire le fichier : elle renvoie une table dans le genre tableau associatif (avec des index qui ne sont pas des nombres), qui contient pour chaque catégorie une table qui correspond à cette catégorie. Les index portent logiquement les noms des catégories et des variables.
INI.save() permet d'enregistrer la table dans le fichier.


La table enregistrée dans le fichier ne peut contenir que des Strings ! Si vous souhaitez enregistrer un nombre, vous devez le convertir en string à l'aide de la fonction tostring().



Et le nôtre ?

Pour être sûr d'avoir la même base, voici le fichier INI que je vais utiliser :
Code : Autre
Code:
1234567891011
Code:
[color]; Par défaut, la couleur sera le blanc (31, 31, 31)rouge=31vert=31bleu=31[nom]; Par défaut, la variable est videnom=



S'il ne vous plaît pas, vous pouvez très bien changer sa structure, mais il faudra alors penser à adapter le code en conséquence



Modifier le nom du bonhomme

Avant µLua 3.0, ça aurait été très simple, puisque µLua intégrait par défaut un clavier. Or, depuis cette version, il n'y est plus. Mais... des membres dévoués de la communauté ont mis au point des claviers particulièrement bien faits.
  • Clavier de Papymouge : le premier, l'ancêtre
  • Clavier de thermo_nono : amélioration de celui de Papymouge (le clavier est désormais personnalisable)
  • Clavier de Quent42340 : un autre, le dernier à avoir vu le jour


J'ai une préférence pour celui de thermo_nono, car j'aime bien les skins et la personnalisation ; bien entendu, cet avis n'engage que moi. Mais comme le but de ce TP n'est pas de vous apprendre à embellir vos homebrews, je vais utiliser celui de Papymouge. Vous pouvez le trouver ici.


Utilisation du clavier

Je ne présenterai ici que le clavier de Papymouge, et encore juste pour que vous sachiez comment vous en servir pour que l'utilisateur puisse entrer son nom
Si vous voulez en utiliser un autre, je ne peux que vous conseiller de farfouiller sur le forum de µLua (notez la fonction "Rechercher" en haut
).

En premier lieu, il faut charger la lib :
Code : Lua
Code:
1

Code:
dofile("clavier.lua")



Le but n'étant pas de vous apprendre à intégrer une lib dans votre programme, je vous renvoie à cet annexe qui parle un peu plus de dofile().

Il faut donc que vous fournissiez avec votre programme le fichier "clavier.lua", mais aussi l'image "Clavier.PNG" que le clavier utilise. Ils doivent être dans le même dossier, cependant ils peuvent être dans un dossier différent de celui de votre programme ; il suffit d'adapter en conséquence le dofile().

Ensuite, il faut initialiser le clavier :
Code : Lua
Code:
1

Code:
newClavier(x, y)



"x" et "y" sont les coordonnées du clavier. La lib définit une constante "C_CENTER" qui permet de centrer le clavier horizontalement et verticalement, selon le paramètre qu'il remplace.

Il faut aussi l'afficher à chaque tour de boucle :
Code : Lua
Code:
1

Code:
showClavier()



La fonction peut prendre divers arguments, mais ils sont inutiles ici.

Pour récupérer l'entrée de l'utilisateur, c'est la fonction :
Code : Lua
Code:
1

Code:
touche = clavierHeld(Stylus.X, Stylus.Y)



Elle renvoie la lettre pressée, ou "ent" si on appuie sur "Entrée", ou "del" si on appuie sur "Retour arrière" (ou "" si on n'appuie sur rien
). On doit lui passer en argument les coordonnées du stylet.

Enfin, pour détruire le clavier à la fin du script, c'est :
Code : Lua
Code:
1

Code:
delClavier()




On va dire que l'on enregistrera si l'utilisateur appuie sur "Entrée". Le bouton Start permettre de quitter sans sauvegarder.


Codons !

Bon, je vous ai déjà dit beaucoup de choses, et je sais que vous avec hâte de coder

Je vous conseille juste de réfléchir un peu avant de foncer tête baissée, même si ce script n'est pas bien compliqué. Rappelez-vous ce que doit faire le programme, et ça ira



3, 2, 1, Partez !


Need help

Vous galérez sur le retour arrière du clavier ? Si oui, vous avez de la chance : j'ai là une petite aide. Si non... et bien c'est ballot


Indice 1 :
Secret (cliquez pour afficher)
Pour gérer le retour arrière, on doit utiliser la fonction string.sub() (fonction de base de Lua)... Lisez la doc




Indice 2 :
Secret (cliquez pour afficher)
Toujours pas trouvé ? Allez, je vous aide encore un peu... Il faut faire une galipette avec une des deux bornes données à la fonction string.sub() qui doit être négative. Mais comment ça négative ?




Correction

Ayé, fini !

Alors, facile hein ?


Voici ma correction :
Code : Lua
Code:
 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233

Code:
dofile("clavier.lua")newClavier(C_CENTER, 10)      -- J'ai décidé de placer le clavier au milieu de l'écran, à 10px du hautconfig = INI.load("tp_INI.ini")      -- A adapter avec le nom de votre fichier INIcouleur = Color.new(tonumber(config["couleur"]["rouge"]), tonumber(config["couleur"]["vert"]), tonumber(config["couleur"]["bleu"]))while not Keys.newPress.Start do   Controls.read()      screen.print(SCREEN_UP, 0, 0, "Votre nom est :", couleur)   screen.print(SCREEN_UP, 0, 8, config["nom"]["nom"], couleur)   screen.print(SCREEN_UP, 0, 50, "Appuyez sur \"Entrée\" pour enregistrer", couleur)   screen.print(SCREEN_UP, 0, 58, "et sur Start pour quitter.", couleur)      showClavier()      render()      local touche = clavierHeld(Stylus.X, Stylus.Y)   if touche ~= "" then                           -- Si l'utilisateur a tapé quelque chose      if touche == "ent" then                        -- Si l'utilisateur a appuyé sur "Entrée"...         INI.save("tp_INI.ini", config)                  -- ... on enregistre.      elseif touche == "del" then                     -- Si l'utilisateur a appuyé sur "Retour arrière"         config["nom"]["nom"] = string.sub(config["nom"]["nom"], 1, -2)      -- On élimine la dernière lettre      else                              -- Si l'utilisateur a appuyé sur une touche "normale"         config["nom"]["nom"] = config["nom"]["nom"]..touche      end   endendconfig = nildelClavier()couleur = nil





Comme vous l'avez remarqué on à utilisé tonumber() car on enregistre que des strings dans un ini et Color.new() ne prend que des nombres donc on doit convertir nos strings en nombres grâce à tonumber()


Je ne pense pas que ça vous aura été difficile de trouver quelque chose de fonctionnel



Les améliorations !

Je vois pas grand chose, le script n'est pas très conséquent en même temps...
Vous pourriez permettre à l'utilisateur de choisir la couleur parmi quelques unes depuis le programme (faites des boutons par exemple ^^), et modifier tout de suite la couleur sans avoir à recharger le fichier INI. N'oubliez pas que INI.save() ne peut enregistrer qu'une table contenant des chaînes de caractères !
Vous pourriez aussi vérifier que les valeurs de rouge, vert et bleu du fichier INI sont bien entre 0 et 31 ; le cas échéant, affichez le texte en blanc et un message d'erreur en rouge



Avec ce que nous avons vu, vous pouvez très bien faire un petit explorateur de fichier pour la DS, avec toutes les fonctions de base (copie, suppression...)


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:54 (2010)    Post subject: Créer un jeu DS Reply with quote

Qu'est-ce qu'un sprite ?
Il convient en premier lieu d'expliquer un peu ce qu'on entend par "sprite" avec MicroLua.

Voici la définition que nous livre la noble encyclopédie Wikipédia :

Citation : Wikipédia : Article 'Sprite (jeu vidéo)'
Un sprite (en français lutin) est dans le jeu vidéo un élément graphique qui peut se déplacer sur l'écran. En principe, un sprite est en partie transparent, et il peut être animé (c’est-à-dire qu'il est formé de plusieurs bitmaps qui s'affichent les uns après les autres).


Concrètement, un sprite se compose de plusieurs images (issues d'un fichier image découpé) ; en changeant l'image affichée, on crée une petite animation, d'un personnage par exemple.
Chaque image qui compose le sprite s'appelle une frame (mot anglais qui désigne ici une image ; les gamers connaissent ce terme par les FPS, ou Frames per Second (images par seconde) ). Avec MicroLua, il est possible d'afficher une seule frame "fixe", ou bien de composer une animation de plusieurs frames choisies individuellement avant de l'afficher, de la mettre en pause, etc.

L'image des frames se comporte comme celle d'une Map ; par conséquent, après avoir chargé le sprite (prochain chapitre), on y accède par un numéro de frame, qui commence à 0.

Comme le dit si bien Wikipédia, "en principe un sprite est en partie transparent". Et pour avoir une partie transparente, µLua définit une couleur qui sera rendue transparente à l'affichage. Comme pour beaucoup de programmes, c'est le rose fuschia qui est utilisé. C'est la couleur RVB (255, 0, 255) (en hexadécimal #FF00FF). Elle est utilisée car elle est en général peut présente dans les dessins.


Maintenant, on va voir comment justement charger un sprite, et comment afficher une de ses frames. A l'attaque !


On commence doucement
Charger le sprite

On commence logiquement par charger le sprite en mémoire. On utilise pour cela la fonction :
Code : Lua
Code:
1

Code:
sprite = Sprite.new("fichier_frames.png", longueur_frame, hauteur_frame, destination)




On charge donc le fichier "fichier_frames.png", qui contient des frames qui font longueur_frame pixels par hauteur_frame pixels. Enfin, on donne comme pour une image la destination du chargement (RAM ou VRAM).
Ça retourne un "objet sprite" (une table en fait), sur laquelle on va utiliser des méthodes (des fonctions).

Première méthode que l'on va essayer :

sprite:drawFrame(ecran, x, y, numFrame)

Certainement la plus simple, drawFrame() permet d'afficher une simple frame à l'écran. On l'utilise...


STOOOOOP ! C'est quoi c't'appel de fonction bizarre avec des deux-points ?

C'est comme ça qu'on appelle en général une méthode en Lua. Tout le jargon de méthode et objet appartient à la POO (Programmation Orientée Objet). C'est un principe de programmation ; comme le but de ce tuto n'est pas de vous l'expliquer, je vous renvoie au cours de M@teo21 sur le C++, et plus précisément sur la partie expliquant ce qu'est la POO.
Je disais donc, que c'est comme cela qu'on appelle une méthode en Lua. On en verra d'autres dans ce cours, et vous serez très certainement amenés à en utiliser dans vos programmes étant donné que beaucoup de libs sont faites en POO


Ou j'en étais moi ?... Ah oui ! On l'utilise donc en remplaçant "sprite" par le nom de la variable qui nous sert à garder le retour de la fonction Sprite.new(). On donne l'écran sur lequel on affiche, les coordonnées, et le numéro de la frame que l'on veut afficher. Et cette frame s'affiche (au prochain render() bien entendu
) !


Mais on se retrouve vite limité avec un simple affichage d'une seule frame ; c'est pour cela que MicroLua permet de constituer des animations.

Les animations de sprites
Ajouter une animation au sprite

Tout commence par là.

Code : Lua
Code:
1

Code:
sprite:addAnimation(table_frames, delais)




table_frames est donc... une table, on suit un peu au fond ! Bref, c'est donc une table qui contient les numéros des frames dont se compose l'animation. Je rappelle que la numérotation des frames commence à 0.
delais est le délai (en millièmes de seconde) entre l'affichage de chaque frame.

Maintenant, on peut afficher l'animation.

Bouton play

On utilise la fonction :
Code : Lua
Code:
1

Code:
sprite:playAnimation(ecran, x, y, numAnim)



x et y sont bien sûr les coordonnées de l'animation. numAnim désigne le numéro de l'animation à jouer. En effet, un sprite peut avoir plusieurs animations : imaginez un personnage, il peut marcher vers le haut, le bas, etc., mais aussi attaquer, jeter un sort... Bref, il faut donner le numéro de l'animation de ce sprite.


La numérotation commence ici à 1, contrairement à celle des frames !


Soumettez-la à votre volonté

Je parle bien sûr de l'animation


Vous pouvez arrêter l'animation :
Code : Lua
Code:
1

Code:
sprite:stopAnimation(numAnim)




Et la remettre au début :
Code : Lua
Code:
1

Code:
sprite:resetAnimation(numAnim)




Et pour la relancer :
Code : Lua
Code:
1

Code:
sprite:startAnimation(numAnim)




Si vous pensez confondre playAnimation() et startAnimation() (car il faut bien dire que pour nous pauvres francophones, les deux veulent dire la même chose), dites vous que playAnimation() est le screen.blit() des Sprites, tandis que startAnimation() et compagnie sont comme les fonctions des Timers (que vous n'avez pas encore vues, c'est pas faux
).


Et en bonus...

MicroLua fournit la fonction
Code : Lua
Code:
1

Code:
sprite:isAnimationAtEnd(numAnim)



qui renvoie true si l'animation a affiché sa dernière frame. Ça peut être utile pour coordonner des sortes de "cinématiques" ou certains effets en parallèle de l'image.


C'est pas fini !

On n'aurait pas oublié quelque chose ? Un Sprite, c'est une image non ? Donc logiquement, il faut vider la mémoire. On fait presque comme pour une image, à ceci-près que ici destroy() est une méthode. On a donc :
Code : Lua
Code:
12

Code:
sprite:destroy()sprite = nil





Vous savez désormais bien utiliser les Sprites.
Passons sans plus tarder au son !


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:55 (2010)    Post subject: Créer un jeu DS Reply with quote

L'instruction dofile()
Afin de tester la procédure, il est conseillé de télécharger la libNumericUpDown qui va nous servir d'exemple.


La façon "classique" utilisée par la communauté MicroLua pour utiliser une librairie, et d'utiliser la fonction dofile() (qui, au passage, est une fonction de base de Lua, et non pas de µLua). La documentation de Lua nous dit que dofile() ouvre le fichier passé en argument, et l'exécute.

On s'en sert donc de cette manière :
Code : Lua
Code:
1

Code:
dofile("libNumericUpDown.lua")



Cette instruction est à placer au début du programme, pour que les fonctions, variables etc. crées par la libs soient accessibles dans tout le reste du programme.

Ensuite, et bien c'est très simple, vous n'avez qu'à appeler les fonctions définies par la libs comme des fonctions normales :
Code : Lua
Code:
123

Code:
objet = NumericUpDown.new(arguments)    -- Instanciation d'un nouvel objet de la classe NumericUpDown (appel du constructeur de classe)objet:draw(Color.new(31, 31, 31))       -- Appel de la méthode draw() de cet objetscreen.print(SCREEN_UP, 0, 0, NumericUpDown.objectCount)    -- Accès à la variable objectCount



Toutes ces instruction doivent être placées après le dofile(), sans quoi ça ne marchera pas.

Tous les termes techniques d'instanciation, constructeur de classe, etc. sont liés à la conception Orientée Objet de cette lib (qui est entre nous soit dit certainement la meilleur façon de faire une lib
). Je ne peux décemment pas vous faire un cours là-dessus, c'est pourquoi je vous renvoie au cours de M@teo21 sur le C++, et plus précisément sur la partie expliquant ce qu'est la POO.

L'instruction require()
Utiliser dofile() est en fait une mauvaise habitude. En effet, Lua dispose d'un système complet de modules, qui gère très bien les libs automatiquement.
N'utilisant que dofile(), je ne maîtrise pas les modules en Lua, c'est pourquoi je ne m'avancerais pas à faire un tuto là-dessus. Je vous invite donc à regarder la section sur les modules de la doc Lua (en anglais malheureusement), qui traite de tout ce qu'il faut savoir là-dessus.

Sachez donc que la meilleure méthode est celle de require(), bien que tout le monde utilise dofile()...


Et bien voilà, vous savez maintenant comment utiliser ce magnifique clavier ou ces superbes contrôles de GUI dans vos programmes !


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:56 (2010)    Post subject: Créer un jeu DS Reply with quote

Sites
Vous voulez des sites sur µLua ?


En voici, en voilà
!

Le site officiel de µLua : ce site en anglais n'est malheureusement plus à jour. Il contient la version 1, 1.0.1 et 2 de µLua ainsi que les documentations de µLua 1.0.1 et µLua 2.
Il contient aussi un tutoriel pour µLua 1.0.1.

Le forum officiel de µLua : ce forum très actif pourra être votre principale aide. La soixante-quinzaine de membres donc une dizaine d'actifs pourront vous aider avec un script défaillant ou autre.
Il y a une section française (très active) et une anglaise (moyennement active).

Le Google Code de µLua : ce site possède un Wiki et permet de télécharger la dernière version de MicroLua. Il est principalement en anglais, bien que certaines pages du Wiki soient traduites en français.

MicroLua DS Underground : ce site fait par un des membres du forum, thermo_nono, contient beaucoup de libs et de homebrews.

MicroLua : c'est le fansite de Aurel2108, fais pour être simple et rapide, il regroupe un uploader de fichiers et une section téléchargements contenant les version de Micro/Nano Lua, les docs, les libs et les homebrews...

MicroLua4DS : c'est le fansite de Reylak, mettant à votre disposition comme µLua DS Underground des libs, des homebrews, etc.

Nano Lua : vous l'aurez deviné, c'est le site de Quent42340, créateur de Nano Lua. Cependant, il remplit aussi le même rôle que les précédents fansites, avec un forum et deux ou trois sections hors-sujet


Documentation
MicroLua

La doc de µLua 3 : (en français (traduite par Reylak) | en anglais)

La doc de µLua 3 en ligne sur le Google Code : (en français | en anglais )

Le tutoriel sur les canevas de MicroLua 2.0 : (en anglais)

Le tutoriel sur le son de MicroLua 3.0 : (en anglais)

La section des tutoriels sur le forum MicroLua : (en français)
Cette section contient quelques tutoriels utiles pour mieux appréhender certains aspects de MicroLua (voire de Lua).

Lua

La doc de Lua 5.1 : (en anglais)

Des tutos pour utiliser Lua 5.1 : (en anglais)



Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:56 (2010)    Post subject: Créer un jeu DS Reply with quote

Editer son script... avec quoi ?
Outre les "classiques" Notepad++ et autres Vims pour quasiment tous les langages, vous pourriez préférer un IDE plus spécifique à µLua, voire même vouloir coder directement sur sa DS !


µLua Creator

Cet IDE développé par Quent42340 offre quelques outils sympathiques permettant de développer plus vite, et en mettant moins les mains dans le code.
Vous pouvez télécharger la version 4.0 beta 3 ici.

Il propose donc un générateur de code, un éditeur de texte avec coloration syntaxique, mais aussi un générateur de code pour le dessin, un éditeur d'évènements, et enfin un éditeur de maps. Il s'intègre de plus avec les testeurs MicroLua Simulator et No$GBA Tester.

Cependant, et sans vouloir dévaloriser le très bon travail de Quent, je pense que l'utilisation abusive de ces assistants n'est pas une bonne chose pour vous qui lisez ce tuto. Ils ne permettent pas d'apprendre à coder comme vous apprendriez en codant "à la main". Bien sûr, quand vous aurez de l'expérience, rien ne vous empêchera de vous servir de µLua Creator



Lua Editor DS

Ça, c'est le fin du fin, c'est Plantafin ! Lua Editor DS (raccourci en LED) vous permet tout bonnement... de coder sur votre DS ! Et on dit... merci samy !

La version 1.3, compatible avec MicroLua 3.0, est disponible ici.

LED est un véritable IDE pour votre console ; il propose des fonctions de base comme le copier-coller, la recherche/remplacement, l'affichage des numéros de ligne, l'indentation intelligente, mais aussi la coloration syntaxique et même l'autocomplétion ! Notez que cette dernière est basée sur le fichier Autocomp ; vous pouvez donc rajouter vos propres mots-clés.
Il permet aussi bien sûr, en plus d'éditer un script, de l'exécuter, puis de revenir l'éditer. C'est donc un must-to-have, indispensable pour coder en nomade.


Notez que vous pouvez personnaliser quelques aspects du logiciel dans le menu des options. Il est conseillé pour coder efficacement, de désactiver la coloration qui malheureusement fait ramer la console, et d'utiliser l'autocomplétion.


Tester son code sur l'ordinateur
Vous vous êtes certainement dit "Aah, si seulement je n'avais pas à mettre mon scripts sur mon linker pour le tester !". Et bien votre vœu est exaucé !


No$GBA Tester

La première façon est d'utiliser l'émulateur Nintendo DS No$GBA (ne vous laissez pas tromper par la mention "GBA", ça marche aussi pour la DS
).
C'est un émulateur, ça signifie qu'il peut lancer sur l'ordinateur des roms (des programmes pour console), en l'occurrence pour la DS. Couplé à un petit système permettant de compiler plus ou moins à la volée une version de µLua pour l'ordinateur, il permet de tester vos scripts sans votre console !

Préparation

No$GBA est fourni dans le dossier "Utilities". Si ce n'est pas déjà fait, décompressez l'archive le contenant. En fait, l'exécutable ne se trouve pas dans l'archive, mais vous pouvez le télécharger ici. Extrayez-le, et mettez-le dans le dossier no$gba Tester.
C'est prêt... ou pas.


Si vous êtes sous Vista, la commande sleep 2 a de fortes chances de ne pas fonctionner, pour la simple et bonne raison qu'elle n'y est plus. Or, elle est indispensable dans le fichier create.bat. Vous devez donc la remplacer par :
Code : Console
Code:
Code:
choice /c 1 /d 1 /t 2 > nul





Vous pouvez aussi trifouiller dans les options de Options->Controls Setup, afin de personnaliser les contrôles.

Testons !

Placez tous vos fichiers à tester dans le dossier fat. Maintenant, lancez create.bat. Une console toute moche en noir et blanc s'affiche (on est à l'époque de la couleur enfin !), avec plein de mots bizarres (on appele ça de l'anglais), jusqu'à une phrase en bon français vous invitant à "Appuyer sur une touche pour continuer...". Obéissez. Puis lancez No$GBA. Dans la fenêtre d'explorateur qui s'est ouverte, sélectionnez la rom luads_fs.nds. Et vous voilà dans le shell de MicroLua ! Vous n'avez plus qu'à lancer votre script.

Ça marcheuh pas !

Il se peut que vous ayez cette erreur :
Code : Console
Code:
Code:
Couldn't open libs.lua



Ça veut dire que le fichier libs.lua est introuvable. Il doit en temps normal se trouve dans le dossier fat (oui, au même niveau que vos scripts).

Parfois, on a cette erreur alors que libs.lua est bel et bien où il faut. Essayez alors de vider le dossier fat, et de ne garder que l'essentiel (les libs de µLua, votre script à tester et out ce dont il a besoin pour tourner). C'est dû au fait que le "compilateur" qui crée la rom donne une taille prédéfinie, qui en général suffit... en général.


MicroLua Simulator

No$GBA, c'est bien ; mais pour le dév, MLS, c'est mieux.
MLS, c'est un programme développé en Lua par Ced-le-pingouin, qui propose une alternative intéressante à No$GBA.
Tout d'abord, pour le télécharger c'est ici. Vous trouverez sur cette page une version pour Linux, une pour Windows, et une pour Mac. Il y a aussi les sources pour les curieux. A vous de choisir la bonne version en fonction de votre OS. La dernière version au moment de l'écriture de ces lignes est la 0.4 beta 2.

Après extraction en bonne et due forme, vous vous retrouvez avec une floppée de fichiers, et au milieu un petit exécutable mls.exe. Lancez-le, puis cliquez-sur File->Open... (Fichier->Ouvrir... en français), et sélectionnez votre script.
Comme vous pouvez le voir, c'est moins fastidieux qu'avec No$GBA.

Je ne vais pas trop détailler son fonctionnement, le Readme en français et en anglais le fera mieux que moi ; il contient notamment la liste des contrôles.


Alors, lequel des deux choisir ?

Chacun a ses avantages et ses inconvénients :

No$GBA Tester :
  • de par la façon dont il teste, il est plus proche de la réalité que MLS, malgré tous les efforts de Ced
  • pas très important mais présent : lorsque que vous appuyez sur la touche Imprim. Ecran de votre clavier, No$GBA envoie dans le presse-papier une image qui contient uniquement les deux écrans accolés, alors que MLS ne le propose pas
  • procédure de test assez longue
  • parfois pénible à faire fonctionner

MicroLua Simulator :
  • outils pour le développeur (mise en pause et redémarrage du script, console d'erreur...)
  • procédure de test rapide et facile
  • le son ne fonctionne pas
  • n'intègre pas les limitations de RAM/VRAM de la console
  • simule à la fois µLua 2.0 et 3.0, sans prévention en cas d'utilisation de fonction spécifique à une version


En fin de compte, les deux se valent à peu près. C'est un peu une affaire de goût, mais de nombreuses personnes ont tendance à privilégier MLS, certainement pour la facilité de test.
Pour ma part, MLS me sert à tester "à la volée", tandis que je dépoussière No$GBA pour avoir un aperçu à coup sûr réaliste des dernières modifications. Cependant, ça ne me dispense pas de tester in situ (c'est-à-dire sur la DS


Back to top
Visit poster’s website
étouraptor
Membre confirmé

Offline

Joined: 16 Mar 2010
Posts: 132
Masculin

PostPosted: Wed 17 Mar - 18:57 (2010)    Post subject: Créer un jeu DS Reply with quote

Voila.
Bonne chance vous en aurais besoin


Back to top
Visit poster’s website
Display posts from previous:   
Post new topic   Reply to topic    Pokémon-Distribution Forum Index -> Divers -> Espace communautaire All times are GMT + 2 Hours
Page 1 of 1

 
Jump to:  

Index | Create a forum | Free support forum | Free forums directory | Report a violation | Cookies | Charte | Conditions générales d'utilisation
Powered by phpBB © 2001, 2005 phpBB Group