# tutorial de uxn: día 3, saltos condicionales y el teclado o controlador lang=es en->{uxn tutorial day 3} ¡esta es la tercera sección del {tutorial de uxn}! aquí introducimos el uso del dispositivo controlador en la computadora uxn varvara: esto nos permitirá añadir interactividad a nuestros programas y empezar a discutir el flujo de control en uxntal. también hablamos de las instrucciones lógicas y de manipulación de la pila en uxntal. # el dispositivo controlador el dispositivo controlador del ordenador varvara nos permite leer las entradas del teclado o de los botones del controlador. la definición de sus puertos tendría el siguiente aspecto en un programa típico: ``` |80 @Controlador [ &vector $2 &botón $1 &tecla $1 ] ``` ## el byte de botón el byte de botón codifica en cada uno de sus ocho bits el estado de ocho "botones" diferentes, basados en la disposición del controlador de NES, la videoconsola clásica de 8 bits de Nintendo. => https://wiki.nesdev.com/w/index.php/Standard_controller controlador NES estándar numerando los bits de derecha a izquierda y de 0 a 7, las teclas correspondientes (y los botones de NES) son + + + + + + + + + + +
bitteclabotón
7Derecha
6Izquierda
5Abajo
4Arriba
3HomeIniciar
2ShiftSelecccionar
1AltB
0CtrlA
& * 7: Derecha & * 6: Izquierda & * 5: Abajo & * 4: Arriba & * 3: Home (Iniciar) & * 2: Shift (Selecccionar) & * 1: Alt (botón B) & * 0: Ctrl (botón A) codificar los estados de los botones de esta manera nos permite presionar y leer muchas de estas teclas al mismo tiempo. ## el byte de tecla el byte de tecla almacena el código ascii de la tecla del teclado que se está pulsando en ese momento. la diferencia entre el byte 'de tecla' y el byte 'de botón' puede ser confusa, especialmente cuando se ejecuta varvara desde uxnemu, donde varias teclas actúan además de botones. una posible manera de recordar podría ser pensar en el byte 'de botón' como refiriéndose a un controlador de gamepad. ## el vector del controlador en el contexto de la programación de uxn, un vector se refiere a una dirección en la memoria principal donde se asigna a uxn para que salte cuando ocurra un evento específico. en el caso del vector del controlador, este evento específico consiste en cada vez que se pulsa o suelta una tecla. en otras palabras: uxn saltará a la dirección asignada como vector del controlador, cada vez que se pulse o suelte una tecla. la siguiente línea de código asignaría ese vector, utilizando la dirección absoluta de la etiqueta en-controlador: ``` ;en-controlador .Controlador/vector DEO2 ``` ¡veamos a continuación como funcionaría! # flujo de control: subrutinas vectoriales hasta ahora nuestros programas uxntal han seguido un flujo lineal: comienzan en la dirección 0100 y terminan en la primera instrucción BRK que se encuentra. podemos pensar en estos programas como rutinas de configuración: configuran los colores del sistema, pueden dibujar o imprimir algunas cosas y luego dejan a uxn esperando. ¿qué estaría esperando uxn? sí, una opción sería: ¡esperar la entrada del teclado! vamos a empezar a organizar nuestros programas uxntal en términos de subrutinas que corresponden a diferentes vectores. cada una de estas subrutinas terminará con la instrucción BRK, para que puedan hacer que uxn vuelva al estado de espera. ## subrutina del vector del controlador para ilustrar ese comportamiento, leamos el siguiente programa. este utiliza el procedimiento de dibujo de sprites que probamos el día anterior, pero hace que ocurra solo cuando se pulsa una tecla. al principio, la pantalla está vacía, y cuando pulsamos una tecla, se dibuja un cuadrado: ``` ( hola-teclado.tal ) ( dispositivos ) |00 @Sistema [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ] |20 @Pantalla [ &vector $2 &ancho $2 &alto $2 &pad $2 &x $2 &y $2 &direc $2 &píxel $1 &sprite $1 ] |80 @Controlador [ &vector $2 &botón $1 &tecla $1 ] ( programa principal ) |0100 ( establecer los colores del sistema ) #2ce9 .Sistema/r DEO2 #01c0 .Sistema/g DEO2 #2ce5 .Sistema/b DEO2 ( asignar vector del controlador ) ;en-controlador .Controlador/vector DEO2 BRK ( ejecutar este código cada vez que se pulse o suelte una tecla ) @en-controlador ( -> ) ( establecer coordenadas x,y ) #0008 .Pantalla/x DEO2 #0008 .Pantalla/y DEO2 ( establecer la direccion del sprite ) ;cuadrado .Pantalla/direc DEO2 ( dibujar el sprite en el fondo ) ( usando el color 1 para el contorno ) #01 .Pantalla/sprite DEO BRK ( sprite ) @cuadrado ff81 8181 8181 81ff ``` bonito, ¿no? ahora, ¿cómo podemos realizar diferentes acciones dependiendo de la tecla que se haya pulsado? en primer lugar, tenemos que hacer que nuestro programa sepa qué tecla se ha pulsado para que pueda actuar en consecuencia. para ello, veamos algunas instrucciones uxntal nuevas. # instrucciones de comparación y lógica ## instrucciones de comparación uxntal tiene cuatro instrucciones para comparar los dos primeros elementos de la pila: * EQU: empuja 01 hacia abajo en la pila si los dos elementos superiores de la pila son iguales, o empuja 00 en caso contrario ( a b -- a==b ) * NEQ: empuja 01 hacia abajo en la pila si los dos elementos superiores de la pila no son iguales, o empuja 00 en caso contrario ( a b -- a!=b ) * GTH: empuja 01 hacia abajo en la pila si el primer elemento es mayor que el segundo, o empuja 00 en caso contrario ( a b -- a>b ) * LTH: empuja 01 hacia abajo en la pila si el primer elemento es menor que el segundo, o empuja 00 en caso contrario ( a b -- a ./img/screenshot_uxn-draw-with-keyboard.png captura de pantalla de un posible resultado de la ejecución del siguiente programa; muestra un rastro dibujado con cuadrados rellenos o delineados. el siguiente programa uxntal permite dibujar utilizando las teclas de las flechas y la tecla Ctrl (botón A). las flechas mueven la posición de un sprite, y al pulsar Ctrl mientras se mueve, lo dibujará con los colores inversos en relleno y trazo. observa el uso de las máscaras AND, los saltos condicionales y algunas operaciones de la pila. ``` ( dibujar-con-teclado.tal ) ( dispositivos ) |00 @Sistema [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ] |20 @Pantalla [ &vector $2 &ancho $2 &alto $2 &pad $2 &x $2 &y $2 &direc $2 &píxel $1 &sprite ] |80 @Controlador [ &vector $2 &botón $1 &tecla $1 ] ( programa principal ) |0100 ( establecer los colores del sistema ) #2ce9 .Sistema/r DEO2 #01c0 .Sistema/g DEO2 #2ce5 .Sistema/b DEO2 ( asignar vector del controlador ) ;en-controlador .Controlador/vector DEO2 ( establecer coordenadas iniciales x,y ) #0008 .Pantalla/x DEO2 #0008 .Pantalla/y DEO2 ( establece la dirección del sprite ) ;cuadrado .Pantalla/direc DEO2 BRK @en-controlador ( -> ) .Controlador/botón DEI DUP ( leer y duplicar el byte del botón ) #01 AND ( aislar el bit 0, correspondiente a Ctrl ) ,&relleno JCN ( si el bit no es 0, saltar al relleno; si es 0, continuar ) &contorno #01 .Pantalla/sprite DEO ( dibujar contorno ) ,&comprobar-flechas JMP ( continuar con comprobar-flechas ) &relleno #04 .Pantalla/sprite DEO ( dibujar relleno ) &comprobar-flechas ( usar el byte del botón de la pila ) DUP #10 AND ( aislar el bit 4, correspondiente a Arriba ) ,&arriba JCN ( saltar si no es 0 ) DUP #20 AND ( aísla el bit 5, correspondiente a Abajo ) &abajo JCN ( salta si no es 0 ) DUP #40 AND ( aislar el bit 6, correspondiente a Izquierda ) ,&izquierda JCN ( salta si no es 0 ) DUP #80 AND ( aísla el bit 7, correspondiente a Derecha ) &derecha JCN ( salta si no es 0 ) POP BRK &arriba .Pantalla/y DEI2 #0008 SUB2 .Pantalla/y DEO2 ( disminuye y ) POP BRK &abajo .Pantalla/y DEI2 #0008 ADD2 .Pantalla/y DEO2 ( incrementa y ) POP BRK &izquierda .Pantalla/x DEI2 #0008 SUB2 .Pantalla/x DEO2 ( disminuye x ) POP BRK &derecha .Pantalla/x DEI2 #0008 ADD2 .Pantalla/x DEO2 ( incrementa x ) POP BRK BRK ( sprite ) @cuadrado ff81 8181 8181 81ff ``` algunas posibilidades para que practiques: * modificar el código para que también responda a que pulses más de una flecha al mismo tiempo. * convertir los incrementos y decrementos de las coordenadas en macros que tomen la dirección del puerto como entrada y realizar una operación equivalente. estas dos líneas deberían funcionar usando la misma macro: ``` .Pantalla/x INCREMENTO .Pantalla/y INCREMENTO ``` recuerde que .Pantalla/x es una dirección literal en la página cero, es decir, empuja un byte correspondiente a la dirección de la subetiqueta Pantalla/x :) # practica posibilidades ¡aquí tienes otras ideas para que practiques con lo que hemos cubierto hoy! * dibujar un controlador virtual que muestre cuáles de sus botones, mapeados a teclas del teclado, están siendo presionados * crear una especie de máquina de escribir que dibuje diferentes símbolos y mueva el cursor de dibujo dependiendo de la tecla que se haya pulsado * dibujar un personaje que cambie su estado según la tecla que se haya pulsado. ¿tal vez utilizar múltiples tiles para dibujarlo? * crea un simple tablero de tres-en-raya para dos jugadores: una tecla dibuja una X, otra dibuja una O y las flechas permiten elegir la casilla a dibujar. ¡ten en cuenta que para un suave movimiento interactivo puede ser mejor utilizar el vector de pantalla que se llama 60 veces por segundo! ¡lo cubriremos en profundidad en el próximo día del tutorial! # instrucciones del día 3 ¡estas son todas las instrucciones uxntal de las que hemos hablado hoy! ## instrucciones de comparación * EQU: empuja 01 hacia abajo en la pila si los dos primeros elementos de la pila son iguales, o empuja 00 en caso contrario ( a b -- a==b ) * NEQ: empuja 01 hacia abajo en la pila si los dos primeros elementos de la pila no son iguales, o empuja 00 en caso contrario ( a b -- a!=b ) * GTH: empuja 01 hacia abajo en la pila si el primer elemento es mayor que el segundo, o empuja 00 en caso contrario ( a b -- a>b ) * LTH: empuja 01 hacia abajo en la pila si el primer elemento es menor que el segundo, o empuja 00 en caso contrario ( a b -- a