509 lines
22 KiB
Text
509 lines
22 KiB
Text
[#_lesson_30_shipping_it]
|
||
== Leçon 30 : Le publier
|
||
|
||
image::learn/30-shipping.png[La leçon terminée, 480]
|
||
|
||
Vous avez un dossier. Il contient un script, quelques images, quelques sons, et
|
||
le `games.dat` que vous avez écrit à la leçon treize. Il tourne, parce que tout
|
||
ce dont il a besoin est là où vous l'avez laissé et que vous savez où c'est.
|
||
|
||
Cette leçon transforme ce dossier en un seul fichier que quelqu'un qui ne vous a
|
||
jamais rencontré peut copier sur sa machine et jouer. L'essentiel tient en deux
|
||
lignes de commande. Le reste, c'est la partie que personne n'enseigne : ce qui a
|
||
sa place dans le fichier, le travail de qui s'y trouve à part le vôtre, et
|
||
comment savoir s'il marche ailleurs qu'ici.
|
||
|
||
[#_one_file]
|
||
=== Un seul fichier
|
||
|
||
Un jeu Singe fini se publie sous la forme d'un seul fichier `.game`. En
|
||
empaqueter un, c'est :
|
||
|
||
----
|
||
Singe --pack MyGame MyGame.game
|
||
----
|
||
|
||
Le premier nom est le dossier de votre jeu, le second est le fichier à écrire.
|
||
Singe lit chaque fichier du dossier dans une base de données et dit ce qu'il a
|
||
fait :
|
||
|
||
----
|
||
>>> Packed 42 files (3819204 bytes) from MyGame into MyGame.game
|
||
----
|
||
|
||
Lancez-le de la même façon que vous lancez n'importe quoi :
|
||
|
||
----
|
||
Singe MyGame.game
|
||
----
|
||
|
||
Ça lance la première entrée du `games.dat` qu'il contient ; `--entry=2` lance
|
||
la deuxième, pour un fichier qui contient plus d'un jeu. Pour l'installer, le
|
||
joueur copie `MyGame.game` à côté du programme Singe. Le menu fourni le trouve
|
||
et l'affiche dans sa liste. Il n'y a rien d'autre : pas d'installateur, pas
|
||
d'archive à décompresser, pas de dossier à mettre au bon endroit.
|
||
|
||
[#_what_packing_does_to_every_file_name]
|
||
=== Ce que l'empaquetage fait à chaque nom de fichier
|
||
|
||
Rien dans votre jeu n'a besoin de changer pour être empaqueté, et ça vaut la
|
||
peine de savoir pourquoi, parce que c'est ce qui risque le plus de vous
|
||
surprendre.
|
||
|
||
Chaque nom qu'utilise votre jeu -- `dofile`, `require`, `io.open`,
|
||
`spriteLoad`, `soundLoad`, `fontLoad`, `videoLoad`, un framefile, un
|
||
`controls.cfg` -- passe par une seule et même recherche. Pour un dossier non
|
||
empaqueté, cette recherche est le simple système de fichiers. Pour un jeu
|
||
empaqueté, le nom est essayé à trois endroits et le premier trouvé l'emporte :
|
||
|
||
. un dossier non empaqueté qui porte le nom du fichier sans son
|
||
extension -- `MyGame/` à côté de `MyGame.game` ;
|
||
. le dossier de données du jeu, sous `files/`, qui est l'endroit où atterrit
|
||
tout ce que le jeu écrit ;
|
||
. la base de données elle-même.
|
||
|
||
Dans la base de données, les noms sont comparés sans tenir compte des
|
||
majuscules, avec l'une ou l'autre sorte de barre oblique, et relativement à la
|
||
racine du jeu. Un nom de dossier en tête égal à celui du jeu lui-même est
|
||
ignoré, si bien que `MyGame/art/spaceship.png`, `art/spaceship.png` et
|
||
`DIR .. "art/spaceship.png"` trouvent tous le même fichier.
|
||
|
||
Deux règles en découlent, et si vous avez suivi le livre, vous obéissez déjà aux
|
||
deux. Utilisez `DIR` pour tout ce que vous chargez, pour qu'un nom ne dépende
|
||
jamais de l'endroit d'où Singe a été lancé. Et n'écrivez que sous
|
||
`singeGetDataPath()`, là où `saveSet` range déjà les choses -- un jeu empaqueté
|
||
est ouvert en lecture seule et n'est jamais écrit, si bien qu'un jeu qui
|
||
sauvegarde à côté de lui-même marche non empaqueté et échoue empaqueté.
|
||
|
||
Deux sortes de noms vont ailleurs exprès. Tout ce qui commence par `Singe/`
|
||
reste sur le vrai système de fichiers, si bien que
|
||
`dofile("Singe/Framework.singe")` continue de marcher, et le dossier de données
|
||
aussi. Et un nom contenant `..` qui essaie de sortir du jeu ne mène nulle part :
|
||
`io.open` renvoie `nil` et un message disant que le nom sort du jeu, et
|
||
`spriteLoad` et ses semblables signalent le fichier comme manquant.
|
||
|
||
[#_the_loose_folder_still_wins]
|
||
=== Le dossier non empaqueté l'emporte toujours
|
||
|
||
Cette première place dans la liste est celle dont vous vous servirez tous les
|
||
jours. Un dossier qui porte le nom du fichier empaqueté, posé à côté de lui,
|
||
l'emporte sur les copies empaquetées, fichier par fichier.
|
||
|
||
----
|
||
MyGame.game le jeu empaqueté
|
||
MyGame/ un dossier avec un seul fichier modifié dedans
|
||
----
|
||
|
||
Déposez-y un seul `art/spaceship.png` corrigé et le jeu empaqueté tourne avec
|
||
votre nouvelle image et tout le reste tiré de la base de données. Rien n'a
|
||
besoin d'être réempaqueté pour essayer une modification, et vous pouvez garder
|
||
là tout votre dossier de travail pendant que vous finissez le jeu. C'est aussi
|
||
comme ça qu'un joueur en fait un mod, ce que vous considérerez ou non comme une
|
||
fonctionnalité.
|
||
|
||
Deux choses en découlent. Vérifiez votre jeu une fois avec ce dossier renommé,
|
||
sinon vous publierez un fichier qui ne marche que sur la machine qui a le
|
||
dossier. Et sachez que l'empaquetage ne cache rien : `--unpack` est une option
|
||
documentée et n'importe qui peut s'en servir. Empaquetez votre jeu parce qu'il
|
||
tient en un seul fichier, pas parce qu'il serait verrouillé.
|
||
|
||
[#_patching_a_released_game]
|
||
=== Corriger un jeu publié
|
||
|
||
Quelqu'un a votre jeu, il y a un bogue dans un script, et vous n'avez pas envie
|
||
de lui renvoyer quarante mégaoctets.
|
||
|
||
----
|
||
Singe --patch MyGame.game fixes
|
||
----
|
||
|
||
`fixes` est un dossier organisé comme le jeu -- les mêmes noms aux mêmes
|
||
endroits -- qui ne contient que les fichiers qui ont changé. Les fichiers que le
|
||
correctif ne nomme pas sont laissés tels quels. Tout le changement est une seule
|
||
transaction, si bien qu'un correctif interrompu laisse le jeu exactement comme
|
||
il était, plutôt qu'à moitié remplacé.
|
||
|
||
Un correctif peut voyager dans un fichier à lui, créé avec l'empaqueteur :
|
||
|
||
----
|
||
Singe --pack fixes MyGame-1.0.2.patch
|
||
Singe --patch MyGame.game MyGame-1.0.2.patch
|
||
----
|
||
|
||
Un `.patch` n'a pas besoin de `games.dat`, ne peut pas être lancé, et le menu
|
||
l'ignore. Il peut aussi porter une table `removed(path)` qui nomme des fichiers
|
||
à supprimer, pour les images que vous avez remplacées par quelque chose qui
|
||
porte un autre nom. Dans tous les cas, Singe vérifie ensuite le jeu corrigé de
|
||
la même manière qu'il vérifie un nouveau jeu, si bien qu'un correctif ne peut
|
||
pas laisser votre `games.dat` pointer vers un fichier qui n'est plus là.
|
||
|
||
Et pour tout ressortir :
|
||
|
||
----
|
||
Singe --unpack MyGame.game MyGameUnpacked
|
||
----
|
||
|
||
[#_what_the_packer_refuses]
|
||
=== Ce que l'empaqueteur refuse
|
||
|
||
L'empaqueteur ne construit pas un jeu à partir de n'importe quoi, et chaque
|
||
refus concerne quelque chose qui casserait plus tard. Il refuse un dossier sans
|
||
`games.dat` à sa racine. Il refuse un `Framework.singe`, un `controls.dat`, tout
|
||
ce qui se termine par `exe`, `sh`, `bat` ou `cmd`, et un fichier sans extension
|
||
dont le nom commence par `singe` -- autrement dit, une copie du moteur ou de ses
|
||
fichiers de support qui s'est égarée dans le dossier de votre jeu. Il refuse
|
||
deux fichiers dont les noms ne diffèrent que par les majuscules, puisque la
|
||
recherche ne peut pas les distinguer. Il refuse une entrée de premier niveau qui
|
||
porte le nom du dossier lui-même. Et il vérifie votre `games.dat` avant de
|
||
valider : chaque entrée a besoin d'un `SCRIPT`, et chaque `SCRIPT`, `VIDEO`,
|
||
`CABINET`, `MARQUEE` et `ATTRACT` qu'elle nomme doit être un fichier qui s'y
|
||
trouve vraiment. Un mauvais chemin est signalé avec le titre de l'entrée et rien
|
||
n'est écrit.
|
||
|
||
Chaque plainte nomme le fichier, et vous en avez la liste complète plutôt que la
|
||
première seulement, si bien qu'un seul passage vous dit tout ce qu'il faut
|
||
corriger.
|
||
|
||
[#_what_to_include_and_what_to_leave_out]
|
||
=== Ce qu'il faut inclure et ce qu'il faut laisser de côté
|
||
|
||
Regardez dans le dossier de votre jeu. Une partie de ce qu'il contient est le
|
||
jeu, et une autre partie, c'est la façon dont le jeu a été fait.
|
||
|
||
À publier : le script et tout ce qu'il charge, le `games.dat`, les images que
|
||
montre le menu (`CABINET`, `MARQUEE` et le clip `ATTRACT`), vos fichiers de
|
||
crédits et de licence, et un lisez-moi si vous en avez un.
|
||
|
||
À laisser de côté : les dessins dont vous avez exporté les images, les prises de
|
||
son que vous n'avez pas utilisées, vos notes, les scripts de test, les captures
|
||
d'écran, tout ce qui s'appelle `old` ou `backup`, le dossier `data` avec vos
|
||
propres sauvegardes et vos propres meilleurs scores dedans, et tout ce que vous
|
||
ne voudriez pas qu'un inconnu lise. Tout cela s'empaquette parfaitement bien, et
|
||
c'est justement le problème : ça part avec le jeu, et n'importe qui y a accès en
|
||
un `--unpack`.
|
||
|
||
La façon fiable de savoir ce que vous avez vraiment publié, c'est de le
|
||
désempaqueter dans un dossier vide et de regarder. Faites-le une fois pour
|
||
chaque version publiée. Ça prend une minute, et c'est la seule vérification qui
|
||
voit ce que vous avez oublié plutôt que ce dont vous vous souvenez.
|
||
|
||
[#_credits_and_licenses]
|
||
=== Crédits et licences
|
||
|
||
Si des images, des sons, de la musique ou une police de votre jeu ont été faits
|
||
par quelqu'un d'autre, vous publiez son travail, et les conditions auxquelles il
|
||
l'a donné sont une obligation plutôt qu'une politesse. Ce n'est pas une
|
||
formalité et ce n'est pas une affaire d'avocats : une personne a fait cette
|
||
chose et a demandé une seule chose précise en retour, en général son nom.
|
||
|
||
Tenez un registre pendant que vous travaillez, pas à la fin. Un simple fichier
|
||
texte dans le dossier du jeu, avec une ligne par élément : ce qu'est le fichier,
|
||
d'où il vient, qui l'a fait, quelle licence, et ce que cette licence exige.
|
||
L'écrire au fur et à mesure prend quelques secondes. Le reconstituer la veille
|
||
d'une sortie, à partir d'un historique de navigateur, c'est comme ça que des
|
||
crédits se perdent.
|
||
|
||
Quelques choses à savoir avant d'en avoir besoin. « Téléchargement gratuit »
|
||
n'est pas une licence ; cherchez les vraies conditions. Creative Commons `BY`
|
||
veut dire que vous devez donner le crédit indiqué, et il n'y a pas d'exception
|
||
pour les jeux. `CC0` et le domaine public ne demandent rien, et créditer quand
|
||
même vous coûte une ligne. Les polices ont leurs propres licences, et certaines
|
||
permettent de les embarquer alors que d'autres non. Vous n'avez presque jamais
|
||
le droit d'utiliser la musique d'une vidéo. Tout ce qu'un outil a généré n'est
|
||
pas plus propre que les conditions de cet outil.
|
||
|
||
Ensuite, mettez les crédits quelque part où un joueur peut les atteindre, dans
|
||
le jeu. Pas seulement dans un fichier texte à côté -- un jeu empaqueté est un
|
||
seul fichier, et le fichier texte est dedans, là où personne ne regardera. Le
|
||
script à la fin de cette leçon est cet écran-là.
|
||
|
||
Le `Singe/LICENSES` de Singe lui-même est la forme à copier : une ligne par
|
||
bibliothèque, avec sa version, sa licence et sa provenance. La liste de votre
|
||
jeu sera plus courte, et le travail est le même.
|
||
|
||
[#_a_version_number_that_means_something]
|
||
=== Un numéro de version qui veut dire quelque chose
|
||
|
||
Votre jeu aura une deuxième version. La première circulera aussi longtemps
|
||
qu'internet existera, et quelqu'un vous enverra un rapport de bogue à son sujet
|
||
sans avoir la moindre idée de la version qu'il a.
|
||
|
||
Alors choisissez un numéro, mettez-le là où un joueur peut le lire, et n'en
|
||
réutilisez jamais un. Trois parties, c'est la forme courante -- `1.0.2` -- et ce
|
||
que veulent dire les parties compte moins que le fait qu'elles ne font que
|
||
monter. Augmentez la dernière pour une correction, celle du milieu pour quelque
|
||
chose de nouveau, la première quand vous avez fait un autre jeu. Quoi que vous
|
||
choisissiez, notez-le dans votre lisez-moi, pour que le vous du futur s'y tienne
|
||
aussi.
|
||
|
||
`games.dat` n'a pas de clé de version, alors c'est à vous de porter le numéro.
|
||
Mettez-le dans le script sous forme de constante, affichez-le sur l'écran des
|
||
crédits, et mettez-le dans le nom de ce que vous envoyez (`MyGame-1.0.2.game`,
|
||
`MyGame-1.0.2.patch`). Le rapport de bogue donne alors la version affichée à
|
||
l'écran, et vous savez de quels fichiers il parle.
|
||
|
||
[#_testing_on_a_machine_that_is_not_yours]
|
||
=== Tester sur une machine qui n'est pas la vôtre
|
||
|
||
Votre machine est le pire endroit possible pour tester une version. Elle a les
|
||
polices que vous avez installées, le dossier que vous étiez en train de
|
||
modifier, le fichier de sauvegarde avec vos réglages dedans, et le moteur dans
|
||
l'état où un mois de travail l'a laissé.
|
||
|
||
Le test minimum, dans l'ordre :
|
||
|
||
. Désempaquetez la version dans un dossier vide et lisez la liste des fichiers.
|
||
. Copiez *uniquement* le fichier `.game` dans un autre dossier, avec une copie
|
||
neuve de Singe et rien d'autre, et lancez-le depuis le menu comme le fera un
|
||
joueur.
|
||
. Supprimez le dossier `data` de ce dossier et relancez. C'est un premier
|
||
lancement sur une machine neuve : pas de réglages sauvegardés, pas de
|
||
meilleurs scores, pas de compte connecté. Un jeu qui ne marche qu'à son
|
||
deuxième lancement est un bogue courant, et c'est comme ça qu'on le trouve.
|
||
. Donnez-le à une personne qui ne l'a jamais vu, et regardez sans l'aider.
|
||
|
||
Puis testez la machine autant que le jeu. Elle aura un écran d'une autre forme,
|
||
alors regardez votre jeu en fenêtre et en plein écran. Elle n'aura peut-être
|
||
aucun périphérique 3D, et c'est pour ça que le menu propose un second moteur de
|
||
rendu. La page *System Information* des outils de service affiche sur un seul
|
||
écran la version du moteur, le système d'exploitation, le processeur, le moteur
|
||
de rendu, les décodeurs et le dossier de données ; une photo de cette page
|
||
répond à presque tout un rapport de bogue, et le dire à vos joueurs dans votre
|
||
lisez-moi vous épargnera une semaine de devinettes.
|
||
|
||
[#_the_script_2]
|
||
=== Le script
|
||
|
||
Un écran de crédits et de version. C'est peu de chose à écrire, et c'est la
|
||
partie de la publication que la plupart des jeux ratent.
|
||
|
||
[source,lua]
|
||
----
|
||
dofile("Singe/Framework.singe")
|
||
|
||
local GAME_NAME = "Rock Dodger"
|
||
local GAME_VERSION = "1.0.2"
|
||
|
||
local CREDITS = {
|
||
"Written and drawn by <your name here>",
|
||
"",
|
||
"Music \"Night Drive\" by A. Composer",
|
||
" Creative Commons BY 4.0",
|
||
" example.org/night-drive",
|
||
"",
|
||
"Explosion freesound.org user \"thud\"",
|
||
" Creative Commons CC0",
|
||
"",
|
||
"Font FreeSansBold",
|
||
" GPL with the font exception",
|
||
"",
|
||
"Engine Singe " .. SINGE_VERSION_STRING,
|
||
" GPL version 3",
|
||
" See Singe/LICENSES for the",
|
||
" libraries Singe is built on.",
|
||
"",
|
||
"Thank you for playing.",
|
||
}
|
||
|
||
local FIRST_ROW = 4
|
||
local ROWS = 10
|
||
|
||
local scroll = 0
|
||
|
||
|
||
local function scrollBy(lines)
|
||
local most = #CREDITS - ROWS
|
||
|
||
if most < 0 then
|
||
most = 0
|
||
end
|
||
scroll = scroll + lines
|
||
if scroll < 0 then
|
||
scroll = 0
|
||
end
|
||
if scroll > most then
|
||
scroll = most
|
||
end
|
||
end
|
||
|
||
|
||
function onInputPressed(what)
|
||
if what == SWITCH_UP then
|
||
scrollBy(-1)
|
||
elseif what == SWITCH_DOWN then
|
||
scrollBy(1)
|
||
elseif what == SWITCH_BUTTON1 then
|
||
scroll = 0
|
||
end
|
||
end
|
||
|
||
|
||
function onOverlayUpdate()
|
||
local line = nil
|
||
|
||
overlayClear()
|
||
overlayPrint(2, 0, GAME_NAME .. " version " .. GAME_VERSION)
|
||
overlayPrint(2, 1, "Singe " .. SINGE_VERSION_STRING .. " id " .. (singeGetGameId() or "none"))
|
||
|
||
for row = 0, ROWS - 1 do
|
||
line = CREDITS[scroll + row + 1]
|
||
if line then
|
||
overlayPrint(2, FIRST_ROW + row, line)
|
||
end
|
||
end
|
||
|
||
overlayPrint(2, FIRST_ROW + ROWS + 1, "Saves go to:")
|
||
overlayPrint(2, FIRST_ROW + ROWS + 2, singeGetDataPath())
|
||
overlayPrint(2, 17, "Up and down scroll. Button 1 goes back to the top.")
|
||
|
||
return OVERLAY_UPDATED
|
||
end
|
||
----
|
||
|
||
Remplacez chaque ligne de `CREDITS` par la vérité sur votre propre jeu. Les
|
||
textes provisoires sont là pour montrer la forme : ce que c'est, qui l'a fait,
|
||
quelle licence, et d'où ça vient.
|
||
|
||
[#_what_just_happened_25]
|
||
=== Ce qui vient de se passer
|
||
|
||
[source,lua]
|
||
----
|
||
local GAME_VERSION = "1.0.2"
|
||
----
|
||
|
||
Un seul endroit, en haut, en majuscules parce que la valeur ne change jamais
|
||
pendant que le jeu tourne. Tout ce qui affiche la version lit ceci, si bien que
|
||
l'augmenter demande une seule modification plutôt qu'une recherche.
|
||
|
||
[source,lua]
|
||
----
|
||
"Music \"Night Drive\" by A. Composer",
|
||
----
|
||
|
||
Ces barres obliques inverses sont la séquence d'échappement que vous avez
|
||
rencontrée à la leçon un : un guillemet double qui fait partie du texte au lieu
|
||
de terminer la chaîne. Les titres contiennent des guillemets, et c'est pour ça
|
||
qu'une liste de crédits tombe dessus dès sa première ligne.
|
||
|
||
[source,lua]
|
||
----
|
||
for row = 0, ROWS - 1 do
|
||
line = CREDITS[scroll + row + 1]
|
||
if line then
|
||
----
|
||
|
||
Dix lignes d'écran qui montrent dix lignes d'une liste plus longue que dix.
|
||
`scroll` indique jusqu'où la fenêtre est descendue dans la liste. Le `+ 1` est
|
||
là parce que Lua compte une liste à partir de un et que les lignes de l'écran
|
||
comptent à partir de zéro, et le `if line then` est là parce que la fin de la
|
||
liste vaut `nil` -- lire au-delà de la fin d'une table n'est pas une erreur en
|
||
Lua, ça ne vous donne simplement rien, mais afficher ce rien en serait une.
|
||
|
||
[source,lua]
|
||
----
|
||
overlayPrint(2, 1, "Singe " .. SINGE_VERSION_STRING .. " id " .. (singeGetGameId() or "none"))
|
||
----
|
||
|
||
Trois faits dont un rapport de bogue a besoin et qu'un joueur ne peut pas
|
||
trouver autrement : votre version sur la ligne du dessus, la version du moteur,
|
||
et l'identifiant du jeu. `SINGE_VERSION_STRING` est une globale que le moteur
|
||
définit avant que votre script tourne. `or "none"` couvre le cas où le jeu n'a
|
||
pas d'entrée dans `games.dat`, pour que la ligne s'affiche au lieu de planter
|
||
sur un `nil`.
|
||
|
||
[source,lua]
|
||
----
|
||
overlayPrint(2, FIRST_ROW + ROWS + 2, singeGetDataPath())
|
||
----
|
||
|
||
L'endroit où ce jeu écrit. Pour un jeu empaqueté, c'est le seul endroit où quoi
|
||
que ce soit est écrit, et c'est le dossier qu'un joueur supprime pour repartir
|
||
de zéro. L'afficher transforme « où sont mes sauvegardes ? » en une question à
|
||
laquelle vous n'aurez jamais à répondre.
|
||
|
||
Si ce chemin dépasse à droite de l'écran, ce n'est pas cassé : `overlayPrint`
|
||
laisse tomber les caractères qui dépasseraient du bord. L'overlay par défaut
|
||
fait soixante cellules de caractère de large.
|
||
|
||
[#_try_it_30]
|
||
=== Essayez
|
||
|
||
. *Empaquetez-le.* Mettez ce script dans le dossier de votre jeu, lancez
|
||
`--pack`, et lancez le fichier `.game`. Puis désempaquetez-le dans un dossier
|
||
vide et lisez la liste de ce qui en est sorti.
|
||
. *Remplacez un fichier.* À côté du fichier empaqueté, créez un dossier qui
|
||
porte son nom sans l'extension, et mettez-y un fichier modifié. Lancez le jeu
|
||
empaqueté et regardez votre fichier non empaqueté l'emporter.
|
||
. *Faites un correctif.* Passez la version à `1.0.3`, mettez seulement le
|
||
script dans un dossier `fixes`, empaquetez-le en `.patch`, et appliquez-le au
|
||
jeu que vous avez déjà fait. Vérifiez la version à l'écran.
|
||
. *Cassez l'empaqueteur.* Renommez votre `games.dat` un instant et essayez
|
||
d'empaqueter. Puis remettez-le, faites pointer l'un de ses noms `SCRIPT` vers
|
||
un fichier qui n'existe pas, et réessayez. Deux refus différents, tous les
|
||
deux avant que quoi que ce soit soit écrit.
|
||
. *Écrivez les vrais crédits.* Parcourez le dossier de votre jeu fichier par
|
||
fichier et écrivez une ligne pour chacun de ceux que vous n'avez pas faits.
|
||
Si vous ne vous rappelez plus d'où vient quelque chose, vous savez maintenant
|
||
si vous devriez le publier.
|
||
|
||
[#_break_it_on_purpose_29]
|
||
=== Cassez-le exprès
|
||
|
||
Lancez Singe une fois depuis l'*intérieur* du dossier de votre jeu, pour que le
|
||
moteur y extraie ses fichiers de support, puis empaquetez-le :
|
||
|
||
----
|
||
Singe --pack MyGame MyGame.game
|
||
----
|
||
|
||
----
|
||
!!! MyGame has Framework.singe: Singe/Framework.singe
|
||
!!! MyGame has sh file: Menu.sh
|
||
----
|
||
|
||
Rien n'est écrit. Chaque ligne donne un fichier qu'il refuse et la raison, et
|
||
vous pouvez les recevoir dans n'importe quel ordre, ou en avoir d'autres en
|
||
plus. Il y a une copie du dossier de support du moteur lui-même dans votre jeu,
|
||
et le script de lancement que le moteur a écrit à côté, parce que vous avez
|
||
lancé Singe depuis là à un moment donné. Un jeu ne doit jamais emporter ni l'un
|
||
ni l'autre : les fichiers de support appartiennent au Singe que lance le
|
||
joueur, quel qu'il soit, pas à votre jeu, et un `Framework.singe` empaqueté
|
||
serait chargé à la place du sien. Sous Windows, la seconde ligne nomme
|
||
`Menu.bat` à la place.
|
||
|
||
Supprimez le dossier `Singe` et `Menu.sh` (ou `Menu.bat`) de l'intérieur de
|
||
votre jeu, gardez le dossier de votre jeu comme un dossier à côté du programme
|
||
Singe plutôt qu'autour de lui, et empaquetez de nouveau. C'est la même organisation que celle que décrivait la
|
||
leçon treize, et cette erreur est ce qui arrive quand elle se dérègle.
|
||
|
||
[#_what_you_learned_30]
|
||
=== Ce que vous avez appris
|
||
|
||
* `Singe --pack folder name.game` transforme un dossier de jeu en un seul
|
||
fichier, et copier ce fichier à côté du programme Singe l'installe.
|
||
* Chaque nom de fichier d'un jeu empaqueté est cherché d'abord dans un dossier
|
||
non empaqueté, puis dans le dossier de données, puis dans la base de données.
|
||
* Un dossier non empaqueté qui porte le nom du fichier empaqueté l'emporte sur
|
||
lui fichier par fichier, et c'est comme ça que vous continuez à
|
||
travailler -- et comme ça que vous publiez une version cassée si vous oubliez qu'il est là.
|
||
* Chargez avec `DIR` et n'écrivez que sous `singeGetDataPath()`, sinon votre jeu
|
||
marchera non empaqueté et échouera empaqueté.
|
||
* `--patch` remplace des fichiers d'un jeu publié en une seule transaction ;
|
||
`--unpack` ressort tout.
|
||
* L'empaqueteur refuse les fichiers du moteur, les conflits de noms, et un
|
||
`games.dat` qui pointe vers des fichiers qu'il n'a pas.
|
||
* Désempaquetez votre propre version et lisez ce qu'elle contient avant de
|
||
l'envoyer où que ce soit.
|
||
* Les images et les sons de quelqu'un d'autre viennent avec des conditions, et
|
||
les respecter veut dire un écran de crédits dans le jeu.
|
||
* Un numéro de version ne fait que monter, et sa place est à l'écran.
|
||
* Testez sur une machine qui n'est pas la vôtre, en commençant sans aucun
|
||
dossier `data`.
|
||
|
||
[#_next_time_30]
|
||
=== La prochaine fois
|
||
|
||
Un seul fichier, installé, crédité et numéroté. La dernière leçon le met dans
|
||
une caisse en bois avec une fente à pièces et sans clavier, ce qui change plus
|
||
de choses dans votre jeu que vous ne le pensez.
|