singe/docs/es/lessons/01-hello.adoc

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.