500 lines
21 KiB
Text
500 lines
21 KiB
Text
[#_lesson_30_shipping_it]
|
|
== Lección 30: Publicarlo
|
|
|
|
image::learn/30-shipping.png[La lección terminada, 480]
|
|
|
|
Tienes una carpeta. Dentro hay un script, unas cuantas imágenes, algunos sonidos
|
|
y el `games.dat` que escribiste en la lección trece. Funciona, porque todo lo que
|
|
necesita está donde lo dejaste y tú sabes dónde es.
|
|
|
|
Esta lección convierte esa carpeta en un solo archivo que alguien que no te
|
|
conoce de nada puede copiar en su ordenador y jugar. Casi todo son dos líneas de
|
|
comandos. El resto es la parte que no enseña nadie: qué va en el archivo, qué
|
|
trabajo de otros hay ahí además del tuyo y cómo averiguar si funciona en algún
|
|
sitio aparte de aquí.
|
|
|
|
[#_one_file]
|
|
=== Un solo archivo
|
|
|
|
Un juego de Singe terminado se publica como un único archivo `.game`.
|
|
Empaquetar uno es:
|
|
|
|
----
|
|
Singe --pack MyGame MyGame.game
|
|
----
|
|
|
|
El primer nombre es la carpeta de tu juego, el segundo es el archivo que hay que
|
|
escribir. Singe mete todos los archivos de la carpeta en una base de datos y
|
|
dice lo que ha hecho:
|
|
|
|
----
|
|
>>> Packed 42 files (3819204 bytes) from MyGame into MyGame.game
|
|
----
|
|
|
|
Se ejecuta igual que cualquier otra cosa:
|
|
|
|
----
|
|
Singe MyGame.game
|
|
----
|
|
|
|
Eso ejecuta la primera entrada del `games.dat` que lleva dentro; `--entry=2`
|
|
ejecuta la segunda, para un archivo que contiene más de un juego. Para
|
|
instalarlo, el jugador copia `MyGame.game` junto al programa Singe. El menú
|
|
incluido lo encuentra y lo pone en la lista. No hay nada más: ni instalador, ni
|
|
archivo comprimido que descomprimir, ni carpeta que poner en el sitio correcto.
|
|
|
|
[#_what_packing_does_to_every_file_name]
|
|
=== Lo que el empaquetado le hace a cada nombre de archivo
|
|
|
|
No hay que cambiar nada de tu juego para empaquetarlo, y vale la pena saber por
|
|
qué, porque es lo que más probablemente te sorprenda.
|
|
|
|
Todos los nombres que usa tu juego -- `dofile`, `require`, `io.open`,
|
|
`spriteLoad`, `soundLoad`, `fontLoad`, `videoLoad`, un framefile, un
|
|
`controls.cfg` -- pasan por una única búsqueda. Para una carpeta suelta, esa
|
|
búsqueda es el sistema de archivos normal. Para un juego empaquetado, el nombre
|
|
se prueba en tres sitios y gana el primero que lo encuentra:
|
|
|
|
. una carpeta suelta con el nombre del archivo sin su extensión -- `MyGame/`
|
|
junto a `MyGame.game`;
|
|
. la carpeta de datos del juego, dentro de `files/`, que es donde ha ido a parar
|
|
todo lo que el juego escribe;
|
|
. la propia base de datos.
|
|
|
|
Dentro de la base de datos, los nombres se comparan sin tener en cuenta las
|
|
mayúsculas, con cualquiera de los dos tipos de barra y a partir de la raíz del
|
|
juego. Un nombre de carpeta inicial igual al del propio juego se ignora, así que
|
|
`MyGame/art/spaceship.png`, `art/spaceship.png` y `DIR .. "art/spaceship.png"`
|
|
encuentran todos el mismo archivo.
|
|
|
|
De ahí salen dos reglas, y si has ido siguiendo el libro ya cumples las dos. Usa
|
|
`DIR` para todo lo que cargues, para que un nombre nunca dependa de dónde se
|
|
arrancó Singe. Y escribe solo dentro de `singeGetDataPath()`, que es donde
|
|
`saveSet` ya pone las cosas -- un juego empaquetado se abre de solo lectura y
|
|
nunca se escribe en él, así que un juego que guarda junto a sí mismo funciona
|
|
suelto y falla empaquetado.
|
|
|
|
Dos nombres van a otro sitio a propósito. Todo lo que empieza por `Singe/` se
|
|
queda en el sistema de archivos de verdad, así que
|
|
`dofile("Singe/Framework.singe")` sigue funcionando, y lo mismo pasa con la
|
|
carpeta de datos. Y un nombre con `..` que intenta salirse del juego no lleva a
|
|
ninguna parte: `io.open` devuelve `nil` y un mensaje que dice que el nombre
|
|
apunta fuera del juego, y `spriteLoad` y sus parientes informan de que el
|
|
archivo no existe.
|
|
|
|
[#_the_loose_folder_still_wins]
|
|
=== La carpeta suelta sigue ganando
|
|
|
|
El primer sitio de la lista es el que usarás todos los días. Una carpeta con el
|
|
nombre del archivo empaquetado, puesta a su lado, gana a las copias empaquetadas
|
|
archivo por archivo.
|
|
|
|
----
|
|
MyGame.game el juego empaquetado
|
|
MyGame/ una carpeta con un archivo cambiado dentro
|
|
----
|
|
|
|
Mete ahí un solo `art/spaceship.png` corregido y el juego empaquetado se ejecuta
|
|
con tu imagen nueva y todo lo demás sacado de la base de datos. No hay que
|
|
volver a empaquetar nada para probar un cambio, y puedes tener ahí toda tu
|
|
carpeta de trabajo mientras terminas el juego. También es como un jugador
|
|
modifica uno, cosa que puede que te parezca una ventaja o puede que no.
|
|
|
|
De ahí salen dos cosas. Prueba tu juego una vez con esa carpeta renombrada para
|
|
que no estorbe, o publicarás un archivo que solo funciona en el ordenador que
|
|
tiene la carpeta. Y que sepas que empaquetar no esconde nada: `--unpack` es una
|
|
opción documentada y cualquiera puede usarla. Empaqueta tu juego porque es un
|
|
solo archivo, no porque sea un archivo cerrado con llave.
|
|
|
|
[#_patching_a_released_game]
|
|
=== Parchear un juego publicado
|
|
|
|
Alguien tiene tu juego, hay un fallo en un script y no quieres volver a
|
|
mandarle cuarenta megabytes.
|
|
|
|
----
|
|
Singe --patch MyGame.game fixes
|
|
----
|
|
|
|
`fixes` es una carpeta organizada como el juego -- los mismos nombres en los
|
|
mismos sitios -- que contiene solo los archivos que han cambiado. Los archivos
|
|
que el parche no nombra se dejan como están. Todo el cambio es una sola
|
|
transacción, así que un parche interrumpido deja el juego exactamente como
|
|
estaba en lugar de a medio sustituir.
|
|
|
|
Un parche puede viajar como un archivo propio, hecho con el empaquetador:
|
|
|
|
----
|
|
Singe --pack fixes MyGame-1.0.2.patch
|
|
Singe --patch MyGame.game MyGame-1.0.2.patch
|
|
----
|
|
|
|
Un `.patch` no necesita `games.dat`, no se puede ejecutar y el menú lo ignora.
|
|
También puede llevar una tabla `removed(path)` que nombra archivos que borrar,
|
|
para el arte que hayas sustituido por otro con un nombre distinto. En cualquier
|
|
caso, Singe comprueba después el juego parcheado igual que comprueba uno nuevo,
|
|
así que un parche no puede dejar tu `games.dat` apuntando a un archivo que ya no
|
|
está.
|
|
|
|
Y para volver a sacarlo todo:
|
|
|
|
----
|
|
Singe --unpack MyGame.game MyGameUnpacked
|
|
----
|
|
|
|
[#_what_the_packer_refuses]
|
|
=== Lo que el empaquetador rechaza
|
|
|
|
El empaquetador no construye un juego con cualquier cosa, y cada rechazo tiene
|
|
que ver con algo que se rompería más tarde. Rechaza una carpeta sin `games.dat`
|
|
en su raíz. Rechaza un `Framework.singe`, un `controls.dat`, cualquier cosa que
|
|
termine en `exe`, `sh`, `bat` o `cmd`, y un archivo sin extensión cuyo nombre
|
|
empiece por `singe` -- es decir, una copia del motor o de sus archivos de
|
|
soporte que se ha colado en la carpeta de tu juego. Rechaza dos archivos cuyos
|
|
nombres solo se diferencian en las mayúsculas, porque la búsqueda no puede
|
|
distinguirlos. Rechaza una entrada de primer nivel con el mismo nombre que la
|
|
propia carpeta. Y comprueba tu `games.dat` antes de confirmar nada: cada entrada
|
|
necesita un `SCRIPT`, y cada `SCRIPT`, `VIDEO`, `CABINET`, `MARQUEE` y `ATTRACT`
|
|
que nombre tiene que ser un archivo que esté de verdad ahí dentro. Una ruta mala
|
|
se informa con el título de la entrada y no se escribe nada.
|
|
|
|
Cada queja nombra el archivo, y sale la lista entera en lugar de solo la
|
|
primera, así que una sola pasada te dice todo lo que hay que arreglar.
|
|
|
|
[#_what_to_include_and_what_to_leave_out]
|
|
=== Qué incluir y qué dejar fuera
|
|
|
|
Mira en la carpeta de tu juego. Parte de lo que hay es el juego, y parte es cómo
|
|
se hizo el juego.
|
|
|
|
Publica: el script y todo lo que carga, el `games.dat`, el arte que muestra el
|
|
menú (`CABINET`, `MARQUEE` y el clip de `ATTRACT`), tus archivos de créditos y
|
|
de licencias, y un léame si tienes uno.
|
|
|
|
Deja fuera: los dibujos de los que exportaste el arte, las tomas de sonido que
|
|
no usaste, tus notas, los scripts de prueba, las capturas de pantalla, cualquier
|
|
cosa que se llame `old` o `backup`, la carpeta `data` con tus propias partidas
|
|
guardadas y tus propios récords, y cualquier cosa que no quieras que lea un
|
|
desconocido. Todo eso se empaqueta perfectamente, y ese es el problema: sale con
|
|
el juego y está a un `--unpack` de cualquiera.
|
|
|
|
La forma fiable de saber lo que has publicado de verdad es desempaquetarlo en
|
|
una carpeta vacía y mirar. Hazlo una vez con cada versión. Lleva un minuto y es
|
|
la única comprobación que ve lo que olvidaste en lugar de lo que recuerdas.
|
|
|
|
[#_credits_and_licenses]
|
|
=== Créditos y licencias
|
|
|
|
Si algo del arte, el sonido, la música o las fuentes de tu juego lo ha hecho
|
|
otra persona, estás publicando su trabajo, y las condiciones con las que lo
|
|
cedió son una obligación, no una cortesía. No es una formalidad ni es cosa de
|
|
abogados: una persona hizo eso y pidió una cosa concreta a cambio, normalmente
|
|
su nombre.
|
|
|
|
Lleva un registro mientras trabajas, no al final. Un archivo de texto plano en
|
|
la carpeta del juego con una línea por cosa: qué archivo es, de dónde salió,
|
|
quién lo hizo, qué licencia tiene y qué exige esa licencia. Escribirlo sobre la
|
|
marcha lleva segundos. Reconstruirlo la noche antes de publicar, a partir del
|
|
historial del navegador, es como se quedan créditos fuera.
|
|
|
|
Unas cuantas cosas que conviene saber antes de necesitarlas. «Descarga gratuita»
|
|
no es una licencia; busca las condiciones de verdad. Creative Commons `BY`
|
|
significa que tienes que dar el crédito que se indica, y no tiene ninguna
|
|
excepción para juegos. `CC0` y el dominio público no piden nada, y dar el
|
|
crédito de todos modos te cuesta una línea. Las fuentes llevan sus propias
|
|
licencias, y unas permiten incrustarlas y otras no. La música de un vídeo casi
|
|
nunca es tuya para usarla. Cualquier cosa generada por una herramienta solo está
|
|
tan limpia como las condiciones de la herramienta.
|
|
|
|
Luego pon los créditos en algún sitio al que pueda llegar un jugador, dentro del
|
|
juego. No solo en un archivo de texto al lado -- un juego empaquetado es un solo
|
|
archivo y el archivo de texto está dentro, donde nadie va a mirar. El script del
|
|
final de esta lección es esa pantalla.
|
|
|
|
El propio `Singe/LICENSES` de Singe es el modelo que copiar: una línea por
|
|
biblioteca, con su versión, su licencia y de dónde salió. La lista de tu juego
|
|
será más corta y el trabajo es el mismo.
|
|
|
|
[#_a_version_number_that_means_something]
|
|
=== Un número de versión que signifique algo
|
|
|
|
Tu juego tendrá una segunda versión. La primera seguirá por ahí mientras dure
|
|
internet, y alguien te mandará un informe de fallo sobre ella sin tener ni idea
|
|
de qué versión tiene.
|
|
|
|
Así que elige un número, ponlo donde un jugador pueda leerlo y no repitas nunca
|
|
uno. Tres partes es la forma habitual -- `1.0.2` -- y lo que signifique cada
|
|
parte importa menos que el hecho de que solo suban. Sube la última por un
|
|
arreglo, la del medio por algo nuevo y la primera cuando hayas hecho un juego
|
|
distinto. Elijas lo que elijas, apúntalo en tu léame para que tu yo del futuro
|
|
también lo cumpla.
|
|
|
|
`games.dat` no tiene clave de versión, así que el número lo llevas tú. Ponlo en
|
|
el script como constante, muéstralo en la pantalla de créditos y ponlo en el
|
|
nombre de lo que mandes (`MyGame-1.0.2.game`, `MyGame-1.0.2.patch`). Así el
|
|
informe de fallo dice la versión de la pantalla y sabes de qué archivos se
|
|
trata.
|
|
|
|
[#_testing_on_a_machine_that_is_not_yours]
|
|
=== Probar en un ordenador que no es el tuyo
|
|
|
|
Tu ordenador es el peor sitio posible para probar una versión. Tiene las fuentes
|
|
que instalaste, la carpeta que estabas editando, el archivo de partida guardada
|
|
con tus ajustes dentro y el motor en el estado en que lo haya dejado un mes de
|
|
trabajo.
|
|
|
|
La prueba mínima, en orden:
|
|
|
|
. Desempaqueta la versión en una carpeta vacía y lee la lista de archivos.
|
|
. Copia *solo* el archivo `.game` en otra carpeta, con una copia recién sacada
|
|
de Singe y nada más, y ejecútalo desde el menú como lo hará un jugador.
|
|
. Borra la carpeta `data` de esa carpeta y vuelve a ejecutarlo. Eso es una
|
|
primera ejecución en un ordenador nuevo: sin ajustes guardados, sin récords,
|
|
sin una cuenta con la sesión iniciada. Un juego que solo funciona la segunda
|
|
vez que se ejecuta es un fallo habitual, y así es como lo encuentras.
|
|
. Dáselo a una persona que no lo haya visto nunca y mira sin ayudar.
|
|
|
|
Luego prueba el ordenador además del juego. Tendrá una pantalla de otra forma,
|
|
así que mira tu juego en ventana y a pantalla completa. Puede que no tenga
|
|
ningún dispositivo 3D, que es por lo que el menú tiene un segundo renderizador.
|
|
La página *System Information* de las herramientas de servicio muestra en una
|
|
sola pantalla la versión del motor, el sistema operativo, el procesador, el
|
|
renderizador, los decodificadores y la carpeta de datos; una foto de esa página
|
|
responde a casi todo un informe de fallo, y decírselo a tus jugadores en tu
|
|
léame te ahorrará una semana de adivinanzas.
|
|
|
|
[#_the_script_2]
|
|
=== El script
|
|
|
|
Una pantalla de créditos y versión. Es poca cosa de escribir y es la parte de
|
|
publicar que la mayoría de los juegos hace mal.
|
|
|
|
[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
|
|
----
|
|
|
|
Sustituye cada línea de `CREDITS` por la verdad sobre tu propio juego. Los
|
|
textos de relleno están ahí para mostrar la forma: qué es, quién lo hizo, qué
|
|
licencia tiene y de dónde salió.
|
|
|
|
[#_what_just_happened_25]
|
|
=== Qué acaba de pasar
|
|
|
|
[source,lua]
|
|
----
|
|
local GAME_VERSION = "1.0.2"
|
|
----
|
|
|
|
Un solo sitio, arriba, en mayúsculas porque nunca cambia mientras el juego se
|
|
ejecuta. Todo lo que muestra la versión lee esto, así que subirla es un cambio y
|
|
no una búsqueda.
|
|
|
|
[source,lua]
|
|
----
|
|
"Music \"Night Drive\" by A. Composer",
|
|
----
|
|
|
|
Esas barras invertidas son la secuencia de escape que conociste en la lección
|
|
uno: unas comillas dobles que forman parte del texto en lugar de terminar la
|
|
cadena. Los títulos llevan comillas, y por eso una lista de créditos se topa con
|
|
esto en su primera línea.
|
|
|
|
[source,lua]
|
|
----
|
|
for row = 0, ROWS - 1 do
|
|
line = CREDITS[scroll + row + 1]
|
|
if line then
|
|
----
|
|
|
|
Diez filas de pantalla que muestran diez líneas de una lista de más de diez.
|
|
`scroll` es cuánto ha bajado la ventana por la lista. El `+ 1` está porque Lua
|
|
cuenta una lista desde uno y las filas de la pantalla cuentan desde cero, y el
|
|
`if line then` está porque el final de la lista es `nil` -- leer más allá del
|
|
final de una tabla no es un error en Lua, simplemente no te da nada, e imprimir
|
|
nada sí lo sería.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayPrint(2, 1, "Singe " .. SINGE_VERSION_STRING .. " id " .. (singeGetGameId() or "none"))
|
|
----
|
|
|
|
Tres datos que necesita un informe de fallo y que un jugador no puede encontrar
|
|
de otra manera: tu versión, en la línea de arriba, la versión del motor y el id
|
|
del juego. `SINGE_VERSION_STRING` es una variable global que el motor fija antes
|
|
de que se ejecute tu script. `or "none"` cubre el caso en que el juego no tiene
|
|
entrada en `games.dat`, para que la línea se imprima en lugar de fallar con un
|
|
`nil`.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayPrint(2, FIRST_ROW + ROWS + 2, singeGetDataPath())
|
|
----
|
|
|
|
Dónde escribe este juego. En un juego empaquetado es el único sitio donde se
|
|
escribe algo, y es la carpeta que borra un jugador para empezar de cero.
|
|
Mostrarla convierte «¿dónde están mis partidas guardadas?» en una pregunta que
|
|
nunca tendrás que responder.
|
|
|
|
Si esa ruta se sale por la derecha de la pantalla, no es que esté rota:
|
|
`overlayPrint` descarta los caracteres que pasarían del borde. El overlay por
|
|
defecto tiene sesenta celdas de carácter de ancho.
|
|
|
|
[#_try_it_30]
|
|
=== Pruébalo
|
|
|
|
. *Empaquétalo.* Pon este script en la carpeta de tu juego, ejecuta `--pack` y
|
|
ejecuta el archivo `.game`. Luego desempaquétalo en una carpeta vacía y lee la
|
|
lista de lo que ha salido.
|
|
. *Sustituye un archivo.* Junto al archivo empaquetado, crea una carpeta con su
|
|
nombre sin la extensión y pon dentro un archivo cambiado. Ejecuta el juego
|
|
empaquetado y mira cómo gana tu archivo suelto.
|
|
. *Haz un parche.* Cambia la versión a `1.0.3`, pon solo el script en una
|
|
carpeta `fixes`, empaqueta eso como un `.patch` y aplícalo al juego que ya
|
|
hiciste. Comprueba la versión en pantalla.
|
|
. *Rompe el empaquetador.* Cambia el nombre de tu `games.dat` un momento e
|
|
intenta empaquetar. Luego déjalo como estaba, haz que uno de sus `SCRIPT`
|
|
apunte a un archivo que no existe y vuelve a intentarlo. Dos rechazos
|
|
distintos, los dos antes de que se escriba nada.
|
|
. *Escribe los créditos de verdad.* Repasa la carpeta de tu juego archivo por
|
|
archivo y escribe una línea por cada uno que no hayas hecho tú. Si no
|
|
recuerdas de dónde salió algo, esa es la respuesta a si deberías publicarlo.
|
|
|
|
[#_break_it_on_purpose_29]
|
|
=== Rómpelo a propósito
|
|
|
|
Ejecuta Singe una vez desde *dentro* de la carpeta de tu juego, para que el
|
|
motor desempaquete ahí sus archivos de soporte, y luego empaquétala:
|
|
|
|
----
|
|
Singe --pack MyGame MyGame.game
|
|
----
|
|
|
|
----
|
|
!!! MyGame has Framework.singe: Singe/Framework.singe
|
|
!!! MyGame has sh file: Menu.sh
|
|
----
|
|
|
|
No se escribe nada. Cada línea es un archivo que no acepta y el porqué, y puede
|
|
que te salgan en otro orden o que salgan otras además. Hay una copia de la
|
|
propia carpeta de soporte del motor dentro de tu juego, y el script lanzador que
|
|
el motor escribió a su lado, porque en algún momento ejecutaste Singe desde ahí
|
|
dentro. Un juego no debe llevar nunca ninguno de los dos: los archivos de
|
|
soporte pertenecen al Singe que esté usando el jugador, no a tu juego, y un
|
|
`Framework.singe` empaquetado se cargaría en lugar del suyo. En Windows, la
|
|
segunda línea nombra `Menu.bat` en su lugar.
|
|
|
|
Borra la carpeta `Singe` y `Menu.sh` (o `Menu.bat`) de dentro de tu juego, deja
|
|
la carpeta de tu juego como una carpeta junto al programa Singe y no alrededor
|
|
de él, y vuelve a empaquetar.
|
|
Es la misma organización que describía la lección trece, y este error es lo que
|
|
pasa cuando se descuida.
|
|
|
|
[#_what_you_learned_30]
|
|
=== Lo que has aprendido
|
|
|
|
* `Singe --pack folder name.game` convierte la carpeta de un juego en un solo
|
|
archivo, y copiar ese archivo junto al programa Singe lo instala.
|
|
* Todo nombre de archivo dentro de un juego empaquetado se busca primero en una
|
|
carpeta suelta, luego en la carpeta de datos y luego en la base de datos.
|
|
* Una carpeta suelta con el nombre del archivo empaquetado lo sustituye archivo
|
|
por archivo, que es como sigues trabajando -- y como publicas una versión rota
|
|
si te olvidas de que está ahí.
|
|
* Carga con `DIR` y escribe solo dentro de `singeGetDataPath()`, o tu juego
|
|
funcionará suelto y fallará empaquetado.
|
|
* `--patch` sustituye archivos de un juego publicado en una sola transacción;
|
|
`--unpack` vuelve a sacarlo todo.
|
|
* El empaquetador rechaza los archivos del motor, los nombres que chocan y un
|
|
`games.dat` que apunta a archivos que no tiene.
|
|
* Desempaqueta tu propia versión y lee lo que lleva antes de mandarla a ningún
|
|
sitio.
|
|
* El arte y el sonido de otros vienen con condiciones, y cumplirlas significa
|
|
una pantalla de créditos dentro del juego.
|
|
* Un número de versión solo sube, y su sitio es la pantalla.
|
|
* Prueba en un ordenador que no sea el tuyo, empezando sin ninguna carpeta
|
|
`data`.
|
|
|
|
[#_next_time_30]
|
|
=== La próxima vez
|
|
|
|
Un solo archivo, instalado, con sus créditos y su número. La última lección lo
|
|
mete en una caja de madera con una ranura para monedas y sin teclado, lo que
|
|
cambia más cosas de tu juego de lo que crees.
|