[#_lesson_13_a_game_folder] == Leçon 13 : Un dossier de jeu image::learn/13-game-folder.png[La leçon terminée, 480] Votre jeu est un script dans un dossier dont vous vous rappelez le nom, et vous le lancez en tapant son nom dans un terminal. C'est très bien pour vous et inutile pour n'importe qui d'autre. Un joueur devrait pouvoir copier un dossier à côté de Singe, lancer le menu, voir votre jeu dans la liste avec son titre et ses illustrations, et appuyer sur un bouton. L'image ci-dessus, c'est ce menu, avec votre jeu dedans. Il faut pour cela un nouveau fichier, d'environ six lignes, et deux images que vous pouvez prendre avec une seule touche. Votre script ne change pas du tout. [#_give_the_game_a_name] === Donnez un nom au jeu Un jeu a deux noms, un pour l'ordinateur et un pour les gens. Celui de l'ordinateur, c'est le dossier, et vous l'avez choisi à la leçon neuf : `rocks`, avec `rocks.singe` dedans. Le dossier et le script portent le même nom, comme dans chaque leçon depuis la leçon un, et c'est pourquoi `Singe rocks` trouve le script à partir du dossier seul. Gardez ce nom simple. Pas d'espaces, qu'un terminal lit comme l'écart entre deux noms. Et les mêmes majuscules partout où vous le tapez : sur la plupart des ordinateurs qui ne sont pas sous Windows, `rocks` et `Rocks` sont deux dossiers différents, et un jeu qui ne tourne que sur votre machine n'est pas un jeu que quelqu'un d'autre peut avoir. Le nom pour les gens peut être tout ce que vous voulez, majuscules, espaces et tout le reste, et il ne vit pas dans le nom du dossier. Il vit dans le fichier dont parle cette leçon, pour que renommer le jeu dans le menu ne veuille jamais dire renommer un dossier. [#_what_goes_in_the_folder] === Ce qui va dans le dossier Tout ce dont votre jeu a besoin, et rien d'autre. À la fin de cette leçon, il ressemble à ceci : ---- rocks/ games.dat Ce que lit le menu rocks.singe Le jeu art/ Le kit graphique de la leçon neuf spaceship.png asteroid.png bullet.png star.png shoot.wav boom.wav ... cabinet.png Une image que le menu montre à côté de la liste marquee.png Une image que le menu montre au-dessus ---- Tout ce qui a pu atterrir là pendant que vous appreniez -- `walk.singe` de la leçon neuf, le petit test du son de la leçon dix -- ne fait pas partie du jeu. Déplacez-les dans un dossier à eux, à côté de `rocks`. Le kit graphique contient aussi quelques fichiers que ce jeu ne charge jamais, et ils ne font aucun mal pour l'instant. C'est à la leçon trente que vous passerez un dossier de jeu en revue pour en retirer tout ce qui n'est pas le jeu. La règle derrière cette organisation, c'est qu'un jeu ne va jamais rien chercher hors de son propre dossier. Ni une illustration, ni un son, ni une bibliothèque dont vous vous servez aussi dans un autre jeu -- si vous partagez du code entre deux jeux, chacun garde sa propre copie. Il y a exactement un endroit hors du dossier où un jeu a le droit de charger quelque chose, et vous y chargez déjà : le dossier `Singe` du moteur lui-même, où se trouve `Singe/Framework.singe`, et, depuis la leçon dix, le clic et la musique. Le dossier du jeu se trouve dans votre dossier de travail, à côté du moteur : ---- singe/ Votre dossier de travail Singe-v3.00-... Le moteur lui-même, quel que soit le nom du vôtre Menu.sh Lance le menu. Menu.bat sous Windows Singe/ Fichiers de support. Pas à vous ; n'y touchez pas data/ Tout ce qui s'écrit, votre sauvegarde comprise rocks/ Votre jeu ---- C'est aussi la forme qu'a la machine d'un joueur. Le moteur a écrit `Singe`, `data` et `Menu.sh` (`Menu.bat` sous Windows) la première fois que vous avez lancé quoi que ce soit, à la leçon un. La leçon un a parlé des deux premiers. Le troisième est nouveau pour vous, et cette leçon le met au travail. [#_paths_count_from_where_singe_started] === Les chemins partent de l'endroit où Singe a démarré Vous faites ça depuis la leçon neuf, donc c'est un rappel, pas un changement. Chaque nom que votre jeu charge -- `art/spaceship.png`, `art/boom.wav` -- est cherché à partir du dossier dans lequel Singe a été *lancé*, et non du dossier où se trouve votre script. Vous lancez Singe dans votre dossier de travail, donc un simple `art/spaceship.png` serait cherché dans `singe/art`, qui n'existe pas. `DIR` est le dossier de votre script lui-même, avec la barre oblique déjà au bout, donc un nom qu'on y colle désigne votre fichier, d'où que Singe ait été lancé : [source,lua] ---- local shipSprite = spriteLoad(DIR .. "art/spaceship.png") ---- Le menu lance Singe dans le dossier où se trouve `Menu.sh`, c'est-à-dire de nouveau votre dossier de travail, donc `DIR` y fait exactement ce qu'il fait pour vous. Il continue de le faire quand le jeu est empaqueté dans un seul fichier à la leçon trente, quand le dossier de travail de quelqu'un d'autre s'appelle tout autrement, et sur une machine que vous ne verrez jamais. Un nom qui commence par `Singe/` désigne le dossier du moteur et n'a jamais besoin de `DIR` ; chaque nom qui est à vous en a besoin. [#_games_dat] === games.dat `games.dat`, c'est la façon dont un jeu se présente. Le menu lit le `games.dat` de chaque dossier de jeu qui se trouve à côté de lui, et liste ce qu'il trouve. Pas de `games.dat`, pas de place dans la liste : votre dossier est invisible, aussi bon que soit le jeu qu'il contient. Créez un nouveau fichier appelé `games.dat` dans votre dossier `rocks`. Voici le plus petit qui marche : [source,lua] ---- GAMES = { { TITLE = "Rocks", SCRIPT = "rocks/rocks.singe" } } ---- C'est du Lua, et c'est une table du genre de celles que vous avez rencontrées à la leçon six : `GAMES` est une liste, et chaque élément de la liste est un enregistrement qui décrit un jeu. Un dossier peut contenir plusieurs jeux -- c'est pour ça que c'est une liste -- mais le vôtre n'en contient qu'un. `SCRIPT` est le champ dont le moteur a besoin pour lancer le jeu, et `TITLE` celui dont le menu a besoin pour le lister. Le chemin du script part du dossier *au-dessus* du `games.dat`, et non du dossier où se trouve le `games.dat`. Donc un `games.dat` placé dans `rocks` désigne son propre script par `rocks/rocks.singe`. On dirait que ça dit `rocks` deux fois, et c'est correct. Tous les autres chemins du fichier marchent de la même façon. Trompez-vous, et rien ne proteste quand vous tapez le nom : l'entrée ne correspond simplement jamais au script que vous avez lancé. `TITLE`, c'est le nom pour les gens du début de cette leçon. C'est ce qu'affiche le menu, et les jeux sont listés dans l'ordre de leurs titres, donc le titre décide aussi de la place de votre jeu dans la liste. [#_telling_the_menu_more] === En dire plus au menu Le menu a tout un panneau à remplir à côté de la liste, et il le remplit avec le reste de l'entrée : [source,lua] ---- GAMES = { { TITLE = "Rocks", SCRIPT = "rocks/rocks.singe", CANVAS_X = 720, CANVAS_Y = 480, YEAR = 2026, GENRE = "Shooter", DEVELOPER = "Your Name Here", PUBLISHER = "Your Name Here", DESCRIPTION = "Shoot the rocks before they reach your ship.", CABINET = "rocks/cabinet.png", MARQUEE = "rocks/marquee.png" } } ---- `CABINET` et `MARQUEE` sont des fichiers d'image ordinaires dans le dossier de votre jeu, dans n'importe quel format que Singe sait lire. L'illustration de borne est la grande image à côté de la liste, et le fronton est la bande au-dessus. Donnez-leur la taille que vous voulez ; le menu les ajuste à leurs panneaux. Vous n'avez pas besoin d'un logiciel de dessin pour les faire, parce que votre jeu peut prendre sa propre photo. Lancez-le, et quand l'écran ressemble à ce que vous voulez montrer au monde, appuyez sur F12 (ou F11, parce que certains bureaux gardent F12 pour eux). Singe enregistre une image de la fenêtre dans le dossier de données de votre jeu, `data/rocks`, sous le nom `singe000.png`, puis `singe001.png`, et ainsi de suite. Prenez-en une de l'écran titre et une au milieu d'un combat. Copiez-les dans votre dossier `rocks` et renommez-les : le combat devient `cabinet.png`, le titre `marquee.png`. Un vrai fronton est une large bande avec le nom du jeu en grosses lettres, et un écran entier tassé dedans ressemble à un timbre-poste. Ça fera l'affaire en attendant mieux. Laissez de côté `MARQUEE` et le menu met à la place l'image manquante du moteur lui-même, un damier rose qui dit MISSING, ce qui est pire. `YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER` et `DESCRIPTION` sont le texte en dessous, et le moteur ne les regarde jamais. Ils sont là pour la personne qui lit le menu, et c'est bien le but. `CANVAS_X` et `CANVAS_Y` sont la taille du monde de votre jeu, et 720 sur 480 est la valeur par défaut -- le même monde que celui où vous dessinez depuis la leçon un. Ne les réglez que si votre jeu veut une autre forme. Un jeu sans champ `VIDEO` est un jeu sans vidéo, ce qui est le cas du vôtre ; c'est à la leçon quatorze que ce champ commence à compter. La section `games.dat` de la Référence donne tous les champs qui existent, dont plusieurs pour du matériel que vous n'avez pas encore. Quelques autres méritent que vous connaissiez leur nom dès maintenant. `REQUIRES` dit ce dont un jeu a besoin de la part de la machine au-delà de la simple 2D : `"GUI"` pour les menus et les pages de la leçon vingt, `"SCENE"` pour la 3D qui commence à la leçon vingt-deux, et quelques autres. Le menu le lit pour pouvoir dire à un joueur « cette machine ne peut pas faire tourner ce jeu » au lieu de laisser le jeu échouer en plein milieu. Rocks, c'est de la 2D toute simple, et laisser de côté `REQUIRES` veut dire exactement ça, donc laissez-le de côté. Vous aurez rarement à dresser la liste vous-même, parce que Singe remarque ce dont un jeu se sert pendant qu'il tourne, et le dit quand l'entrée ne le liste pas. À partir de la leçon vingt, vous verrez des lignes comme celle-ci, que le jeu ait un `games.dat` ou non : ---- Warning: this game uses GUI, which its games.dat does not list in REQUIRES. ---- C'est un conseil, pas une erreur ; le jeu tourne dans les deux cas. Le remède tient en une ligne dans l'entrée, `REQUIRES = { "GUI" },`, et empaqueter un jeu à la leçon trente écrit la liste pour vous si l'entrée n'en a pas. Son partenaire `TIER`, un nombre de 0 à 3, dit quelle puissance de machine un jeu demande, et peut attendre que vous écriviez un jeu assez lourd pour que ça compte. `GAME_ID` est une identité unique pour votre jeu, dont les tableaux des scores en ligne de la leçon vingt-huit ont besoin, et rien d'autre. Et `RESOLUTION_X` et `RESOLUTION_Y` demandent une taille de fenêtre précise. Ignorez le reste jusqu'à ce que quelque chose vous envoie le chercher. [#_running_it_from_the_menu] === Le lancer depuis le menu Lancez `Menu.sh` -- `Menu.bat` sous Windows -- depuis votre dossier de travail. Il trouve le Singe le plus récent à côté de lui et lance le menu. Votre jeu est dans la liste, avec ses illustrations à côté et sa description en dessous. C'est la seule chose dans la liste, parce que `rocks` est le seul dossier auquel vous avez donné un `games.dat` ; `hello`, `dodge` et les autres ne sont pas des jeux, pour autant que le menu puisse en juger. Haut et bas avancent d'un jeu, gauche et droite d'une page, et start ou un bouton de tir lance celui qui est sélectionné. Quittez le jeu avec Échap et vous voilà de retour au menu, sur le même jeu, prêt à repartir. Le menu se souvient aussi du jeu sur lequel vous étiez d'un lancement à l'autre. C'est tout ce qu'il faut pour publier un jeu, du point de vue du moteur. Un joueur copie votre dossier à côté de Singe, et le jeu apparaît. Taper le nom marche toujours, et marche de la même façon : ---- Singe rocks ---- Quand vous lancez un script à la main comme ça, Singe cherche un `games.dat` à côté de lui -- et jusqu'à trois dossiers au-dessus -- et si une entrée nomme le script que vous avez lancé, les réglages de cette entrée s'y appliquent. Un jeu se comporte donc de la même façon depuis un terminal que depuis le menu, ce qui veut dire que vous pouvez continuer à travailler comme avant, avec `-R` et un éditeur de texte, tout en vous fiant à ce qu'un joueur obtiendra. Il écrit aussi au même endroit : quelle que soit la façon dont votre jeu est lancé, sa sauvegarde est celle de `data/rocks`. [#_later_one_file] === Plus tard : un seul fichier Un dossier, c'est facile pour travailler et un peu malcommode à donner : une douzaine de fichiers, un dossier dans un dossier, et un joueur qui le décompresse au mauvais endroit. Un jeu Singe terminé peut être empaqueté dans un seul fichier `.game` que le moteur lance directement, illustrations, sons et tout le reste compris, et qu'un joueur copie à côté de Singe, un point c'est tout. Rien dans votre jeu n'a besoin de changer pour ça. C'est la leçon trente, et ça vaut la peine d'attendre : empaquetez un jeu qui n'est pas fini et vous l'empaquetterez de nouveau demain. [#_what_just_happened_9] === Ce qui vient de se passer [source,lua] ---- GAMES = { { ---- Deux accolades, parce que c'est une liste d'enregistrements. L'extérieure, c'est la liste. L'intérieure, c'est le premier élément de la liste, c'est-à-dire l'enregistrement d'un jeu. Se tromper sur l'une des deux est l'erreur habituelle, et Lua vous donnera la ligne. [source,lua] ---- SCRIPT = "rocks/rocks.singe", ---- Compté à partir du dossier au-dessus du `games.dat`, c'est-à-dire votre dossier de travail. C'est le même nom que celui que vous taperiez après `Singe` pour lancer le script à la main, et c'est la façon la plus simple de vous en souvenir. La virgule au bout de la ligne sépare un champ du suivant, exactement comme à la leçon six. Le dernier champ d'un enregistrement n'a pas de virgule après lui -- Lua ne s'en offusque pas s'il en a une, mais laissez-la de côté et votre fichier ressemblera à celui de tout le monde. Une virgule qui manque au milieu, c'est une autre affaire, et c'est l'erreur de cette leçon. [source,lua] ---- CABINET = "rocks/cabinet.png", ---- Une image que charge le menu, pas votre jeu, donc elle est nommée comme `SCRIPT`, à partir du dossier du dessus, et pas avec `DIR`. `DIR` appartient à votre script pendant qu'il tourne, et le menu et le moteur lisent `games.dat` avant que votre script ait démarré. [#_try_it_13] === Essayez . *Faites de meilleures illustrations.* Si vous avez un logiciel de dessin, faites un vrai `marquee.png` : une large bande avec ROCKS écrit en travers en grosses lettres. Mettez-le à la place de la capture d'écran et regardez de nouveau le menu. . *Donnez un games.dat à Dodge.* Écrivez un `games.dat` dans votre dossier `dodge` de la leçon sept et lancez le menu. Deux jeux maintenant, dans l'ordre des titres. Puis changez le `TITLE` de Rocks en `Asteroid Field` et regardez-le passer au-dessus de Dodge : la liste est triée par titre, pas par dossier. . *Cassez games.dat pour le menu.* Supprimez l'une des accolades fermantes du `games.dat` de `rocks` et lancez le menu. Votre jeu a disparu de la liste, et le terminal dit pourquoi. Remettez-la. . *Trompez-vous de SCRIPT.* Mettez `CANVAS_X` à `1280` et `CANVAS_Y` à `720`, et lancez `Singe rocks`. L'aire de jeu est plus large. Changez maintenant `SCRIPT` en `rocks.singe` et relancez-le. Le jeu a retrouvé son ancienne taille, et rien ne vous l'a dit : l'entrée ne nomme plus le script que vous avez lancé, donc elle ne s'applique pas. Remettez les deux comme avant. . *Trouvez votre sauvegarde.* Lancez le jeu depuis le menu, établissez un meilleur score, quittez pour revenir au menu, et quittez le menu. Lancez `Singe rocks` et regardez l'écran titre. Puis cherchez dans `data/rocks` le fichier qui s'en est souvenu. [#_break_it_on_purpose_12] === Cassez-le exprès Retirez la virgule au bout de la ligne `TITLE`, pour que le haut du fichier devienne : [source,lua] ---- GAMES = { { TITLE = "Rocks" SCRIPT = "rocks/rocks.singe", ---- Lancez `Singe rocks`. Le jeu démarre, et le terminal dit ceci : ---- Note: rocks/games.dat ignored: [string "rocks/games.dat"]:4: '}' expected (to close '{' at line 2) near 'SCRIPT' ---- Votre jeu tourne quand même, parce qu'un jeu lancé par son nom n'a pas besoin de son entrée. Il tourne simplement sans elle. Lancez le menu, en revanche, et votre jeu a disparu. Si c'était le seul, la liste affiche `No games yet`, et le terminal dit la même chose autrement : ---- rocks/games.dat: rocks/games.dat:4: '}' expected (to close '{' at line 2) near 'SCRIPT' Skipped. ---- Lisez-le comme n'importe quelle autre erreur Lua. Le fichier est `rocks/games.dat` et la ligne est la 4. Mais la ligne 4 est la ligne `SCRIPT`, et elle n'a rien de faux. L'erreur est au bout de la ligne 3. Après `TITLE = "Rocks"`, Lua attendait soit une virgule et un autre champ, soit le `}` qui ferme l'enregistrement commencé à la ligne 2. Il a trouvé `SCRIPT` à la place, donc c'est à la ligne 4 qu'il s'en est aperçu. Sa proposition de correction -- un `}` -- est fausse ; sa ligne est décalée d'une. Quand une erreur désigne le début d'une ligne, regardez la fin de la ligne d'avant. Remettez la virgule, et relancez le menu. [#_what_you_learned_13] === Ce que vous avez appris * Un jeu est un dossier : le script, ses illustrations et un `games.dat`, et rien qui vienne de l'extérieur, sauf le dossier `Singe` du moteur lui-même. * Le nom du dossier est pour l'ordinateur, donc gardez-le simple. Le nom pour les gens, c'est `TITLE`. * Les noms que charge votre script partent de l'endroit où Singe a été lancé, et c'est pourquoi chacun d'eux est construit à partir de `DIR`. * `games.dat` est un fichier Lua qui contient une liste `GAMES`, et chaque entrée est un jeu. * Une entrée a besoin de `TITLE` et de `SCRIPT` et de rien d'autre ; ses chemins partent du dossier au-dessus du `games.dat`. * `CABINET`, `MARQUEE`, `YEAR`, `GENRE`, `DEVELOPER`, `PUBLISHER` et `DESCRIPTION` sont ce que le menu montre au joueur, et F12 prend une image dont vous pouvez vous servir pour les deux premiers. * `REQUIRES` dit au menu ce dont un jeu a besoin au-delà de la 2D, et Singe vous prévient quand un jeu se sert de quelque chose que son entrée ne liste pas. * `Menu.sh` ou `Menu.bat` lance le menu fourni, qui liste chaque dossier de jeu à côté de lui, trié par titre. * Un jeu lancé par son nom reçoit lui aussi son entrée de `games.dat`, donc il se comporte de la même façon dans les deux cas, et un `games.dat` qui ne se charge pas est signalé, puis ignoré. * Un jeu terminé peut être empaqueté dans un seul fichier plus tard, à la leçon trente. [#_next_time_13] === La prochaine fois Voilà la deuxième partie terminée : vous avez un jeu, avec des illustrations, du son, des collisions, un score, et un moyen pour quelqu'un d'autre de le lancer. La troisième partie porte sur ce que presque aucun autre moteur ne fait -- lire du film comme le monde où se déroule le jeu -- et la leçon quatorze commence par le disque, l'image et l'attente.