289 lines
11 KiB
Text
289 lines
11 KiB
Text
[#_lesson_1_hello]
|
|
== Lección 1: Hola
|
|
|
|
image::learn/01-hello.png[La lección terminada, 480]
|
|
|
|
Eso es lo que tendrás al final de esta lección. No es gran cosa a la vista.
|
|
También es un programa que has escrito tú, funcionando en un motor de juegos de
|
|
verdad, y todo lo demás de este libro se construye sobre las cinco líneas que lo
|
|
hicieron.
|
|
|
|
[#_set_up_your_work_folder]
|
|
=== Prepara tu carpeta de trabajo
|
|
|
|
Crea una carpeta para guardarlo todo, llamada `singe` o como quieras, y pon
|
|
dentro tu copia de Singe. Esta es tu *carpeta de trabajo*, y cada lección de
|
|
este libro pone una carpeta nueva dentro de ella. La crearás una vez y no
|
|
volverás a pensar en ella.
|
|
|
|
Dentro de la carpeta de trabajo, crea una carpeta llamada `hello`, y dentro de
|
|
ella un archivo llamado `hello.singe`.
|
|
|
|
[literal]
|
|
----
|
|
singe/ <- tu carpeta de trabajo, con Singe dentro
|
|
hello/
|
|
hello.singe
|
|
----
|
|
|
|
Tanto anidamiento no es una manía. Singe trata la carpeta desde la que lo
|
|
ejecutas como el sitio donde viven los juegos, una carpeta por juego, y también
|
|
guarda allí sus propios archivos. Tu juego va en su propia carpeta, un nivel más
|
|
abajo. De la lección dos en adelante, cada lección es otra carpeta junto a
|
|
`hello`.
|
|
|
|
Dos cosas sobre los nombres. La parte que va después del punto, `.singe`, es
|
|
como Singe sabe que esto es un script. Y en la mayoría de los ordenadores que no
|
|
son Windows, las mayúsculas cuentan: `Hello.singe` y `hello.singe` son dos
|
|
archivos distintos. Acostúmbrate desde ya a escribir los nombres exactamente.
|
|
|
|
Que la carpeta y el script tengan el mismo nombre también importa, y enseguida
|
|
verás por qué.
|
|
|
|
Abre `hello.singe` en tu editor de texto. Está vacío. Es lo correcto.
|
|
|
|
[#_type_this_in]
|
|
=== Escribe esto
|
|
|
|
[source,lua]
|
|
----
|
|
function onOverlayUpdate()
|
|
overlayClear()
|
|
overlayPrint(2, 2, "Hello!")
|
|
return OVERLAY_UPDATED
|
|
end
|
|
----
|
|
|
|
Guárdalo.
|
|
|
|
No te preocupes todavía por lo que significa nada de esto. Vale la pena fijarse
|
|
en dos cosas antes de ejecutarlo, porque se cumplirán en todos los programas que
|
|
escribas.
|
|
|
|
La primera es que los espacios al principio de las tres líneas del medio están
|
|
ahí a propósito. No le hacen nada en absoluto al programa -- Singe lo ejecutaría
|
|
exactamente igual sin ellos -- pero te muestran de un vistazo que esas tres
|
|
líneas van *dentro* de la cosa que empieza con `function` y termina con `end`.
|
|
Todos los programadores lo hacen. Hazlo desde el primer día y nunca tendrás que
|
|
aprenderlo más tarde.
|
|
|
|
La segunda es el orden de las líneas. Ocurren de arriba abajo, una tras otra,
|
|
como los pasos de una receta. Es lo más importante de un programa, y casi todo
|
|
lo que confunde a un principiante viene de olvidarlo.
|
|
|
|
[#_run_it]
|
|
=== Ejecútalo
|
|
|
|
Abre una terminal, ve a tu *carpeta de trabajo* -- no a la carpeta `hello` que
|
|
hay dentro -- y escribe el nombre de la carpeta que quieres ejecutar:
|
|
|
|
----
|
|
Singe hello
|
|
----
|
|
|
|
En Windows es `Singe.exe hello`. Si tu copia de Singe está en otro sitio,
|
|
escribe la ruta hasta ella, por ejemplo `../Singe hello`.
|
|
|
|
Por eso la carpeta y el script comparten nombre. Cuando le das una carpeta,
|
|
Singe busca dentro un script que se llame igual. Ponles nombres distintos y
|
|
obtendrás `Error: Unable to locate the game.`, que es el motor diciendo que ha
|
|
buscado y no ha encontrado nada que reconozca. Siempre puedes ser explícito y
|
|
escribir `Singe hello/hello.singe`, que hace lo mismo.
|
|
|
|
Se abre una ventana negra con la palabra `Hello!` cerca de la esquina superior
|
|
izquierda. Pulsa *Esc* o *Q* para salir.
|
|
|
|
Habrán pasado dos cosas que no has pedido, y las dos son normales. En tu carpeta
|
|
de trabajo han aparecido unas carpetas llamadas `Singe` y `data`, junto a
|
|
`hello`: la primera es el motor desempaquetando los archivos que necesita, y la
|
|
segunda es donde irá todo lo que guarden tus juegos. Deja las dos en paz. Y la
|
|
ventana es casi toda negra, porque no has dibujado nada aparte de seis
|
|
caracteres.
|
|
|
|
[#_what_just_happened]
|
|
=== Qué acaba de pasar
|
|
|
|
Ahora las cinco líneas, de una en una.
|
|
|
|
[source,lua]
|
|
----
|
|
function onOverlayUpdate()
|
|
----
|
|
|
|
`function` empieza un grupo de instrucciones y le da un nombre. Todo lo que hay
|
|
desde aquí hasta el `end` que le corresponde le pertenece. Esta se llama
|
|
`onOverlayUpdate`, y los paréntesis vacíos después del nombre tendrán sentido en
|
|
la lección cinco.
|
|
|
|
Ese nombre no lo eliges tú. Singe busca una función con exactamente ese nombre y
|
|
la llama unas sesenta veces por segundo, para siempre, para que tengas ocasión
|
|
de dibujar. Si lo escribes `onoverlayupdate` u `onOverlayUpdated`, Singe no la
|
|
encontrará, tu ventana se quedará negra y nada te dirá que te has equivocado.
|
|
Esa es la primera lección de verdad: el ordenador hace lo que escribiste, no lo
|
|
que querías decir.
|
|
|
|
Una función que escribes tú y que llama el motor es un *callback*. No la llamas
|
|
tú, y no puedes decidir cuándo se ejecuta; la escribes, y Singe te devuelve la
|
|
llamada cuando hay algo que hacer. Todos los nombres de este libro que empiezan
|
|
por `on` son callbacks, y hay uno para casi todo lo que puede pasar: un botón
|
|
pulsado, una tecla escrita, un sonido que termina, el disco que llega a un
|
|
fotograma. `onOverlayUpdate` es el de dibujar, y es el único sitio donde se
|
|
permite dibujar.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayClear()
|
|
----
|
|
|
|
Esto también es una función, pero no una que tengas que escribir tú: la
|
|
proporciona Singe, junto con varios cientos más, y tú la estás *llamando*.
|
|
Llamar a una función significa decir su nombre seguido de paréntesis. Esta deja
|
|
la pantalla limpia.
|
|
|
|
Va primero porque dibujar no sustituye lo que había antes, sino que dibuja
|
|
encima. Primero limpias, luego dibujas, siempre.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayPrint(2, 2, "Hello!")
|
|
----
|
|
|
|
Otra llamada, y a esta hay que decirle tres cosas, que van dentro de los
|
|
paréntesis separadas por comas. Las cosas que le das así a una función se llaman
|
|
*argumentos*.
|
|
|
|
Las dos primeras son números: cuánto hacia la derecha y cuánto hacia abajo. La
|
|
tercera es el texto que hay que imprimir, y va entre comillas dobles porque así
|
|
es como le dices al ordenador que `Hello!` es un trozo de texto y no el nombre
|
|
de algo. Al texto entre comillas se le llama *cadena*, y usarás cadenas
|
|
constantemente.
|
|
|
|
Tarde o temprano querrás poner unas comillas dobles dentro de una cadena, y la
|
|
forma obvia no funciona: las segundas comillas terminan la cadena antes de
|
|
tiempo, y te sale el mismo error `unfinished string` que verás al final de esta
|
|
lección. Hay dos formas de evitarlo, y vale la pena conocer las dos.
|
|
|
|
[source,lua]
|
|
----
|
|
overlayPrint(2, 2, "She said \"hello\" to me.")
|
|
overlayPrint(2, 4, 'She said "hello" to me.')
|
|
----
|
|
|
|
La primera pone una barra invertida delante de cada comilla que forma parte del
|
|
texto. La barra invertida dice «el siguiente carácter es parte de la cadena, no
|
|
su final», y las dos juntas se llaman *secuencia de escape*. La segunda usa
|
|
comillas simples para marcar los extremos de la cadena, lo que deja las comillas
|
|
dobles libres para ser texto normal. Lua acepta cualquiera de los dos tipos de
|
|
comillas, siempre que la cadena termine con el mismo tipo con el que empezó.
|
|
|
|
Esas dos líneas imprimen exactamente lo mismo. Usa la que se lea mejor, que
|
|
suele ser la de comillas simples cuando el texto está lleno de comillas dobles.
|
|
|
|
Los dos números no son píxeles. `overlayPrint` es el texto sencillo del propio
|
|
motor, y cuenta en celdas de carácter: `(0, 0)` es la esquina superior izquierda
|
|
del todo, `(1, 0)` es una letra a la derecha, y `(0, 1)` es una línea más abajo.
|
|
Así que `(2, 2)` está dos letras hacia dentro y dos líneas hacia abajo. Otras
|
|
formas de dibujar texto sí cuentan en píxeles, y las verás en la lección
|
|
diecinueve.
|
|
|
|
[source,lua]
|
|
----
|
|
return OVERLAY_UPDATED
|
|
----
|
|
|
|
`return` devuelve una respuesta a quien haya llamado a la función. Singe le hace
|
|
a tu `onOverlayUpdate` una pregunta cada vez que la llama: ¿has cambiado algo?
|
|
`OVERLAY_UPDATED` significa que sí, así que ponlo en pantalla.
|
|
|
|
`OVERLAY_UPDATED` no lleva comillas porque no es texto. Es un nombre que Singe
|
|
ya le ha dado a un valor, para que puedas escribir algo que se pueda leer en
|
|
lugar de un número que tendrías que recordar.
|
|
|
|
[source,lua]
|
|
----
|
|
end
|
|
----
|
|
|
|
El final que corresponde a la `function`. Cada `function` tiene exactamente uno,
|
|
y olvidarlo es el error más común que existe.
|
|
|
|
[#_try_it]
|
|
=== Pruébalo
|
|
|
|
Cambia una cosa cada vez, guarda y vuelve a ejecutarlo. Ese ciclo -- cambiar,
|
|
ejecutar, mirar -- es todo el trabajo.
|
|
|
|
. *Mueve el texto.* Cambia `overlayPrint(2, 2, "Hello!")` por
|
|
`overlayPrint(10, 5, "Hello!")`. Luego prueba `(0, 0)`. Luego prueba
|
|
`(200, 2)`, y averigua por qué ha desaparecido.
|
|
. *Di otra cosa.* Pon tu nombre entre las comillas.
|
|
. *Di dos cosas.* Añade una segunda línea `overlayPrint` debajo de la primera,
|
|
con otro número de fila y otro texto. Nada te impide tener tantas como
|
|
quieras.
|
|
. *Quita la limpieza.* Borra la línea `overlayClear()` y ejecútalo. No cambia
|
|
nada, porque todavía no se mueve nada en tu pantalla. Vuelve a ponerla de
|
|
todos modos. En la lección dos importará muchísimo, y este es un buen momento
|
|
para ver que algunos errores esperan antes de morder.
|
|
|
|
[#_break_it_on_purpose]
|
|
=== Rómpelo a propósito
|
|
|
|
Los principiantes pasan más tiempo leyendo mensajes de error que leyendo libros
|
|
de programación, así que quitémonos ya el primero de encima.
|
|
|
|
Borra las comillas de cierre después de `Hello!`, para que la línea quede
|
|
`overlayPrint(2, 2, "Hello!)`, y ejecútalo. Singe se niega a arrancar y dice:
|
|
|
|
----
|
|
Error running script: hello/hello.singe:3: unfinished string near '"Hello!)'
|
|
----
|
|
|
|
Léelo desde la izquierda. `hello/hello.singe` es qué archivo: la carpeta y luego
|
|
el script que hay dentro. `3` es qué línea. El
|
|
resto es lo que ha ido mal, en este caso un trozo de texto que se abrió y nunca
|
|
se cerró. Ve a la línea tres, vuelve a poner las comillas y funciona.
|
|
|
|
Casi todos los errores que verás tienen esa forma: un archivo, una línea y una
|
|
queja. La queja a veces está escrita para alguien que ya sabe Lua, pero el
|
|
archivo y la línea siempre son correctos, y nueve de cada diez veces la línea
|
|
basta.
|
|
|
|
[#_stop_restarting_it]
|
|
=== Deja de reiniciarlo
|
|
|
|
Ya has arrancado Singe a mano cinco o seis veces. Deja de hacerlo. Ejecútalo
|
|
así:
|
|
|
|
----
|
|
Singe -R hello
|
|
----
|
|
|
|
`-R` le dice a Singe que vigile tu script. Guarda un cambio en tu editor y el
|
|
juego se reinicia solo un momento después con tu cambio dentro, sin cerrar la
|
|
ventana. Si guardas un error, se imprime el error y la ventana se queda vacía
|
|
hasta que guardes el arreglo.
|
|
|
|
Usa `-R` durante el resto de este libro.
|
|
|
|
[#_what_you_learned]
|
|
=== Lo que has aprendido
|
|
|
|
* Un programa es un archivo de instrucciones que ocurren en orden, de arriba
|
|
abajo.
|
|
* Una `function` agrupa instrucciones bajo un nombre y se detiene en su `end`.
|
|
* `onOverlayUpdate` es un nombre que Singe busca y llama muchas veces por
|
|
segundo, y es donde va todo lo que dibujas.
|
|
* Llamar a una función significa escribir su nombre y unos paréntesis. Lo que
|
|
va dentro de los paréntesis es un argumento.
|
|
* Una función que el motor llama por ti, en lugar de una que llamas tú, es un
|
|
callback. `onOverlayUpdate` es uno.
|
|
* El texto entre comillas dobles es una cadena.
|
|
* Limpia la pantalla antes de dibujar en ella.
|
|
* Un error te dice el archivo y la línea. Empieza por ahí.
|
|
|
|
[#_next_time]
|
|
=== La próxima vez
|
|
|
|
Tu `Hello!` se queda donde lo pusiste y nunca se mueve. Para que se mueva,
|
|
necesitas un sitio donde guardar un número que cambia -- una *variable* -- y de
|
|
eso trata toda la lección dos.
|