Ortotipografía: enumeraciones con y

Las enumeraciones y algunas conjunciones de oraciones en el texto preceden la conjunción «y» de una coma. En español, esta coma no es apropiada para separar el último término de la enumeración o las oraciones que se unen.

Posiblemente se trate de un calco del inglés. Se puede leer sobre este uso en la Fundéu, que cita a su vez el Diccionario panhispánico de dudas:
https://www.fundeu.es/recomendaciones/no-se-escribe-coma-delante-de-la-yde-las-enumeraciones-1123/
This commit is contained in:
Roberto MF 2022-01-25 01:11:00 +01:00
parent e1d4942426
commit 5f35851a56
9 changed files with 198 additions and 198 deletions

View File

@ -2,11 +2,11 @@
una guía introductoria y pausada para programar la computadora varvara basada en el núcleo {uxn}.
> El ecosistema de Uxn es un espacio de juego y exploración de computación personal, creado para desarrollar y utilizar pequeñas herramientas y juegos, y programable en su propio lenguaje ensamblador.
> El ecosistema de Uxn es un espacio de juego y exploración de computación personal, creado para desarrollar y utilizar pequeñas herramientas y juegos y programable en su propio lenguaje ensamblador.
=> https://100r.co/site/uxn.html 100R - uxn
también puedes conseguir una versión "offline" de este material, y apoyar nuestros proyectos, con el libro {introducción a programación uxn}.
también puedes conseguir una versión "offline" de este material y apoyar nuestros proyectos, con el libro {introducción a programación uxn}.
esta es una traducción del {uxn tutorial} a cargo de ~jota.
@ -15,7 +15,7 @@ esta es una traducción del {uxn tutorial} a cargo de ~jota.
# día 1
en esta primera sección del tutorial vamos a hablar de los aspectos básicos de la computadora uxn llamada varvara, su paradigma de programación, su arquitectura, y por qué podrías querer aprender a programar en ella.
en esta primera sección del tutorial vamos a hablar de los aspectos básicos de la computadora uxn llamada varvara, su paradigma de programación, su arquitectura y por qué podrías querer aprender a programar en ella.
también vamos a saltar directo a nuestros primeros programas simples para demostrar conceptos fundamentales que desarrollaremos en los días siguientes.
@ -31,7 +31,7 @@ también discutiremos el trabajo con cortos (2 bytes) además de los números de
# día 3
aquí introducimos el uso del dispositivo controlador en la computadora varvara: esto nos permite agregar interactividad a nuestros programas, y empezar a implementar control de flujo en uxntal.
aquí introducimos el uso del dispositivo controlador en la computadora varvara: esto nos permite agregar interactividad a nuestros programas y empezar a implementar control de flujo en uxntal.
también hablamos de instrucciones lógicas y de manipulación de la pila en uxntal.
@ -47,7 +47,7 @@ también hablamos del uso de la memoria del programa como un espacio para datos
# día 5
aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo de retención.
aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo de retención.
también discutimos posibles estructuras para crear bucles y programas más complejos utilizando estos recursos.
@ -59,7 +59,7 @@ aquí hablamos de cómo podemos integrar todo lo que hemos cubierto para crear s
basamos nuestra discusión en una recreación del clásico juego pong.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar sprites de varios tiles, y para comprobar las colisiones.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar sprites de varios tiles y para comprobar las colisiones.
{tutorial de uxn día 6}

View File

@ -2,13 +2,13 @@
en la primera parte del {tutorial de uxn día 6} hablamos de cómo cubrir el fondo de la pantalla con un tile dado.
aquí generalizaremos un procedimiento similar en una subrutina dibuja-tiles que dibuje un rectángulo relleno con un tile dado. recibirá las coordenadas x,y de la esquina superior izquierda del rectángulo, su anchura y altura en píxeles, y la dirección del tile:
aquí generalizaremos un procedimiento similar en una subrutina dibuja-tiles que dibuje un rectángulo relleno con un tile dado. recibirá las coordenadas x,y de la esquina superior izquierda del rectángulo, su anchura y altura en píxeles y la dirección del tile:
```
@dibuja-tiles ( x^ y^ ancho^ alto^ direc* -- )
```
un recordatorio de que estamos utilizando la convención de añadir un signo de intercalación (^) después del nombre de un valor para indicar que es un corto, y un asterisco (*) para indicar que es un corto que funciona como un puntero (es decir, una dirección en la memoria del programa)
un recordatorio de que estamos utilizando la convención de añadir un signo de intercalación (^) después del nombre de un valor para indicar que es un corto y un asterisco (*) para indicar que es un corto que funciona como un puntero (es decir, una dirección en la memoria del programa)
vamos a detallar cómo llegar a dos versiones de esta subrutina, una que se basa en una fuerte manipulación de la pila, y otra que utiliza variables. esto con el fin de comparar ambos enfoques y darnos una visión más amplia de las posibilidades dentro de uxntal.
@ -41,7 +41,7 @@ BRK
## repetir un tile en una fila
¿qué procedimiento podríamos seguir para repetir el dibujo de un tile empezando por x, y terminando en un límite correspondiente a x+ancho?
¿qué procedimiento podríamos seguir para repetir el dibujo de un tile empezando por x y terminando en un límite correspondiente a x+ancho?
una forma sería algo así como:
@ -53,7 +53,7 @@ una forma sería algo así como:
antes de abstraerlo, recomiendo que lo escribamos con números concretos.
digamos que nuestra x inicial es 0008, nuestro ancho es 0100, y el tile que estamos dibujando es tile-fondo.
digamos que nuestra x inicial es 0008, nuestro ancho es 0100 y el tile que estamos dibujando es tile-fondo.
el límite, x+ancho, sería 0108.
@ -134,7 +134,7 @@ recuerda que estamos mostrando la parte superior de las pilas a su derecha.
después de estos pasos, la x inicial está en la parte superior de la pila, por lo que podemos enviarla directamente a la pantalla.
el último cambio que necesitaríamos es reemplazar nuestro límite codificado por una instrucción STH2kr (copiar el límite de la pila de retorno a la pila de trabajo), y terminar nuestra rutina con una POP2r (eliminar el límite de la pila de retorno).
el último cambio que necesitaríamos es reemplazar nuestro límite codificado por una instrucción STH2kr (copiar el límite de la pila de retorno a la pila de trabajo) y terminar nuestra rutina con una POP2r (eliminar el límite de la pila de retorno).
nuestra subrutina se vería entonces de la siguiente manera:
@ -206,7 +206,7 @@ RTN
## repetir una fila
similar a lo que acabamos de hacer: ¿cuál es el procedimiento que podríamos seguir para repetir verticalmente una fila empezando por `y`, y terminando en un límite correspondiente a y+altura?
similar a lo que acabamos de hacer: ¿cuál es el procedimiento que podríamos seguir para repetir verticalmente una fila empezando por `y` y terminando en un límite correspondiente a y+altura?
siguiendo la misma estrategia, podríamos hacer:
@ -216,7 +216,7 @@ siguiendo la misma estrategia, podríamos hacer:
### versión concreta
utilicemos los mismos números que antes, suponiendo que nuestra `y` inicial es 0008, nuestra altura es 0100, y por tanto nuestro límite siendo 0108.
utilicemos los mismos números que antes, suponiendo que nuestra `y` inicial es 0008, nuestra altura es 0100, y por tanto, nuestro límite siendo 0108.
en el caso de x, comencemos en 0000 y tengamos un ancho correspondiente al ancho de la pantalla.
@ -245,7 +245,7 @@ el siguiente código se basa en el bucle anterior de x, pero ahora dibuja una fi
ahora, antes de saltar directamente a la emulación de la solución para dibujar la fila, vamos a notar que en este caso no es tan fácil.
¿por qué? porque la idea de nuestra subrutina dibuja-tiles es que debe ser capaz de recibir la x inicial y el ancho del rectángulo, y ahora mismo estos valores están codificados dentro del bucle.
¿por qué? porque la idea de nuestra subrutina dibuja-tiles es que debe ser capaz de recibir la x inicial y el ancho del rectángulo y ahora mismo estos valores están codificados dentro del bucle.
esta debería ser la firma de nuestra subrutina:
@ -272,7 +272,7 @@ en primer lugar, la dirección del tile es el valor de la parte superior de la p
.Pantalla/direc DEO2 ( ptra: x^ y^ ancho^ alto^ )
```
pensando en el bucle vertical, necesitamos calcular su límite sumando la altura a `y`, y necesitamos establecer la `y` inicial.
pensando en el bucle vertical, necesitamos calcular su límite sumando la altura a `y` y necesitamos establecer la `y` inicial.
podríamos hacer lo siguiente:
@ -353,7 +353,7 @@ STH2kr ( ptra: x^ ancho^ / pret: limite-y^ x^ ancho^ )
;dibuja-tiles-en-fila JSR2 ( ptra: / pret: limite-y^ x^ ancho^ )
```
¿qué sigue? añadir 8 a `y`, y comprobar si es menor que el límite. la primera parte va sin problemas:
¿qué sigue? añadir 8 a `y` y comprobar si es menor que el límite. la primera parte va sin problemas:
```
.Pantalla/y DEI2 #0008 ADD2 DUP2 ( añade 8 a `y`; ptra: y^ y^ / pret: limite-y^ x^ ancho^ )

View File

@ -1,6 +1,6 @@
# tutorial uxn: día 1, aspectos básicos
¡hola! en esta primera sección del {tutorial de uxn} vamos a hablar de los aspectos básicos de la computadora uxn llamada varvara, su paradigma de programación en un lenguaje llamado uxntal, su arquitectura, y por que puede que quieras aprender a programarla.
¡hola! en esta primera sección del {tutorial de uxn} vamos a hablar de los aspectos básicos de la computadora uxn llamada varvara, su paradigma de programación en un lenguaje llamado uxntal, su arquitectura y por que puede que quieras aprender a programarla.
también saltaremos directo a nuestros primeros programas simples para demostrar conceptos fundamentales que desarrollaremos en los próximos días.
@ -8,7 +8,7 @@ también saltaremos directo a nuestros primeros programas simples para demostrar
o primero que nada... ¿qué es uxn?
> El ecosistema de Uxn es un espacio de juego y exploración de computación personal, creado para desarrollar y utilizar pequeñas herramientas y juegos, y programable en su propio lenguaje ensamblador.
> El ecosistema de Uxn es un espacio de juego y exploración de computación personal, creado para desarrollar y utilizar pequeñas herramientas y juegos y programable en su propio lenguaje ensamblador.
=> https://100r.co/site/uxn.html 100R - uxn
@ -25,7 +25,7 @@ personalmente, veo en ella las siguientes virtudes:
* ámbito de práctica y experimentación de computación dentro de límites
* ya portada a plataformas de computación actuales y de varios años de antigüedad
¡todos estos conceotos suenan genial para mí, y espero que para ti también!
¡todos estos conceotos suenan genial para mí y espero que para ti también!
sin embargo, noto algunos aspectos que pueden hacerla parecer no tan asequible:
@ -36,7 +36,7 @@ la idea de este tutorial es explorar estos dos aspectos y revelar cómo trabajan
# notación postfija (y la pila)
el núcleo uxn está inspirado por las máquinas forth en que utiliza la recombinación de componentes simples para lograr soluciones apropiadas, y en que es una máquina basada en pila.
el núcleo uxn está inspirado por las máquinas forth en que utiliza la recombinación de componentes simples para lograr soluciones apropiadas y en que es una máquina basada en pila.
esto implica que está principalmente basada en interacciones con una pila "push down", dónde las operaciones son indicadas mediante la llamada notación postfija.
@ -56,7 +56,7 @@ dónde, leyendo de izquierda a derecha:
* el número 1 es empujado en la pila
* el número 48 es empujado en la pila
* + toma dos elementos de la parte superior de la pila, los suma, y empuja el resultado en la pila
* + toma dos elementos de la parte superior de la pila, los suma y empuja el resultado en la pila
el libro Starting Forth tiene algunas buenas ilustraciones sobre este proceso de suma:
@ -87,7 +87,7 @@ también podemos escribirla de muchas otras maneras, por ejemplo:
¡asegúrate de que éstas expresiones funcionan y son equivalentes! sólo debes seguir estas reglas, leyendo de izquierda a derecha:
* si es un número, empujarlo a la pila
* si es un operador, tomar dos elementos de la parte superior de la pila, aplicar la operación, y empujar el resultado en la pila.
* si es un operador, tomar dos elementos de la parte superior de la pila, aplicar la operación y empujar el resultado en la pila.
nota: en el caso de la división, los operandos siguen el mismo orden de izquierda a derecha. 3/2 sería escrito como:
@ -111,7 +111,7 @@ uxn puede manejar también palabras binarias de 16 bits (2 bytes), también cono
los números en uxn son expresados utilizando el sistema hexadecimal (base 16), en el que cada dígito (nibble) va de 0 a 9 y luego de 'a' a 'f' (en minúscula).
un byte necesita dos dígitos hexadecimales (nibbles) para ser expresado, y un corto necesita cuatro.
un byte necesita dos dígitos hexadecimales (nibbles) para ser expresado y un corto necesita cuatro.
## el cpu uxn
@ -134,7 +134,7 @@ la memoria en la computadora uxn consiste en cuatro espacios separados:
cada byte en la memoria principal posee una dirección de 16 bits (2 bytes) de tamaño, mientras que cada byte en la memoria de entrada/salida posee una dirección de 8 bits (1 byte) de tamaño. ambos pueden ser accedidos aleatoriamente.
los primeros 256 bytes de la memoria principal constituyen una sección llamada página cero. esta sección puede ser referenciada por 8 bits (1 byte), y su propósito es almacenar datos durante el tiempo de ejecución de la máquina.
los primeros 256 bytes de la memoria principal constituyen una sección llamada página cero. esta sección puede ser referenciada por 8 bits (1 byte) y su propósito es almacenar datos durante el tiempo de ejecución de la máquina.
hay tres instrucciones diferentes para interactuar con cada uno de estos espacios de memoria.
@ -150,7 +150,7 @@ el contador de programa es una palabra de 16 bits que indica la dirección del p
una vez que el cpu lee un byte, lo decodifica como instrucción y lo ejecuta.
la instrucción va a implicar normalmente un cambio en la(s) pila(s), y algunas veces también un cambio en el flujo normal del contador de programa: en lugar de apuntar al siguiente byte en memoria, puede ser apuntado a otro lado, "saltando" de un lugar en memoria a otro.
la instrucción va a implicar normalmente un cambio en la(s) pila(s) y algunas veces también un cambio en el flujo normal del contador de programa: en lugar de apuntar al siguiente byte en memoria, puede ser apuntado a otro lado, "saltando" de un lugar en memoria a otro.
# instalación y toolchain
@ -192,7 +192,7 @@ $ cd uxn
$ ./build.sh
```
si todo fué bién, verás varios mensajes en la terminal y una pequeña ventana con el título uxn, y una aplicación demo: uxnemu está ahora corriendo una "rom" correspondiendo a esa aplicación.
si todo fué bién, verás varios mensajes en la terminal y una pequeña ventana con el título uxn y una aplicación demo: uxnemu está ahora corriendo una "rom" correspondiendo a esa aplicación.
## controles uxnemu
@ -213,7 +213,7 @@ en principio puedes hacer doble clic en uxnemu y que se ejecute. sin embargo, ut
puedes ajustar tu $PATH para tenerlos disponibles en todos lados.
la idea es que para correr un programa escrito en uxntal (el lenguaje ensamblador de uxn), primero tienes que ensamblarlo en una "rom", y luego puedes correr esta rom con el emulador.
la idea es que para correr un programa escrito en uxntal (el lenguaje ensamblador de uxn), primero tienes que ensamblarlo en una "rom" y luego puedes correr esta rom con el emulador.
por ejemplo, para correr {darena} que se encuentra en projects/examples/demos/ :
@ -239,17 +239,17 @@ estuvimos hablando antes sobre el cpu uxn y las 32 instrucciones que sabe cómo
ese lenguaje ensamblador uxntal implica que hay una relación uno a uno mapeando de una instrucción escrita en el lenguaje a una palabra de 8 bit correspondiente que el cpu puede interpretar.
por ejemplo, la instrucción ADD (suma) en uxntal es codificada como un byte con el valor 18 en hexadecimal, y corresponde al siguiente conjunto de de acciones: toma los dos elementos superiores de la pila, los suma, y empuja el resultado a la pila.
por ejemplo, la instrucción ADD (suma) en uxntal es codificada como un byte con el valor 18 en hexadecimal y corresponde al siguiente conjunto de de acciones: toma los dos elementos superiores de la pila, los suma y empuja el resultado a la pila.
en sistemas de tipo forth podemos ver el siguiente tipo de notación para expresar los operandos que una instrucción toma de la pila, y el(los) resultado(s) que empuja devuelta a la pila:
en sistemas de tipo forth podemos ver el siguiente tipo de notación para expresar los operandos que una instrucción toma de la pila y el(los) resultado(s) que empuja devuelta a la pila:
```
ADD ( a b -- a+b )
```
esto significa que ADD toma el primer elemento desde arriba 'b', luego toma el siguiente primer elemento 'a', y empuja devuelta el resultado de sumar a+b.
esto significa que ADD toma el primer elemento desde arriba 'b', luego toma el siguiente primer elemento 'a' y empuja devuelta el resultado de sumar a+b.
ahora que estamos en eso, hay una instrucción complementaria, SUB (resta) (opcode 19), que toma los dos elementos superiores de la pila, los resta, y empuja a la pila el resultado:
ahora que estamos en eso, hay una instrucción complementaria, SUB (resta) (opcode 19), que toma los dos elementos superiores de la pila, los resta y empuja a la pila el resultado:
```
SUB ( a b -- a-b )
@ -259,7 +259,7 @@ nota que el orden de los operandos es similar al de la división que discutimos
## un primer programa
escribamos el siguiente programa en nuestro editor de texto favorito, y guardémoslo como hola.tal:
escribamos el siguiente programa en nuestro editor de texto favorito y guardémoslo como hola.tal:
```
( hola.tal )
@ -298,7 +298,7 @@ la primera línea es un comentario: los comentarios son encerrados entre parént
en la segunda linea ocurren varias cosas:
* |0100 : puede que recuerdes este número de antes - este es el valor inicial del contador de programa; la dirección del primer byte que el cpu lee. usamos esta notación para indicar que lo que esté escrito después será escrito en memoria después de esta dirección.
* LIT : esta aparece dos veces, y es una instrucción uxn con las siguientes acciones: empuja el siguiente valor en memoria a la pila, y hace que el contador de programa saltee ese byte.
* LIT : esta aparece dos veces y es una instrucción uxn con las siguientes acciones: empuja el siguiente valor en memoria a la pila y hace que el contador de programa saltee ese byte.
* 68 : un número hexadecimal, que corresponde al código ascii del caracter 'h'
* 18 : un número hexadecimal, que corresponde a una dirección de entrada/salida: dispositivo 1 (consola), dirección 8.
* DEO : otra instrucción uxn, que podemos definir como lo siguiente: escribir el byte dado en la dirección de dispositivo dada, ambos tomados de la pila ( byte dirección -- )
@ -313,7 +313,7 @@ leyendo el programa de izquierda a derecha, podemos ver el siguiente comportamie
¿y qué es el dispositivo de entrada/salida con la dirección 18?
mirando en la tabla de dispositivos de la referencia varvara, podemos ver que el dispositivo con la dirección 1 en el nibble superior es la consola (entrada y salida estandard), y que la columna con la dirección 8 corresponde a "escritura".
mirando en la tabla de dispositivos de la referencia varvara, podemos ver que el dispositivo con la dirección 1 en el nibble superior es la consola (entrada y salida estandard) y que la columna con la dirección 8 corresponde a "escritura".
=> https://wiki.xxiivv.com/site/varvara.html varvara
@ -347,11 +347,11 @@ $ hexdump -C bin/hola.rom
00000005
```
80 es el "opcode" correspondiente a LIT, y 17 es el opcode correspondiente a DEO. ¡y ahí están nuestros 68 y 18!
80 es el "opcode" correspondiente a LIT y 17 es el opcode correspondiente a DEO. ¡y ahí están nuestros 68 y 18!
¡osea, efectivamente, nuestro programa ensamblado presenta una correspondencia uno a uno con las instrucciones que acabamos de escribir!
de hecho, podríamos haber escrito nuestro programa con estos números hexadecimales (el código máquina), y hubiera funcionado igual:
de hecho, podríamos haber escrito nuestro programa con estos números hexadecimales (el código máquina) y hubiera funcionado igual:
```
( hola.tal )
@ -446,7 +446,7 @@ por eso debemos incluir una instrucción LIT.
incluso ahora que sabemos que #18 corresponde a empujar la dirección de dispositivo escribir en consola en la pila, por legibilidad y para asegurar nuestro código a futuro es una buena práctica asignar una serie de etiquetas que corresponderán a ese dispositivo y sus sub direcciones.
la runa @ nos permite definir etiquetas, y la runa & nos permite definir sub etiquetas.
la runa @ nos permite definir etiquetas y la runa & nos permite definir sub etiquetas.
por ejemplo, para el dispositivo de consola, la manera en que verías esto escrito en programas para la computadora varvara es la siguiente:
@ -474,7 +474,7 @@ luego tenemos varias sub etiquetas, indicadas por la runa &, y pads relativos, i
nada de esto sería traducido a código máquina, pero nos asiste al escribir código uxntal.
la runa para referirse a una dirección literal en la página cero o el espacio de direcciones de entrada/salida, es . (punto), y una / (barra) nos permite referirnos a una de sus sub etiquetas.
la runa para referirse a una dirección literal en la página cero o el espacio de direcciones de entrada/salida es . (punto) y una / (barra) nos permite referirnos a una de sus sub etiquetas.
recuerda: al ser una runa de "dirección literal" va a agregar una instrucción LIT antes de la correspondiente dirección :)
@ -508,7 +508,7 @@ por ejemplo, podemos ver que el siguiente fragmento de código es repetido varia
.Consola/escribe DEO ( equivalente a #18 DEO, o a LIT 18 DEO )
```
podemos definir un macro llamado EMIT que tomará de la pila un byte correspondiente a un caracter, y lo imprimirá en la salida estandard. para esto, necesitamos la runa %, y llaves para la definición.
podemos definir un macro llamado EMIT que tomará de la pila un byte correspondiente a un caracter y lo imprimirá en la salida estandard. para esto, necesitamos la runa % y llaves para la definición.
¡no olvides los espacios!
@ -590,8 +590,8 @@ recordemos que el número tendría que ser escrito como un byte completo para qu
éstas son las instrucciones que cubrimos hoy:
* ADD: toma los dos elementos superiores de la pila, los suma, y empuja el resultado ( a b -- a+b )
* SUB: toma los dos elementos superiores de la pila, los resta, y empuja el resultado ( a b -- a-b )
* ADD: toma los dos elementos superiores de la pila, los suma y empuja el resultado ( a b -- a+b )
* SUB: toma los dos elementos superiores de la pila, los resta y empuja el resultado ( a b -- a-b )
* LIT: empuja el siguiente byte en memoria a la pila
* DEO: escribe el byte dado en la dirección de dispositivo dada, tomando ambos de la pila ( byte dirección -- )

View File

@ -34,7 +34,7 @@ contando de derecha a izquierda, el 6to bit de un byte que codifica una instrucc
siempre que el modo corto esté activado, es decir, cuando ese bit sea 1 en lugar de 0, la cpu uxn realizará la instrucción dada por los 5 primeros bits (el opcode) pero utilizando pares de bytes en lugar de bytes individuales.
el byte que esté más adentro de la pila será el byte "alto" del corto, y el byte que esté más cerca de la parte superior de la pila será el byte "bajo" del corto.
el byte que esté más adentro de la pila será el byte "alto" del corto y el byte que esté más cerca de la parte superior de la pila será el byte "bajo" del corto.
en uxntal, indicamos que queremos poner esta bandera añadiendo el dígito '2' al final de una instrucción mnemónica.
@ -44,7 +44,7 @@ en uxntal, indicamos que queremos poner esta bandera añadiendo el dígito '2' a
### LIT2
en primer lugar, recapitulemos. el siguiente código empujará el número 02 hacia abajo en la pila, luego empujará el número 30 (hexadecimal) hacia abajo en la pila, y finalmente los sumará, dejando el número 32 en la pila:
en primer lugar, recapitulemos. el siguiente código empujará el número 02 hacia abajo en la pila, luego empujará el número 30 (hexadecimal) hacia abajo en la pila y finalmente los sumará, dejando el número 32 en la pila:
```
#02 #30 ADD
@ -70,7 +70,7 @@ LIT2 02 30 ADD ( código ensamblado: a0 02 30 18 )
en lugar de empujar un byte, LIT2 está empujando el corto (dos bytes) que sigue en la memoria, hacia abajo en la pila.
podemos utilizar la runa hexadecimal literal (#) con un corto (cuatro nibbles) en lugar de un byte (dos nibbles), y funcionará como una abreviatura de LIT2:
podemos utilizar la runa hexadecimal literal (#) con un corto (cuatro nibbles) en lugar de un byte (dos nibbles) y funcionará como una abreviatura de LIT2:
```
#0230 ADD
@ -86,7 +86,7 @@ ahora veamos que pasa con la instrucción ADD cuando usamos el modo corto.
#0004 #0008 ADD
```
así es! la pila tendrá los siguientes valores, porque estamos empujando 4 bytes hacia abajo en la pila, sumando (ADD) los dos más cercanos a la parte superior, y empujando el resultado hacia abajo en la pila.
así es! la pila tendrá los siguientes valores, porque estamos empujando 4 bytes hacia abajo en la pila, sumando (ADD) los dos más cercanos a la parte superior y empujando el resultado hacia abajo en la pila.
```
00 04 08 <- arriba
@ -101,9 +101,9 @@ ahora, comparemos con lo que ocurre con el ADD2:
en este caso estamos empujando los mismos 4 bytes hacia abajo en la pila, pero ADD2 está haciendo las siguientes acciones:
* toma el elemento superior de la pila (08) y lo almacena como el byte bajo del primer corto
* toma el nuevo elemento superior de la pila (00), y lo almacena como el byte alto del primer corto, que ahora es 0008
* toma el nuevo elemento superior de la pila (04), y lo almacena como el byte bajo del segundo corto
* toma el nuevo elemento superior de la pila (00), y lo almacena como el byte alto del segundo corto, que ahora es 0004
* toma el nuevo elemento superior de la pila (00) y lo almacena como el byte alto del primer corto, que ahora es 0008
* toma el nuevo elemento superior de la pila (04) y lo almacena como el byte bajo del segundo corto
* toma el nuevo elemento superior de la pila (00) y lo almacena como el byte alto del segundo corto, que ahora es 0004
* suma los dos cortos (0004 + 0008), obteniendo un resultado de 000c
* empuja el byte alto del resultado (00) hacia abajo en la pila
* empuja el byte bajo del resultado (0c) hacia abajo en la pila
@ -122,7 +122,7 @@ en cualquier caso, es útil tener en cuenta cómo funcionan para algunos comport
hablemos ahora de la instrucción DEO ("device out" o salida de dispositivo) de la que hablamos el día anterior, ya que su modo corto implica algo especial.
la instrucción DEO necesita un valor (1 byte) para salir, y una dirección entrada/salida (1 byte) en la pila, para poder sacar ese valor en esa dirección.
la instrucción DEO necesita un valor (1 byte) para salir y una dirección entrada/salida (1 byte) en la pila, para poder sacar ese valor en esa dirección.
```
DEO ( valor dirección -- )
@ -130,7 +130,7 @@ DEO ( valor dirección -- )
esta instrucción tiene una contrapartida: DEI ("device in" o entrada de dispositivo).
la instrucción DEI toma una dirección de entrada/salida (1 byte) de la pila, y va a empujar hacia abajo en la pila el valor (1 byte) que corresponde a la lectura de esa entrada.
la instrucción DEI toma una dirección de entrada/salida (1 byte) de la pila y va a empujar hacia abajo en la pila el valor (1 byte) que corresponde a la lectura de esa entrada.
```
DEI ( dirección -- valor )
@ -138,15 +138,15 @@ DEI ( dirección -- valor )
¿qué crees que harán DEO2 y DEI2?
en el caso del modo corto de DEO y DEI, el aspecto corto se aplica al valor de salida o entrada, y no a la dirección.
en el caso del modo corto de DEO y DEI, el aspecto corto se aplica al valor de salida o entrada y no a la dirección.
recuerda que las 256 direcciones de entrada/salida ya están cubiertas usando un solo byte, por lo que usar un corto para ellas sería redundante: el byte alto sería siempre 00.
considerando esto, los siguientes son los comportamientos que podemos esperar:
la instrucción DEO2 necesita un valor (1 corto) para salir, y una dirección entrada/salida (1 byte) en la pila, para poder sacar ese valor a esa dirección. por lo tanto necesita un total de 3 bytes en la pila para operar.
la instrucción DEO2 necesita un valor (1 corto) para salir y una dirección entrada/salida (1 byte) en la pila, para poder sacar ese valor a esa dirección. por lo tanto necesita un total de 3 bytes en la pila para operar.
por otro lado, la instrucción DEI2 necesita una dirección entrada/salida (1 byte) en la pila, y empujará hacia abajo en la pila el valor (1 corto) que corresponde a esa entrada.
por otro lado, la instrucción DEI2 necesita una dirección entrada/salida (1 byte) en la pila y empujará hacia abajo en la pila el valor (1 corto) que corresponde a esa entrada.
en la siguiente sección veremos algunos ejemplos en los que podremos utilizar estas instrucciones.
@ -154,7 +154,7 @@ el puerto de 'escritura' del dispositivo de la consola que utilizamos la última
# dispositivo de sistema y colores
el dispositivo del sistema es el dispositivo varvara con una dirección de 00. sus puertos de salida (que comienzan en la dirección 08) corresponden a tres cortos diferentes: uno llamado rojo (r), el otro verde (g), y el último azul (b).
el dispositivo del sistema es el dispositivo varvara con una dirección de 00. sus puertos de salida (que comienzan en la dirección 08) corresponden a tres cortos diferentes: uno llamado rojo (r), el otro verde (g) y el último azul (b).
en los ejemplos uxntal podemos ver sus etiquetas definidas de la siguiente manera:
@ -162,7 +162,7 @@ en los ejemplos uxntal podemos ver sus etiquetas definidas de la siguiente maner
|00 @Sistema [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
```
ignoraremos los primeros elementos por el momento, y nos centraremos en los componentes de color.
ignoraremos los primeros elementos por el momento y nos centraremos en los componentes de color.
## colores del sistema
@ -205,7 +205,7 @@ prueba cambiar los valores del color 0, es decir, la primera columna, y mira lo
# el dispositivo de pantalla
como recapitulación: mencionamos que el dispositivo de pantalla sólo puede mostrar cuatro colores diferentes en un momento dado, y que estos colores están numerados del 0 al 3. fijamos estos colores usando los puertos correspondientes en el dispositivo del sistema.
como recapitulación: mencionamos que el dispositivo de pantalla sólo puede mostrar cuatro colores diferentes en un momento dado y que estos colores están numerados del 0 al 3. fijamos estos colores usando los puertos correspondientes en el dispositivo del sistema.
¡ahora hablemos del dispositivo de pantalla y empecemos a usarlo!
@ -243,14 +243,14 @@ al principio, la capa del primer plano es completamente transparente: un proceso
la primera y más sencilla forma de dibujar en la pantalla es dibujando un solo píxel.
para hacer esto necesitamos establecer un par de coordenadas x,y donde queremos que se dibuje el pixel, y necesitamos establecer el byte 'pixel' a un valor específico para realizar realmente el dibujo.
para hacer esto necesitamos establecer un par de coordenadas x,y donde queremos que se dibuje el pixel y necesitamos establecer el byte 'pixel' a un valor específico para realizar realmente el dibujo.
## estableciendo las coordenadas
las coordenadas x,y siguen las convenciones comunes a otros programas de gráficos por ordenador:
* x comienza en 0 a la izquierda, y aumenta hacia la derecha de la pantalla
* y comienza en 0 en la parte superior, y aumenta hacia la parte inferior de la pantalla
* x comienza en 0 a la izquierda y aumenta hacia la derecha de la pantalla
* y comienza en 0 en la parte superior y aumenta hacia la parte inferior de la pantalla
si quisiéramos dibujar un píxel en coordenadas ( 8, 8 ), estableceríamos sus coordenadas de esta manera:
@ -259,7 +259,7 @@ si quisiéramos dibujar un píxel en coordenadas ( 8, 8 ), estableceríamos sus
#0008 .Pantalla/y DEO2
```
alternativamente, podríamos empujar primero los valores de las coordenadas hacia abajo en la pila, y la salida de ellos después:
alternativamente, podríamos empujar primero los valores de las coordenadas hacia abajo en la pila y la salida de ellos después:
```
#0008 #0008 .Pantalla/x DEO2 .Pantalla/y DEO2
@ -335,7 +335,7 @@ el programa completo se vería de la siguiente manera:
¡wuju!
recuerda que puedes usar F1 para cambiar de nivel de zoom, y F3 para hacer capturas de pantalla de tus bocetos :)
recuerda que puedes usar F1 para cambiar de nivel de zoom y F3 para hacer capturas de pantalla de tus bocetos :)
## hola píxeles
@ -398,7 +398,7 @@ teniendo en cuenta esto, ¿se puede saber qué haría este código?
¡lo has adivinado bien, espero!
* la primera línea empuja la coordenada x como un corto, hacia abajo en la pila.
* la segunda línea empuja el número 0001, lo añade al corto anterior, y empuja el resultado a la pila.
* la segunda línea empuja el número 0001, lo añade al corto anterior y empuja el resultado a la pila.
* la tercera línea toma el resultado de la pila y lo escribe como la nueva coordenada x.
ese conjunto de instrucciones incrementa la coordenada x de la pantalla por uno :)
@ -481,9 +481,9 @@ agradable, ¿no? ¡las operaciones ahora se ven más claras! y si quisiéramos t
el dispositivo de pantalla varvara nos permite utilizar y dibujar tiles de 8x8 píxeles, también llamados sprites.
hay dos modos posibles: 1bpp (1 bit por píxel), y 2bpp (2 bits por píxel).
hay dos modos posibles: 1bpp (1 bit por píxel) y 2bpp (2 bits por píxel).
los mosaicos o "tiles" de 1bpp usan dos colores, y se codifican usando 8 bytes; usar un bit por píxel significa que sólo podemos codificar si ese píxel está usando un color, o el otro.
los mosaicos o "tiles" de 1bpp usan dos colores y se codifican usando 8 bytes; usar un bit por píxel significa que sólo podemos codificar si ese píxel está usando un color o el otro.
los tiles de 2bpp utilizan cuatro colores y se codifican utilizando 16 bytes; el uso de dos bits por píxel significa que podemos codificar cuál de los cuatro colores disponibles tiene el píxel.
@ -493,13 +493,13 @@ almacenaremos y accederemos a estos tiles desde la memoria principal.
un tile de 1bpp consiste en un conjunto de 8 bytes que codifican el estado de sus 8x8 píxeles.
cada byte corresponde a una fila del tile, y cada bit de una fila corresponde al estado de un píxel de izquierda a derecha: puede estar "encendido" (1) o "apagado" (0).
cada byte corresponde a una fila del tile y cada bit de una fila corresponde al estado de un píxel de izquierda a derecha: puede estar "encendido" (1) o "apagado" (0).
## codificando un sprite de 1bpp
por ejemplo, podríamos diseñar un azulejo que corresponda al contorno de un cuadrado de 8x8, activando o desactivando sus píxeles en consecuencia.
``` el contorno de un cuadrado marcado con 1s, y su interior marcado con 0s
``` el contorno de un cuadrado marcado con 1s y su interior marcado con 0s
11111111
10000001
10000001
@ -512,11 +512,11 @@ por ejemplo, podríamos diseñar un azulejo que corresponda al contorno de un cu
como cada una de las filas es un byte, podemos codificarlas como números hexadecimales en lugar de binarios.
vale la pena notar (o recordar) que los grupos de cuatro bits corresponden a un nibble, y cada combinación posible en un nibble puede ser codificada como un dígito {hexadecimal}.
vale la pena notar (o recordar) que los grupos de cuatro bits corresponden a un nibble y cada combinación posible en un nibble puede ser codificada como un dígito {hexadecimal}.
basándonos en eso, podríamos codificar nuestro cuadrado de la siguiente manera:
``` el contorno de un cuadrado marcado con 1s, y sus interiores marcados con 0s, y su equivalente en hexadecimal
``` el contorno de un cuadrado marcado con 1s y sus interiores marcados con 0s, y su equivalente en hexadecimal
11111111: ff
10000001: 81
10000001: 81
@ -535,13 +535,13 @@ en uxntal, necesitamos etiquetar y escribir en la memoria principal los datos co
@cuadrado ff81 8181 8181 81ff
```
tengamos en cuenta que aquí no estamos utilizando la runa hexadecimal literal (#): queremos utilizar los bytes en bruto en la memoria, y no necesitamos empujarlos hacia abajo en la pila.
tengamos en cuenta que aquí no estamos utilizando la runa hexadecimal literal (#): queremos utilizar los bytes en bruto en la memoria y no necesitamos empujarlos hacia abajo en la pila.
para asegurarse de que estos bytes no son leídos como instrucciones por la cpu uxn, es una buena práctica precederlos con la instrucción BRK: esto interrumpirá la ejecución del programa antes de llegar aquí, dejando a uxn en un estado en el que está esperando entradas.
## configurando la dirección
para dibujar el sprite, necesitamos enviar su dirección en memoria al dispositivo de pantalla, y necesitamos asignar un byte de sprite apropiado.
para dibujar el sprite, necesitamos enviar su dirección en memoria al dispositivo de pantalla y necesitamos asignar un byte de sprite apropiado.
para lograr esto, escribimos lo siguiente:
@ -551,7 +551,7 @@ para lograr esto, escribimos lo siguiente:
una nueva runa está aquí! la runa de dirección absoluta literal (;) nos permite empujar hacia abajo en la pila la dirección absoluta de la etiqueta dada en la memoria principal.
una dirección absoluta tendría 2 bytes de longitud, y se introduce en la pila con LIT2, incluida por el ensamblador cuando se utiliza esta runa.
una dirección absoluta tendría 2 bytes de longitud y se introduce en la pila con LIT2, incluida por el ensamblador cuando se utiliza esta runa.
como la dirección es de 2 bytes, la imprimimos con DEO2.
@ -589,7 +589,7 @@ los ocho valores posibles de este nibble alto, utilizados para dibujar un sprite
si se observa con atención, se puede ver algún patrón: cada bit del nibble alto del byte del sprite corresponde a un aspecto diferente de este comportamiento.
lo siguiente muestra el significado de cada uno de estos bits en el nibble alto, suponiendo que estamos contando los bits del byte de derecha a izquierda, y de 0 a 7:
lo siguiente muestra el significado de cada uno de estos bits en el nibble alto, suponiendo que estamos contando los bits del byte de derecha a izquierda y de 0 a 7:
+ <table>
+ <tr><th>bit 7</th><th>bit 6</th><th>bit 5</th><th>bit 4</th></tr>
@ -771,7 +771,7 @@ un solo tile de 2bpp de 8x8 píxeles necesita 16 bytes para ser codificada. esto
para demostrar esta codificación, vamos a remezclar nuestro cuadrado de 8x8, asignando uno de los cuatro estados posibles (0, 1, 2, 3) a cada uno de los píxeles:
``` un cuadrado de 8x8 construido con los dígitos 0 y 1 en el borde, y 2 y 3 en el interior
``` un cuadrado de 8x8 construido con los dígitos 0 y 1 en el borde y 2 y 3 en el interior
00000001
03333311
03333211
@ -812,7 +812,7 @@ separamos nuestro tile en dos cuadrados diferentes, uno para los bits altos y ot
00000000 11111111
```
ahora podemos pensar en cada uno de estos cuadrados como sprites de 1bpp, y codificarlos en hexadecimal como lo hicimos antes:
ahora podemos pensar en cada uno de estos cuadrados como sprites de 1bpp y codificarlos en hexadecimal como lo hicimos antes:
``` los dos cuadrados 8x8 anteriores con su correspondiente codificación hexadecimal
00000000: 00 00000001: 01
@ -827,7 +827,7 @@ ahora podemos pensar en cada uno de estos cuadrados como sprites de 1bpp, y codi
## almacenando el sprite
para escribir este sprite en la memoria, primero almacenamos el cuadrado correspondiente a los bits bajos, y luego el cuadrado correspondiente a los bits altos. cada uno de ellos, de arriba a abajo:
para escribir este sprite en la memoria, primero almacenamos el cuadrado correspondiente a los bits bajos y luego el cuadrado correspondiente a los bits altos. cada uno de ellos, de arriba a abajo:
```
@nuevo-cuadrado 017f 7b73 6343 7fff 007c 7c7c 7c7c 0000
@ -847,7 +847,7 @@ el dispositivo de pantalla tratará esta dirección como un sprite 2bpp cuando u
### sprite de nibble alto para 2bpp
el nibble alto para los sprites de 2bpp nos permitirá elegir la capa que queremos que se dibuje, y la dirección de rotación.
el nibble alto para los sprites de 2bpp nos permitirá elegir la capa que queremos que se dibuje y la dirección de rotación.
los ocho valores posibles para este nibble son:
@ -990,7 +990,7 @@ nasu es una herramienta de 100R, escrita en uxntal, que facilita el diseño y la
=> https://100r.co/site/nasu.html 100R - nasu
además de usarlo para dibujar con los colores 1, 2, 3 (y borrar para obtener el color 0), puedes usarlo para encontrar los colores de tu sistema, para ver cómo se verán tus sprites con los diferentes modos de color (también conocidos como modos de mezcla), y para ensamblar objetos hechos de múltiples sprites.
además de usarlo para dibujar con los colores 1, 2, 3 (y borrar para obtener el color 0), puedes usarlo para encontrar los colores de tu sistema, para ver cómo se verán tus sprites con los diferentes modos de color (también conocidos como modos de mezcla) y para ensamblar objetos hechos de múltiples sprites.
puedes exportar e importar archivos chr, que puedes incluir en tu código usando una herramienta como hexdump.
@ -998,13 +998,13 @@ puedes exportar e importar archivos chr, que puedes incluir en tu código usando
# tamaño de la pantalla y capacidad de respuesta
lo último que cubriremos hoy tiene que ver con las suposiciones que hace varvara sobre el tamaño de su pantalla, y algunas estrategias de código que podemos usar para lidiar con ellas.
lo último que cubriremos hoy tiene que ver con las suposiciones que hace varvara sobre el tamaño de su pantalla y algunas estrategias de código que podemos usar para lidiar con ellas.
en resumen, ¡no hay un tamaño de pantalla estándar!
por defecto, la pantalla del emulador varvara tiene un tamaño de 512x320 píxeles (o 64x40 tiles).
sin embargo, y a modo de ejemplo, el ordenador virtual también funciona en la nintendo ds, con una resolución de 256x192 píxeles (32x24 tiles), y en el teletipo con una resolución de 128x64 píxeles (16x8 tiles)
sin embargo, y a modo de ejemplo, el ordenador virtual también funciona en la nintendo ds, con una resolución de 256x192 píxeles (32x24 tiles), y en el teletipo, con una resolución de 128x64 píxeles (16x8 tiles)
como programadorxs, se espera que decidamos qué hacer con ellos: nuestros programas pueden adaptarse a los distintos tamaños de pantalla, pueden tener distintos modos según el tamaño de la pantalla, etc.
@ -1054,7 +1054,7 @@ y = altopantalla/2
para esto, vamos a introducir las instrucciones MUL y DIV: funcionan como ADD y SUB, pero para la multiplicación y la división:
* MUL: toma los dos elementos superiores de la pila, los multiplica y empuja el resultado ( a b -- a*b )
* DIV: toma los dos elementos superiores de la pila, los divide, y empuja el resultado ( a b -- a/b )
* DIV: toma los dos elementos superiores de la pila, los divide y empuja el resultado ( a b -- a/b )
usando DIV, nuestra expresión traducida para el caso de la coordenada x, podría verse como:
@ -1068,9 +1068,9 @@ usando DIV, nuestra expresión traducida para el caso de la coordenada x, podrí
si lo que queremos es dividir por encima o multiplicar por potencias de dos (como en este caso), también podemos utilizar la instrucción SFT.
esta instrucción toma un número y un "valor de desplazamiento" que indica la cantidad de posiciones de bit a desplazar a la derecha, y/o a la izquierda.
esta instrucción toma un número y un "valor de desplazamiento" que indica la cantidad de posiciones de bit a desplazar a la derecha y/o a la izquierda.
el nibble inferior del valor de desplazamiento indica a uxn cuántas posiciones hay que desplazar a la derecha, y el nibble superior expresa cuántos bits hay que desplazar a la izquierda.
el nibble inferior del valor de desplazamiento indica a uxn cuántas posiciones hay que desplazar a la derecha y el nibble superior expresa cuántos bits hay que desplazar a la izquierda.
para dividir un número por encima de 2, tendríamos que desplazar sus bits un espacio a la derecha.
@ -1080,7 +1080,7 @@ por ejemplo, dividir 10 (en decimal) entre 2 podría expresarse de la siguiente
#0a #01 SFT ( resultado: 05 )
```
0a es 0000 1010 en binario, y 05 es 0000 0101 en binario: los bits de 0a se desplazaron una posición a la derecha, y se introdujo un cero como bit más a la izquierda.
0a es 0000 1010 en binario y 05 es 0000 0101 en binario: los bits de 0a se desplazaron una posición a la derecha y se introdujo un cero como bit más a la izquierda.
para multiplicar por 2, desplazamos un espacio a la izquierda:
@ -1088,7 +1088,7 @@ para multiplicar por 2, desplazamos un espacio a la izquierda:
#0a #10 SFT ( resultado: 14 en hexadecimal )
```
14 en hexadecimal (20 en decimal), es 0001 0100 en binario: los bits de 0a fueron desplazados una posición a la izquierda, y un cero fue introducido como el bit más a la derecha.
14 en hexadecimal (20 en decimal), es 0001 0100 en binario: los bits de 0a fueron desplazados una posición a la izquierda y un cero fue introducido como el bit más a la derecha.
en modo corto, el número a desplazar es un corto, pero el valor de desplazamiento sigue siendo un byte.
@ -1144,16 +1144,16 @@ además de cubrir los fundamentos del dispositivo de pantalla hoy, discutimos es
* INC: incrementa el valor en la parte superior de la pila ( a -- a+1 )
* BRK: rompe el flujo del programa, para cerrar subrutinas
* MUL: toma los dos primeros elementos de la pila, los multiplica y empuja el resultado ( a b -- a*b )
* DIV: toma los dos primeros elementos de la pila, los divide, y empuja el resultado ( a b -- a/b )
* SFT: toma un valor de desplazamiento y un número a desplazar con ese valor, y lo desplaza. el nibble inferior del valor de desplazamiento indica el desplazamiento a la derecha, y el nibble superior el desplazamiento a la izquierda ( número desplazo -- númerodesplazado )
* DIV: toma los dos primeros elementos de la pila, los divide y empuja el resultado ( a b -- a/b )
* SFT: toma un valor de desplazamiento y un número a desplazar con ese valor y lo desplaza. el nibble inferior del valor de desplazamiento indica el desplazamiento a la derecha y el nibble superior el desplazamiento a la izquierda ( número desplazo -- númerodesplazado )
también cubrimos el modo corto, que le indica a la cpu que debe operar con palabras de 2 bytes de longitud.
# día 3
¡en el {tutorial de uxn día 3} empezamos a trabajar con la interactividad usando el teclado, y cubrimos en profundidad varias instrucciones uxntales!
¡en el {tutorial de uxn día 3} empezamos a trabajar con la interactividad usando el teclado y cubrimos en profundidad varias instrucciones uxntales!
sin embargo, te invito a que te tomes un descanso, y a que sigas explorando el dibujo en la pantalla de uxn a través del código antes de continuar!
sin embargo, te invito a que te tomes un descanso y a que sigas explorando el dibujo en la pantalla de uxn a través del código antes de continuar!
# apoyo

View File

@ -2,7 +2,7 @@
¡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.
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.
@ -22,7 +22,7 @@ el byte de botón codifica en cada uno de sus ocho bits el estado de ocho "boton
=> 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
numerando los bits de derecha a izquierda y de 0 a 7, las teclas correspondientes (y los botones de NES) son
+ <table>
+ <tr><th>bit 7</th><th>bit 6</th><th>bit 5</th><th>bit 4</th><th>bit 3</th><th>bit 2</th><th>bit 1</th><th>bit 0</th></tr>
@ -65,9 +65,9 @@ la siguiente línea de código asignaría ese vector, utilizando la dirección 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.
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?
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!
@ -79,7 +79,7 @@ cada una de estas subrutinas terminará con la instrucción BRK, para que puedan
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 sólo cuando se pulsa una tecla. al principio, la pantalla está vacía, y cuando pulsamos una tecla se dibuja un cuadrado:
este utiliza el procedimiento de dibujo de sprites que probamos el día anterior, pero hace que ocurra sólo cuando se pulsa una tecla. al principio, la pantalla está vacía, y cuando pulsamos una tecla, se dibuja un cuadrado:
```
( hola-teclado.tal )
@ -137,9 +137,9 @@ uxntal tiene cuatro instrucciones para comparar los dos primeros elementos de la
* 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>b )
podemos pensar en los resultados empujados por estas instrucciones como banderas booleanas: son 01 si la comparación fue verdadera, y son 00 si fue falsa.
podemos pensar en los resultados empujados por estas instrucciones como banderas booleanas: son 01 si la comparación fue verdadera y son 00 si fue falsa.
el siguiente código leerá el valor de la tecla del controlador, y empujará a la pila una bandera correspondiente a que sea igual al carácter 'a':
el siguiente código leerá el valor de la tecla del controlador y empujará a la pila una bandera correspondiente a que sea igual al carácter 'a':
```
.Controlador/tecla DEI ( lee la tecla y la empuja hacia abajo en la pila )
@ -155,22 +155,22 @@ uxntal tiene tres instrucciones lógicas a nivel de bit.
pueden funcionar como operadores lógicos que utilizan como operandos las banderas dadas por las instrucciones de comparación que hemos comentado anteriormente:
* AND: realiza un AND a nivel de bits con los dos elementos superiores de la pila, y empuja el resultado ( a b -- a&b )
* ORA: realiza un OR a nivel de bits con los dos primeros elementos de la pila, y empuja el resultado ( a b -- a|b )
* EOR: realiza un OR exclusivo a nivel de bits con los dos primeros elementos de la pila, y empuja hacia abajo el resultado ( a b -- a^b )
* AND: realiza un AND a nivel de bits con los dos elementos superiores de la pila y empuja el resultado ( a b -- a&b )
* ORA: realiza un OR a nivel de bits con los dos primeros elementos de la pila y empuja el resultado ( a b -- a|b )
* EOR: realiza un OR exclusivo a nivel de bits con los dos primeros elementos de la pila y empuja hacia abajo el resultado ( a b -- a^b )
AND2, ORA2, EOR2 funcionarán de la misma manera, pero con cortos en lugar de bytes.
### AND
lo siguiente empujará hacia abajo en la pila una bandera que indica si el byte tecla está entre 30 y 39 inclusive, usando 01 para representar 'verdadero', y 00 para representar 'falso':
lo siguiente empujará hacia abajo en la pila una bandera que indica si el byte tecla está entre 30 y 39 inclusive, usando 01 para representar 'verdadero' y 00 para representar 'falso':
```
.Controlador/tecla DEI ( lee la tecla y la introduce en la pila )
#2f GTH ( ¿es mayor que 2f? empuja la bandera a la pila )
Controlador/tecla DEI ( lee la tecla y la introduce en la pila )
#3a LTH ( ¿es menor que 3a? empuja la bandera a la pila )
AND ( aplica un AND a las banderas de la pila, y empuja el resultado a la pila )
AND ( aplica un AND a las banderas de la pila y empuja el resultado a la pila )
```
que la instrucción sea a nivel de bit (o "bitwise") significa que aplica la operación AND a cada uno de los bits de los operandos.
@ -204,7 +204,7 @@ el siguiente código empujará una bandera hacia abajo en la pila si el byte tec
LIT '1 EQU ( ¿es '1'? empuja la bandera a la pila )
.Controlador/tecla DEI ( lee la tecla y empujar a la pila )
LIT 'a EQU ( ¿es 'a'? empuja la bandera a la pila )
ORA ( aplica un OR a las banderas en la pila, y empuja el resultado en la pila )
ORA ( aplica un OR a las banderas en la pila y empuja el resultado en la pila )
```
cuando alguna o ambas banderas son verdaderas, la bandera será verdadera:
@ -224,7 +224,7 @@ un "exclusive-OR", o también "o-exclusivo", es una operación lógica que tiene
basándose en este comportamiento, esta instrucción puede utilizarse para invertir el valor de una bandera utilizando un valor especial en el que el/los bit(s) que queremos invertir se pongan a 1. este tipo de valores se llaman máscaras.
por ejemplo, el siguiente código empujará una bandera correspondiente a que la te sea mayor o igual a 20, calculando primero si es menor que 20, y luego invirtiendo el resultado:
por ejemplo, el siguiente código empujará una bandera correspondiente a que la te sea mayor o igual a 20, calculando primero si es menor que 20 y luego invirtiendo el resultado:
```
.Controlador/tecla DEI ( lee la tecla y la empuja a la pila )
@ -252,7 +252,7 @@ EOR 0000 0001 ( máscara )
0000 0001 ( verdadero )
```
observe que la máscara es la misma, y el resultado es el valor opuesto de la bandera.
observe que la máscara es la misma y el resultado es el valor opuesto de la bandera.
# flujo de control: saltos condicionales
@ -277,7 +277,7 @@ en modo corto, las direcciones que toman estas instrucciones son absolutas (es d
hay varias runas que se refieren a direcciones y etiquetas. uxnasm las lee y las convierte a los valores binarios correspondientes.
en los días anteriores ya hablamos de algunas de ellas; esta es una recapitulación de las mismas, y una introducción de las nuevas:
en los días anteriores ya hablamos de algunas de ellas; esta es una recapitulación de las mismas y una introducción de las nuevas:
* dirección literal en la página cero: .etiqueta (un byte)
* dirección literal en memoria principal: ;label (un corto)
@ -418,10 +418,10 @@ discutimos anteriormente este segmento de código, que empuja una bandera que re
#2f GTH ( ¿es mayor que 2f? empuja la bandera a la pila )
Controlador/tecla DEI ( lee la tecla y la introduce en la pila )
#3a LTH ( ¿es menor que 3a? empuja la bandera a la pila )
AND ( aplica un AND a las banderas en la pila, y empuja el resultado en la pila )
AND ( aplica un AND a las banderas en la pila y empuja el resultado en la pila )
```
en lugar de leer la tecla dos veces, podríamos hacerlo una vez, y luego usar la instrucción DUP para copiar el valor:
en lugar de leer la tecla dos veces, podríamos hacerlo una vez y luego usar la instrucción DUP para copiar el valor:
```
.Controlador/tecla DEI DUP ( leer y duplicar la tecla )
@ -463,7 +463,7 @@ finalmente podemos proceder a la comparación y al AND:
```
#3a LTH ( ¿es menor que 3a? empuja la bandera en la pila )
AND ( aplica un AND a las banderas en la pila, y empuja el resultado en la pila )
AND ( aplica un AND a las banderas en la pila y empuja el resultado en la pila )
```
terminando con una pila que sólo tiene el resultado:
@ -479,10 +479,10 @@ el código completo se leería como:
#2f GTH ( ¿es mayor que 2f? empuja la bandera a la pila )
SWP ( poner la tecla en la parte superior )
#3a LTH ( ¿es menor que 3a? empuja la bandera a la pila )
AND ( aplica un AND a las banderas en la pila, y empuja el resultado en la pila )
AND ( aplica un AND a las banderas en la pila y empuja el resultado en la pila )
```
el primer código se ensambla en 13 bytes, y éste se ensambla en 12 bytes. quizá no haya demasiada diferencia en ese aspecto.
el primer código se ensambla en 13 bytes y éste se ensambla en 12 bytes. quizá no haya demasiada diferencia en ese aspecto.
sin embargo, una ventaja más significativa es que esta nueva rutina ahora necesita su entrada empujada hacia abajo en la pila sólo al principio.
@ -580,13 +580,13 @@ en nuestra máscara AND, estableceremos como 1 los bits en las posiciones en las
por ejemplo, digamos que queremos ver si el bit número 4, que corresponde al botón Arriba, está encendido o apagado, independientemente del estado de los otros botones.
nuestra máscara AND tendrá un 1 en el bit número 4 (de derecha a izquierda, y empezando por el 0), y 0 en el resto:
nuestra máscara AND tendrá un 1 en el bit número 4 (de derecha a izquierda y empezando por el 0) y 0 en el resto:
```
0001 000: 10
```
¿qué pasaría si se pulsa el botón A (tecla Ctrl), con su estado codificado en el bit 0, y nada más?
¿qué pasaría si se pulsa el botón A (tecla Ctrl), con su estado codificado en el bit 0 y nada más?
```
0000 0001 ( botón )
@ -627,7 +627,7 @@ aplicar esta máscara sería tan sencillo como escribir:
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.
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.
@ -704,7 +704,7 @@ BRK
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:
* 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
@ -720,7 +720,7 @@ recuerde que .Pantalla/x es una dirección literal en la página cero, es decir,
* 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.
* 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!
@ -739,14 +739,14 @@ recuerde que .Pantalla/x es una dirección literal en la página cero, es decir,
## lógica a nivel de bits
* AND: realiza un AND a nivel de bits con los dos primeros elementos de la pila, y empuja hacia abajo el resultado ( a b -- a&b )
* ORA: realiza un OR a nivel de bits con los dos primeros elementos de la pila, y empuja el resultado ( a b -- a|b )
* EOR: realiza un OR exclusivo a nivel de bits con los dos primeros elementos de la pila, y empuja hacia abajo el resultado ( a b -- a^b )
* AND: realiza un AND a nivel de bits con los dos primeros elementos de la pila y empuja hacia abajo el resultado ( a b -- a&b )
* ORA: realiza un OR a nivel de bits con los dos primeros elementos de la pila y empuja el resultado ( a b -- a|b )
* EOR: realiza un OR exclusivo a nivel de bits con los dos primeros elementos de la pila y empuja hacia abajo el resultado ( a b -- a^b )
## saltos
* JMP: salto incondicional a la dirección de la pila ( direc -- )
* JCN: salto condicional: toma una dirección y un valor de la pila, y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )
* JCN: salto condicional: toma una dirección y un valor de la pila y si el valor no es 00, salta a la dirección; en caso contrario continúa con la siguiente instrucción ( valor direc -- )
## pila

View File

@ -4,7 +4,7 @@
aquí hablamos del bucle de animación del ordenador varvara, a través de su vector de dispositivo de pantalla.
también hablamos del uso de la memoria del programa como un espacio para datos usando "variables". esto nos permite guardar y recuperar datos durante el tiempo de ejecución de nuestros programas, y puede ahorrarnos manejos complejos en la pila :)
también hablamos del uso de la memoria del programa como un espacio para datos usando "variables". esto nos permite guardar y recuperar datos durante el tiempo de ejecución de nuestros programas y puede ahorrarnos manejos complejos en la pila :)
# el vector pantalla
@ -28,7 +28,7 @@ uxn saltará a la ubicación de la etiqueta a una frecuencia de 60 veces por seg
## una línea que crece
el siguiente programa demuestra un uso básico pero potente del vector pantalla: en cada fotograma, dibuja un píxel en las coordenadas x,y de la pantalla dadas, y añade 1 al valor de la coordenada x:
el siguiente programa demuestra un uso básico pero potente del vector pantalla: en cada fotograma, dibuja un píxel en las coordenadas x,y de la pantalla dadas y añade 1 al valor de la coordenada x:
```
( hola-linea.tal )
@ -136,11 +136,11 @@ aquí están las dos instrucciones que nos ayudarían:
como ya hemos comentado, una dirección absoluta siempre tendrá una longitud de dos bytes.
en el modo corto, LDA2 cargará un corto desde la dirección dada, y STA2 almacenará un corto en la dirección dada.
en el modo corto, LDA2 cargará un corto desde la dirección dada y STA2 almacenará un corto en la dirección dada.
### ejemplos
como ejemplo, el siguiente código leería los dos bytes de pixel/x, los incrementaría en uno, y los almacenaría de nuevo en pixel/x:
como ejemplo, el siguiente código leería los dos bytes de pixel/x, los incrementaría en uno y los almacenaría de nuevo en pixel/x:
```
;pixel/x LDA2 ( cargar pixel/x en la pila )
@ -168,7 +168,7 @@ BRK
@pixel [ &x $2 &y $2 ]
```
nótese que podríamos haber conseguido el mismo resultado almacenando el resultado, y luego recargándolo y enviándolo como salida.
nótese que podríamos haber conseguido el mismo resultado almacenando el resultado y luego recargándolo y enviándolo como salida.
aquí podemos ver cómo un DUP2 puede facilitar esa operación, siempre y cuando mantengamos un modelo mental (¡o tangible!) de lo que ocurre en la pila.
@ -216,7 +216,7 @@ las instrucciones para cargar (leer) y almacenar (escribir) desde y hacia la pá
en estas instrucciones, la dirección siempre será de un byte.
en el modo corto, LDZ2 cargará un corto desde la dirección dada, y STZ2 almacenará un corto en la dirección dada.
en el modo corto, LDZ2 cargará un corto desde la dirección dada y STZ2 almacenará un corto en la dirección dada.
### ejemplos
@ -303,7 +303,7 @@ las instrucciones para trabajar de esta manera son:
similar a LDZ y STZ, en estas instrucciones la dirección siempre será de un byte.
en el modo corto, LDR2 cargará un corto desde la dirección dada, y STR2 almacenará un corto en la dirección dada.
en el modo corto, LDR2 cargará un corto desde la dirección dada y STR2 almacenará un corto en la dirección dada.
### ejemplos
@ -361,7 +361,7 @@ el uso de "variables" nos ayudará ahora a discutir tres formas diferentes de an
los revisaremos por separado para mantener los ejemplos relativamente simples y legibles.
tenga en cuenta que estos ejemplos también sirven para discutir más posibilidades de programación uxntal, y pueden llegar a ser un poco abrumadores.
tenga en cuenta que estos ejemplos también sirven para discutir más posibilidades de programación uxntal y pueden llegar a ser un poco abrumadores.
te recomiendo que revises y experimentes con uno a la vez, pacientemente :)
@ -369,7 +369,7 @@ te recomiendo que revises y experimentes con uno a la vez, pacientemente :)
ya discutimos como hacer que uxn cambie la posición de un pixel en la pantalla, dejando un rastro.
cambiar ese programa para dibujar un sprite de 8x8 en su lugar sería relativamente sencillo, y puede que ya lo hayas probado: tendríamos que usar Pantalla/sprite en lugar de Pantalla/pixel, con un byte apropiado para definir su color y orientación, y tendríamos que establecer la dirección de los datos de nuestro sprite en Pantalla/direc.
cambiar ese programa para dibujar un sprite de 8x8 en su lugar sería relativamente sencillo y puede que ya lo hayas probado: tendríamos que usar Pantalla/sprite en lugar de Pantalla/pixel, con un byte apropiado para definir su color y orientación, y tendríamos que establecer la dirección de los datos de nuestro sprite en Pantalla/direc.
eso daría como resultado un sprite que se mueve y que además deja un rastro: ¡te invito a que lo pruebes primero!
@ -383,7 +383,7 @@ una posible forma de conseguirlo sería siguiendo este orden de operaciones dent
* cambiar de posición
* dibujar nuevo sprite
esto nos permite borrar el sprite de su posición en el fotograma anterior, actualizar sus coordenadas a una nueva posición, y luego dibujarlo ahí.
esto nos permite borrar el sprite de su posición en el fotograma anterior, actualizar sus coordenadas a una nueva posición y luego dibujarlo ahí.
### código de ejemplo
@ -447,7 +447,7 @@ BRK
nítido, ¿no? :)
como esto es sólo un ejemplo para ilustrar un punto, hay algunas cosas que podrían ser optimizadas para hacer nuestro programa más pequeño, y hay algunas cosas que podrían ser útiles pero fueron omitidas. por ejemplo, no hay un valor inicial para la coordenada x, o la coordenada `y` no se utiliza.
como esto es sólo un ejemplo para ilustrar un punto, hay algunas cosas que podrían ser optimizadas para hacer nuestro programa más pequeño y hay algunas cosas que podrían ser útiles pero fueron omitidas. por ejemplo, no hay un valor inicial para la coordenada x, o la coordenada `y` no se utiliza.
### posibilidades adicionales
@ -488,7 +488,7 @@ el siguiente programa nos permite controlar la posición horizontal de nuestro c
=> ./img/screencap_uxn-moving-square.gif animación que muestra un cuadrado moviéndose horizontalmente en la pantalla, aparentemente controlado por un humano.
¡nótese las similitudes entre el programa anterior, y lo que cubrimos en el {tutorial de uxn día 3}!
¡nótese las similitudes entre el programa anterior y lo que cubrimos en el {tutorial de uxn día 3}!
```
( hola-sprite-en-movimiento.tal )
@ -597,7 +597,7 @@ EQU2 ( ¿es x igual a la anchura de la pantalla - 8? )
### módulo
otra posibilidad podría ser aplicar una operación de módulo a nuestras coordenadas cambiadas para que siempre se mantengan dentro de los límites, volviendo a la izquierda cuando se cruce con la derecha, y viceversa.
otra posibilidad podría ser aplicar una operación de módulo a nuestras coordenadas cambiadas para que siempre se mantengan dentro de los límites, volviendo a la izquierda cuando se cruce con la derecha y viceversa.
un posible conjunto de macros de módulo podría ser:
@ -655,7 +655,7 @@ para tener una animación compuesta por esos fotogramas necesitamos cambiar la d
una forma de conseguirlo es teniendo una "variable global" en la página cero que cuente los fotogramas del programa. además, tendríamos que tener ese conteo acotado en un rango correspondiente a la cantidad de fotogramas de nuestra animación.
¡ya sabemos cómo hacer la primera parte, y más o menos sabemos cómo hacer la segunda!
¡ya sabemos cómo hacer la primera parte y más o menos sabemos cómo hacer la segunda!
### cargar, incrementar y almacenar la cuenta de fotogramas
@ -686,13 +686,13 @@ cuando tenemos un número de fotogramas que corresponde a una potencia de dos, c
por ejemplo, si tenemos 8 fotogramas numerados del 0 al 7, podemos observar que esos números sólo requieren tres bits para ser representados.
para construir nuestra máscara AND, ponemos como 1 esos tres bits, y 0 los demás:
para construir nuestra máscara AND, ponemos como 1 esos tres bits y 0 los demás:
```
0000 0111: 07
```
esta máscara AND "dejará pasar" los tres bits menos significativos de otro byte, y desactivará los demás.
esta máscara AND "dejará pasar" los tres bits menos significativos de otro byte y desactivará los demás.
en uxntal este proceso se vería de la siguiente manera:
@ -731,7 +731,7 @@ o, otra forma de verlo:
generalizando, ¡el fotogramaN esta (N veces 8) bytes después de la etiqueta de animación!
esto significa que si obtenemos la dirección absoluta de la etiqueta de animación, y le añadimos (N veces 8) bytes, obtendremos la dirección absoluta del fotogramaN :)
esto significa que si obtenemos la dirección absoluta de la etiqueta de animación y le añadimos (N veces 8) bytes, obtendremos la dirección absoluta del fotogramaN :)
la cantidad de bytes que separa cada subetiqueta se llama "offset" o desfase.
@ -747,7 +747,7 @@ después de aplicar el módulo 8 a nuestro cuentafotogramas podemos multiplicarl
### de byte a corto
nota que hasta ahora hemos estado trabajando con bytes, y todo ha ido bien.
nota que hasta ahora hemos estado trabajando con bytes y todo ha ido bien.
sin embargo, ¡las direcciones absolutas son cortos!
@ -927,7 +927,7 @@ ah, ¡mucho mejor!
ten en cuenta que si quieres dividir la frecuencia a números que no son potencias de 2, podrías empezar a ver algunas fallas ("glitches") aproximadamente cada 4 segundos: esto se debe a que el cuentafotograma se sobrepasa y no da una buena secuencia de resultados para esos divisores.
esto también puede ocurrir si tienes una animación que consta de un número de fotogramas que no es una potencia de 2, y utilizas una operación MOD normal para calcular el desfase al fotograma correspondiente.
esto también puede ocurrir si tienes una animación que consta de un número de fotogramas que no es una potencia de 2 y utilizas una operación MOD normal para calcular el desfase al fotograma correspondiente.
la solución más sencilla para estos problemas sería utilizar un número de fotogramas de pequeño tamaño que sólo causara esos fallos de sobreflujo aproximadamente cada 18 minutos.
@ -950,7 +950,7 @@ en modo corto, estas instrucciones cargan o almacenan cortos desde o hacia la me
# día 5
en el {tutorial de uxn día 5} introducimos el dispositivo de ratón varvara para explorar más interacciones posibles, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
en el {tutorial de uxn día 5} introducimos el dispositivo de ratón varvara para explorar más interacciones posibles y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
¡también discutimos posibles estructuras para crear bucles y programas más complejos utilizando estos recursos!

View File

@ -1,6 +1,6 @@
# tutorial de uxn: día 5, el ratón y chucherías de uxntal
esta es la quinta sección del {tutorial de uxn}! aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones, y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
esta es la quinta sección del {tutorial de uxn}! aquí introducimos el dispositivo de ratón varvara para explorar más posibles interacciones y cubrimos los elementos restantes de uxntal y uxn: la pila de retorno, el modo de retorno y el modo mantener.
¡también discutimos posibles estructuras para crear bucles y programas más complejos utilizando estos recursos!
@ -44,7 +44,7 @@ recuerda que podemos utilizar las máscaras AND, tal y como se introdujo en el {
el dispositivo del ratón tiene un par de cortos para indicar si el ratón se está desplazando.
despy indicará un desplazamiento vertical con un valor "positivo" cuando se mueve hacia arriba (o en realidad, "lejos del usuario"), y un valor "negativo" cuando se mueve hacia abajo (o "hacia el usuario")
despy indicará un desplazamiento vertical con un valor "positivo" cuando se mueve hacia arriba (o en realidad, "lejos del usuario") y un valor "negativo" cuando se mueve hacia abajo (o "hacia el usuario")
* 0001 cuando se desplaza hacia arriba
* ffff cuando se desplaza hacia abajo
@ -201,7 +201,7 @@ BRK
@puntero_icn [ 80c0 e0f0 f8e0 1000 ]
```
nótese que dibuja el puntero en primer plano, y que utiliza 'a' en el nibble bajo del byte del sprite: esto implica que utilizará el color 2 para dibujar la forma del puntero, y dibujará con transparencia el resto del tile. ( ver dibujar sprites de 1bpp en el {tutorial de uxn día 2} )
nótese que dibuja el puntero en primer plano y que utiliza 'a' en el nibble bajo del byte del sprite: esto implica que utilizará el color 2 para dibujar la forma del puntero y dibujará con transparencia el resto del tile. ( ver dibujar sprites de 1bpp en el {tutorial de uxn día 2} )
este modo de mezcla te permitiría dibujar cosas en el plano de fondo y que el puntero las cubra sólo con su forma, y no con todo el cuadrado del tile.
@ -213,7 +213,7 @@ este modo de mezcla te permitiría dibujar cosas en el plano de fondo y que el p
ahora, podemos ver que el programa funciona, pero está inundando la subrutina en-raton con mucho código.
eso es aun mas cierto si consideramos que solo estamos dibujando el puntero, y no tomando ninguna otra acción, como responder a los botones.
eso es aun mas cierto si consideramos que solo estamos dibujando el puntero y no tomando ninguna otra acción, como responder a los botones.
crear una macro para todo este código podría ser posible, pero también poco práctico debido a la cantidad de código.
@ -365,7 +365,7 @@ como cada uno de los modos es un bit independiente, es posible combinarlos, por
## un breve ejemplo de pila de retorno
por ejemplo, el siguiente código empujaría dos números hacia abajo en la pila de retorno, los sumaría, y empujaría el resultado de nuevo en la pila de retorno:
por ejemplo, el siguiente código empujaría dos números hacia abajo en la pila de retorno, los sumaría y empujaría el resultado de nuevo en la pila de retorno:
```
LITr 01 LITr 02 ADDr
@ -596,7 +596,7 @@ el modo mantener puede combinarse con los otros modos, para un total de ocho com
## modo mantener en aritmética
sabemos lo que hace el siguiente código uxntal; empuja 01 y 02 hacia abajo en la pila, suma ambos elementos, y empuja el resultado (03) hacia abajo en la pila:
sabemos lo que hace el siguiente código uxntal; empuja 01 y 02 hacia abajo en la pila, suma ambos elementos y empuja el resultado (03) hacia abajo en la pila:
```
#01 #02 ( pt: 01 02 )
@ -623,7 +623,7 @@ en realidad, si recuerdas, en el {tutorial de uxn día 4} compartí contigo un p
%MOD2 { OVR2 OVR2 DIV2 MUL2 SUB2 } ( a b -- a%b )
```
dije entonces que había un conjunto más optimizado, y que lo discutiríamos más adelante.
dije entonces que había un conjunto más optimizado y que lo discutiríamos más adelante.
¡ahora es ese momento!
@ -651,7 +651,7 @@ SUB ( pt: 01 )
¿ves la posibilidad de introducir el modo mantener?
si te fijas bien, verás que el DUP2 está ahí para no perder los valores originales en la división, y así poder realizar la multiplicación y la resta después.
si te fijas bien, verás que el DUP2 está ahí para no perder los valores originales en la división y así poder realizar la multiplicación y la resta después.
pero entonces, ¿cómo podemos realizar la división sin perder sus operandos y sin usar DUP2?
@ -668,7 +668,7 @@ SUB ( pt: 01 )
¡de esta manera, nuestra macro puede tener un byte menos!
podemos generalizar este comportamiento para el modo corto, y obtener el conjunto óptimo de macros que mencioné anteriormente:
podemos generalizar este comportamiento para el modo corto y obtener el conjunto óptimo de macros que mencioné anteriormente:
```
%MOD { DIVk MUL SUB }
@ -682,7 +682,7 @@ el modo mantener puede ser útil cuando hacemos comparaciones y no queremos perd
por ejemplo, en nuestra subrutina dibuja-línea-horizontal, teníamos el siguiente conjunto de líneas de código:
```
( duplicar longitud y el conteo, comparar, y saltar )
( duplicar longitud y el conteo, comparar y saltar )
DUP2 ( pt: longitud conteo longitud conteo / pr: )
NEQ ( pt: longitud conteo bandera / pr: )
,&bucle JCN ( pt: longitud conteo / pr: )
@ -693,7 +693,7 @@ verás que aquí, como en el caso DIVk anterior, el DUP2 está ahí sólo para a
por lo tanto, podríamos reemplazar DUP2 NEQ con NEQk:
```
( duplicar la longitud y el conteo, comparar, y saltar )
( duplicar la longitud y el conteo, comparar y saltar )
NEQk ( pt: longitud conteo bandera / pr: )
,&bucle JCN ( pt: longitud conteo / pr: )
```
@ -734,7 +734,7 @@ con lo que ya hemos cubierto, y en caso de que quieras algunas ideas, aquí hay
## sprites de varios tiles
dibujar un sprite formado por varios tiles es un proceso que puede beneficiarse del uso de subrutinas: ten una subrutina que reciba un par de coordenadas x,y en la pila de trabajo cuando sea llamada, y úsala para dibujar los tiles en las posiciones correspondientes relativas a esas coordenadas.
dibujar un sprite formado por varios tiles es un proceso que puede beneficiarse del uso de subrutinas: ten una subrutina que reciba un par de coordenadas x,y en la pila de trabajo cuando sea llamada y úsala para dibujar los tiles en las posiciones correspondientes relativas a esas coordenadas.
## herramienta de dibujo
@ -742,7 +742,7 @@ dibujar un sprite formado por varios tiles es un proceso que puede beneficiarse
tal vez comienza con dibujar sólo cuando se presiona un botón. cambia el color y/o el "pincel" dependiendo del botón que se presiona.
puedes tener diferentes "modos" seleccionables: tal vez cambien el pincel que estás usando, la forma en que el pincel se comporta (por ejemplo, ¿en espejo, caleidoscopio?), y/o las formas que se dibujan.
puedes tener diferentes "modos" seleccionables: tal vez cambien el pincel que estás usando, la forma en que el pincel se comporta (por ejemplo, ¿en espejo, caleidoscopio?) y/o las formas que se dibujan.
considera cómo seleccionarías esos modos: ¿botones en pantalla? ¿teclas del teclado? ¿acordes con los botones del ratón?
@ -775,7 +775,7 @@ en el {tutorial de uxn día 6} hablamos de cómo podemos integrar todo lo que he
¡basamos nuestra discusión en una recreación del clásico juego pong!
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar los sprites de varios tiles, y para comprobar las colisiones.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar los sprites de varios tiles y para comprobar las colisiones.
primero, te invito a tomar un descanso!

View File

@ -4,7 +4,7 @@ esta es la sexta sección del {tutorial de uxn}! aquí hablamos de cómo podemos
basamos nuestra discusión en una recreación del clásico juego pong.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar sprites de varios tiles, y para comprobar las colisiones.
además de utilizar estrategias y fragmentos de código anteriores, cubrimos estrategias para dibujar y controlar sprites de varios tiles y para comprobar las colisiones.
# lógica general
@ -52,7 +52,7 @@ BRK
## repetir un tile en una fila
¿qué procedimiento podríamos seguir para repetir el dibujo de un tile empezando por x, y terminando en un límite correspondiente a x+ancho?
¿qué procedimiento podríamos seguir para repetir el dibujo de un tile empezando por x y terminando en un límite correspondiente a x+ancho?
una forma sería algo así como:
@ -62,7 +62,7 @@ una forma sería algo así como:
### una primera versión
digamos que nuestra x inicial es 0000, nuestro ancho es el ancho de la pantalla, y el tile que estamos dibujando es tile-fondo.
digamos que nuestra x inicial es 0000, nuestro ancho es el ancho de la pantalla y el tile que estamos dibujando es tile-fondo.
el límite del bucle, x+ancho, sería también el ancho de la pantalla.
@ -132,9 +132,9 @@ entremedio, podemos enviar nuestro byte de sprite para dibujar el tile.
#0008 ADD2 ( incrementar x )
```
en este punto, la pila tiene la nueva x en la parte superior de la pila, y el ancho de la pantalla debajo.
en este punto, la pila tiene la nueva x en la parte superior de la pila y el ancho de la pantalla debajo.
podemos compararlos en modo mantener para conservar esos valores en la pila, y hacer nuestro salto como antes:
podemos compararlos en modo mantener para conservar esos valores en la pila y hacer nuestro salto como antes:
```
GTH2k ( ¿es ese ancho mayor que x?, o también, ¿es x menor que el ancho? )
@ -207,7 +207,7 @@ BRK
## repitiendo una fila
similar a lo que acabamos de hacer: ¿cuál es el procedimiento que podríamos seguir para repetir verticalmente una fila empezando por `y`, y terminando en un límite correspondiente a y+altura?
similar a lo que acabamos de hacer: ¿cuál es el procedimiento que podríamos seguir para repetir verticalmente una fila empezando por `y` y terminando en un límite correspondiente a y+altura?
siguiendo la misma estrategia, podríamos hacer:
@ -223,7 +223,7 @@ para ilustrar un pequeño cambio, supongamos que queremos tener un margen en la
%MARGEN-PARED { #0010 } ( margen en la parte superior e inferior )
```
nuestra `y` inicial sería MARGEN-PARED, y nuestro límite sería la altura de la pantalla menos MARGEN-PARED.
nuestra `y` inicial sería MARGEN-PARED y nuestro límite sería la altura de la pantalla menos MARGEN-PARED.
podemos usar la misma estructura que antes, pero usando `y`:
@ -326,11 +326,11 @@ se habla de varias posibilidades para usar uxntal de esa manera abstracta: yo di
# las palas
podemos pensar en las dos palas del juego como dos rectángulos, cada uno con sus propias coordenadas x e `y`, y ambos con la misma anchura y altura.
podemos pensar en las dos palas del juego como dos rectángulos, cada uno con sus propias coordenadas x e `y` y ambos con la misma anchura y altura.
la coordenada x de cada pala puede ser constante, y la coordenada `y` debe ser de seguro una variable.
la coordenada x de cada pala puede ser constante y la coordenada `y` debe ser de seguro una variable.
en esta parte veremos cómo dibujar las palas en base a estos parámetros, y también recapitularemos cómo cambiar sus coordenadas `y` con el controlador.
en esta parte veremos cómo dibujar las palas en base a estos parámetros y también recapitularemos cómo cambiar sus coordenadas `y` con el controlador.
## dibujar las palas multi-tile
@ -384,11 +384,11 @@ pero añadamos también un byte de color para el byte del sprite:
@dibuja-pala ( x^ y^ color -- )
```
recordemos que estamos utilizando la convención de añadir un signo de intercalación (^) después del nombre de un valor para indicar que es un corto, y un asterisco (*) para indicar que es un corto que funciona como un puntero (es decir, una dirección en la memoria del programa)
recordemos que estamos utilizando la convención de añadir un signo de intercalación (^) después del nombre de un valor para indicar que es un corto y un asterisco (*) para indicar que es un corto que funciona como un puntero (es decir, una dirección en la memoria del programa)
por un lado esta segunda versión nos permitiría cambiar de color cuando, por ejemplo, le demos a la pelota, pero lo más importante es que esto nos permitirá borrar la pala antes de moverla, como hemos hecho en días anteriores.
en principio la subrutina debería ser directa: tenemos que establecer las coordenadas x e `y` de cada una de las fichas, relativas a las coordenadas x e `y` dadas, y dibujarlas con el color dado.
en principio la subrutina debería ser directa: tenemos que establecer las coordenadas x e `y` de cada una de las fichas, relativas a las coordenadas x e `y` dadas y dibujarlas con el color dado.
hay muchas maneras de hacerlo, dependiendo del gusto.
@ -404,9 +404,9 @@ podríamos por ejemplo dibujar los tiles en el siguiente orden, con las siguient
o podríamos hacerlo de forma más tradicional:
* dibujar el tile 0, luego añadir 8 a x
* dibujar el tile 1, luego restar 8 a x, y añadir 8 a `y`
* dibujar el tile 1, luego restar 8 a x y añadir 8 a `y`
* dibujar el tile 2, luego añadir 8 a x
* dibujar el tile 3, luego restar 8 a x, y añadir 8 a `y`
* dibujar el tile 3, luego restar 8 a x y añadir 8 a `y`
* dibujar el tile 4, luego añadir 8 a x
* dibujar el tile 5
@ -414,7 +414,7 @@ en lugar de restar podríamos recuperar x de la pila de retorno, o de una variab
una posible ventaja de ir en orden es que podemos incrementar la dirección del sprite por 10 (16 en decimal) para llegar a la dirección del siguiente tile. para esto, y/o para los cambios de coordenadas, podemos aprovechar el byte auto de la pantalla.
sin embargo, en este caso voy a ir por la primera opción, y voy a establecer manualmente la dirección para cada tile.
sin embargo, en este caso voy a ir por la primera opción y voy a establecer manualmente la dirección para cada tile.
adicionalmente, guardaré el color en la pila de retorno:
@ -480,7 +480,7 @@ ahora podemos llamarlo, por ejemplo, de la siguiente manera y obtener nuestra pa
=> ./img/screenshot_uxn-pong-paddle.png captura de pantalla de la pala dibujada sobre el fondo
es posible considerar formas más eficientes de dibujarla. por ejemplo, podríamos tener un dibuja-sprite generalizado que reciba la dirección inicial de un conjunto de tiles, y la anchura y altura en términos de número de tiles:
es posible considerar formas más eficientes de dibujarla. por ejemplo, podríamos tener un dibuja-sprite generalizado que reciba la dirección inicial de un conjunto de tiles y la anchura y altura en términos de número de tiles:
```
@dibuja-sprite ( x^ y^ ancho alto direc* color )
@ -541,7 +541,7 @@ MARGEN SUB2 ANCHO-PALA SUB2
.derecha/x STZ2
```
para centrar las coordenadas `y` podemos restar la altura de la pala a la altura de la pantalla, y luego dividir entre dos:
para centrar las coordenadas `y` podemos restar la altura de la pala a la altura de la pantalla y luego dividir entre dos:
```
.Pantalla/alto DEI2 ALTO-PALA SUB2 MITAD2
@ -562,7 +562,7 @@ para dibujar cada pala, podemos hacer el siguiente procedimiento dentro de nuest
### el programa hasta ahora
omitiendo la definición de las subrutinas dibuja-fondo y dibuja-pala, y como forma de tener un punto de comprobación, ahora mismo nuestro programa tendría el siguiente aspecto:
omitiendo la definición de las subrutinas dibuja-fondo y dibuja-pala y como forma de tener un punto de comprobación, ahora mismo nuestro programa tendría el siguiente aspecto:
=> ./img/screenshot_uxn-pong-paddles.png captura de pantalla de las dos palas, centradas verticalmente y con el mismo margen respecto a los lados
@ -662,7 +662,7 @@ donde COLOR-BORRAR en este caso sería:
para actualizar la posición de nuestras palas, podemos recurrir al ejemplo hola-sprite-en-movimiento.tal del {tutorial de uxn día 4}.
podemos usar las flechas arriba y abajo para cambiar la posición de la pala izquierda, y los botones ctrl y alt (A y B) para cambiar la posición de la pala derecha.
podemos usar las flechas arriba y abajo para cambiar la posición de la pala izquierda y los botones ctrl y alt (A y B) para cambiar la posición de la pala derecha.
podemos tener una macro para definir la velocidad de la pala, es decir, cuánto sumaremos o restaremos al mover cada cuadro:
@ -839,7 +839,7 @@ para dibujarla, sólo tendríamos que hacer:
COLOR-PELOTA ;dibuja-pelota JSR2
```
=> ./img/screenshot_uxn-pong-paddles-and-ball.png captura de la pantalla mostrando las palas en su posición horizontal pero a diferentes alturas, y la pelota completamente centrada en la pantalla.
=> ./img/screenshot_uxn-pong-paddles-and-ball.png captura de la pantalla mostrando las palas en su posición horizontal pero a diferentes alturas y la pelota completamente centrada en la pantalla.
## movimiento de la pelota
@ -849,7 +849,7 @@ para el movimiento de la pelota, seguiremos la misma estructura que antes:
* actualizar su posición
* dibujar la pelota en la nueva posición
se vería algo como lo siguiente, y podría situarse a lo largo de los procedimientos equivalentes para las palas dentro de la subrutina en-cuadro:`
se vería algo como lo siguiente y podría situarse a lo largo de los procedimientos equivalentes para las palas dentro de la subrutina en-cuadro:`
```
( dentro de en-cuadro )
@ -913,7 +913,7 @@ entonces, ¿existe un valor positivo de vel-x que haga que x se reduzca al sumar
sin embargo, aquí estamos limitados por 8 o 16 bits. ¿y qué implica eso?
por ejemplo, si tenemos el número ffff (16 bits, todos son unos), y sumamos 0001, ¿qué obtenemos?
por ejemplo, si tenemos el número ffff (16 bits, todos son unos) y sumamos 0001, ¿qué obtenemos?
```
1111 1111 1111 1111
@ -926,9 +926,9 @@ de acuerdo, es un número mayor, pero el 1 de la izquierda queda fuera de los 16
en uxn, el resultado de sumar ffff y 0001 es 0000: decimos que estamos desbordando los 16 bits.
veámoslo al revés: si tenemos 0001, y sumamos ffff, obtenemos 0000, ¡es decir, 1 menos que 1!
veámoslo al revés: si tenemos 0001 y sumamos ffff, obtenemos 0000, ¡es decir, 1 menos que 1!
si tenemos 0002, y añadimos ffff:
si tenemos 0002 y añadimos ffff:
```
0000 0000 0000 0010
@ -1022,7 +1022,7 @@ hemos definido la forma general de actualizar la posición de la pelota dada su
¡ahora veamos cómo implementar el clásico "rebote"!
primero, empecemos con las paredes en la parte superior e inferior de la pantalla; recordando que hay un margen (MARGEN-PARED) entre el borde real de la pantalla, y las paredes.
primero, empecemos con las paredes en la parte superior e inferior de la pantalla; recordando que hay un margen (MARGEN-PARED) entre el borde real de la pantalla y las paredes.
para realizar estas detecciones de colisión, tendríamos que comprobar sólo la coordenada `y` de la pelota.
@ -1136,7 +1136,7 @@ puedes probarlo usando diferentes velocidades iniciales dentro de la configuraci
## colisiones con las palas
¡trabajemos con lo que acabamos de hacer, y adaptémoslo para rebotar con las palas!
¡trabajemos con lo que acabamos de hacer y adaptémoslo para rebotar con las palas!
### pala izquierda
@ -1219,7 +1219,7 @@ todo el código x-en-izquierda terminaría pareciendo:
&verif-pala-der
```
"fin" sería una etiqueta al final de la subrutina, y "reset" es una subrutina de la cuálf hablaremos más adelante.
"fin" sería una etiqueta al final de la subrutina y "reset" es una subrutina de la cuálf hablaremos más adelante.
esta aproximación de comparar con 0000 es la más fácil, pero ten en cuenta que podría no funcionar si cambias la velocidad de la pelota: podría ocurrir que cruzara la pared pero con una coordenada x que nunca fuera igual a 0.
@ -1231,7 +1231,7 @@ este puede ser otro buen ejercicio para ti: ¿cómo comprobarías si la pelota h
### pala derecha
para la pala derecha haremos lo mismo que arriba, pero cambiando las comparaciones relativas a la coordenada x de la pelota: usaremos el ancho de la pantalla como referencia para la pared derecha, y a partir de ahí le restaremos el margen y el ancho.
para la pala derecha haremos lo mismo que arriba, pero cambiando las comparaciones relativas a la coordenada x de la pelota: usaremos el ancho de la pantalla como referencia para la pared derecha y a partir de ahí le restaremos el margen y el ancho.
```
&verif-pala-der
@ -1292,7 +1292,7 @@ sería interesante tener algún mecanismo para también cambiar la velocidad: ta
aquí está todo el código que hemos escrito hoy:
=> ./img/screencap_uxn-pong.gif animación que muestra el pong en acción: las palas se mueven, la pelota rebota en las paredes superior e inferior y en las palas, y la pelota se reinicia desde el centro cuando la pelota golpea cualquier lado.
=> ./img/screencap_uxn-pong.gif animación que muestra el pong en acción: las palas se mueven, la pelota rebota en las paredes superior e inferior y en las palas y la pelota se reinicia desde el centro cuando la pelota golpea cualquier lado.
## configuración

View File

@ -19,14 +19,14 @@ sus puertos se definen normalmente de la siguiente manera:
* el corto vector no se utiliza actualmente
* el corto éxito almacena la longitud de los datos que se han leído o escrito con éxito, o cero si ha habido un error
* el corto nombre es para la dirección de memoria donde se almacena el nombre del archivo (terminado en cero, es decir, con un 00)
* el corto largo es la cantidad de bytes a leer o escribir: ¡no olvidemos que la memoria del programa es ffff más 1 byte de largo, y que el programa mismo se almacena allí!
* el corto largo es la cantidad de bytes a leer o escribir: ¡no olvidemos que la memoria del programa es ffff más 1 byte de largo y que el programa mismo se almacena allí!
* el corto leer es para la dirección de memoria inicial donde los datos de lectura deben ser almacenados
* el corto escribir es para la dirección de memoria inicial donde se almacenan los datos a escribir
* el corto estad es similar al de leer, pero lee la entrada del directorio para el nombre del archivo
* el byte borrar borra el archivo cuando se escribe cualquier valor en él.
* establecer el byte adjuntar a 01 hace que `escribir` añada datos al final del archivo. cuando el byte adjuntar tiene el valor por defecto, 00, `escribir` sobrescribe el contenido desde el principio
una operación de lectura se inicia cuando se escribe en el corto `leer`, y una operación de escritura se inicia cuando se escribe en el corto `escribir`.
una operación de lectura se inicia cuando se escribe en el corto `leer` y una operación de escritura se inicia cuando se escribe en el corto `escribir`.
¡estos pueden parecer muchos detalles para manejar, pero veremos que no son demasiado problema!
@ -40,7 +40,7 @@ para leer un archivo, necesitamos saber lo siguiente:
¡y eso es todo!
podemos usar una estructura como la siguiente, donde el nombre del archivo y la memoria reservada están bajo una etiqueta, y la subrutina carga-archivo bajo otra:
podemos usar una estructura como la siguiente, donde el nombre del archivo y la memoria reservada están bajo una etiqueta y la subrutina carga-archivo bajo otra:
```
@carga-archivo ( -- )
@ -93,7 +93,7 @@ el siguiente programa escribirá "hola" y una nueva línea (0a) en un archivo ll
;archivo/nombre .Archivo/nombre DEO2 ( establecer el nombre de archivo )
#0006 .Archivo/largo DEO2 ( intentará escribir 6 bytes )
( establecer la dirección de inicio de los datos, y hacer la escritura )
( establecer la dirección de inicio de los datos y hacer la escritura )
;archivo/datos .Archivo/escribir DEO2
( leer y evaluar el byte éxito )
@ -161,7 +161,7 @@ observe cómo las etiquetas &datos y &r apuntan a la misma ubicación: ¡no es u
### escribiendo el archivo de temas
y para hacer la operación contraria, podemos leer los colores del sistema en nuestro espacio reservado en memoria, y luego escribirlos en el archivo:
y para hacer la operación contraria, podemos leer los colores del sistema en nuestro espacio reservado en memoria y luego escribirlos en el archivo:
```
@guardar-tema ( -- )
@ -221,7 +221,7 @@ basándonos en esto, debería ser sencillo utilizarlos. por ejemplo, para leer l
tal vez puedas usar estos valores como coordenadas para algunos sprites, o tal vez puedas usarlos como tamaños o límites para figuras creadas con bucles.
o ¿qué tal dibujar sprites condicionalmente, y/o cambiar los colores del sistema dependiendo de la hora? :)
o ¿qué tal dibujar sprites condicionalmente y/o cambiar los colores del sistema dependiendo de la hora? :)
¡también puedes utilizar los valores de la fecha y la hora como semillas para generar algo de pseudo-aleatoriedad!
@ -250,7 +250,7 @@ supondremos que no estás familiarizado con estos conceptos, así que los discut
como hemos mencionado anteriormente, podemos pensar en los datos de las muestras como el equivalente a los datos de los sprites.
tienen que estar en la memoria del programa, tienen una longitud que debemos conocer, y podemos referirnos a ellos mediante etiquetas.
tienen que estar en la memoria del programa, tienen una longitud que debemos conocer y podemos referirnos a ellos mediante etiquetas.
el ejemplo piano.tal en el repositorio uxn, tiene varios de ellos, todos de 256 bytes de largo:
@ -352,7 +352,7 @@ el ejemplo piano.tal en el repositorio uxn, tiene varios de ellos, todos de 256
en el contexto de varvara, podemos entenderlos como múltiples bytes sin signo (u8) que corresponden a las amplitudes de la onda sonora que componen la muestra.
un "cabezal de reproducción" visita cada uno de estos números durante un tiempo determinado, y los utiliza para establecer la amplitud de la onda sonora.
un "cabezal de reproducción" visita cada uno de estos números durante un tiempo determinado y los utiliza para establecer la amplitud de la onda sonora.
las siguientes imágenes muestran la forma de la onda (o "waveform") de cada una de estas muestras.
@ -373,7 +373,7 @@ tri-pcm:
sierra-pcm:
=> ./img/screenshot_uxn-waveform_saw.png forma de onda de la muestra de sierra
de forma similar a como hemos tratado los sprites, y de forma parecida al dispositivo de archivo comentado anteriormente, para fijar una muestra en el dispositivo de audio sólo tenemos que escribir su dirección y su longitud:
de forma similar a como hemos tratado los sprites y de forma parecida al dispositivo de archivo comentado anteriormente, para fijar una muestra en el dispositivo de audio sólo tenemos que escribir su dirección y su longitud:
```
;sierra-pcm .Audio0/direc DEO2 ( establecer la dirección de la muestra )
@ -386,9 +386,9 @@ la frecuencia a la que se reproduce esta muestra (es decir, a la que la amplitud
el byte tono hace que la muestra comience a reproducirse cada vez que le escribimos, de forma similar a como el byte de sprite realiza el dibujo del sprite cuando le escribimos.
los primeros 7 bits (de derecha a izquierda) del byte corresponden a una nota midi, y por tanto a la frecuencia a la que se reproducirá la muestra.
los primeros 7 bits (de derecha a izquierda) del byte corresponden a una nota midi, y por tanto, a la frecuencia a la que se reproducirá la muestra.
el octavo bit es una bandera: cuando es 0 la muestra se reproducirá en bucle, y cuando es 1 la muestra se reproducirá sólo una vez.
el octavo bit es una bandera: cuando es 0 la muestra se reproducirá en bucle y cuando es 1 la muestra se reproducirá sólo una vez.
normalmente querremos hacer un bucle de la muestra para generar un tono basado en ella. sólo cuando la muestra sea lo suficientemente larga tendrá sentido no hacer un bucle y reproducirla una vez.
@ -423,9 +423,9 @@ BRK
## volumen
el byte de volumen se divide en dos nibbles: el nibble alto corresponde al volumen del canal izquierdo, y el nibble bajo corresponde al volumen del canal derecho.
el byte de volumen se divide en dos nibbles: el nibble alto corresponde al volumen del canal izquierdo y el nibble bajo corresponde al volumen del canal derecho.
por lo tanto, cada canal tiene 16 niveles posibles: 0 es el mínimo, y f el máximo.
por lo tanto, cada canal tiene 16 niveles posibles: 0 es el mínimo y f el máximo.
lo siguiente establecería el volumen máximo en el dispositivo:
@ -466,7 +466,7 @@ ok, ¡ahora estamos listos para reproducir el sonido!
## reproduciendo la muestra
¡el siguiente programa tiene ahora los cinco componentes que necesitamos para reproducir un sonido: una dirección de muestra, su longitud, las duraciones de adsr, el volumen, y su tono!
¡el siguiente programa tiene ahora los cinco componentes que necesitamos para reproducir un sonido: una dirección de muestra, su longitud, las duraciones de adsr, el volumen y su tono!
```
( hola-sonido.tal )
@ -485,7 +485,7 @@ ok, ¡ahora estamos listos para reproducir el sonido!
BRK
```
nota (!) que sólo se reproducirá el sonido una vez, y lo hace cuando se inicia el programa.
nota (!) que sólo se reproducirá el sonido una vez y lo hace cuando se inicia el programa.
### algunos experimentos sugeridos
@ -534,7 +534,7 @@ el byte de salida nos permite leer la amplitud de la envolvente. devuelve 0 cuan
## polifonía
la idea de tener cuatro dispositivos de audio es que podemos tenerlos todos sonando a la vez, y cada uno puede tener una muestra, envolvente ADSR, volumen y tono diferentes.
la idea de tener cuatro dispositivos de audio es que podemos tenerlos todos sonando a la vez y cada uno puede tener una muestra, envolvente ADSR, volumen y tono diferentes.
esto nos da muchas más posibilidades:
@ -567,4 +567,4 @@ pero antes de hacer todo esto, ¡no te olvides de tomar un descanso! :)
# apoyo
si te ha gustado este tutorial y te ha resultado útil, considera compartirlo y darle tu {apoyo} :)
si te ha gustado este tutorial y te ha resultado útil, considera compartirlo y darle tu {apoyo} :)