{"id":2862,"date":"2021-02-07T13:57:00","date_gmt":"2021-02-07T13:57:00","guid":{"rendered":"http:\/\/blog.rastersoft.com\/?p=2862"},"modified":"2023-12-25T19:47:45","modified_gmt":"2023-12-25T19:47:45","slug":"pintando-en-el-spectrum-12","status":"publish","type":"post","link":"https:\/\/blog.rastersoft.com\/?p=2862","title":{"rendered":"Pintando en el Spectrum (12)"},"content":{"rendered":"\n<p>Llega el momento de hacer el mapa. Para ello tenemos que recordar que el Spectrum no tiene la capacidad de memoria de los ordenadores actuales, lo que significa que no podemos crear pantallas <em>a lo bruto<\/em> y guardarlas tal cual, sino que tenemos que buscar la manera de guardarlas comprimidas, para que ocupen lo menos posible. Una t\u00e9cnica habitual es utilizar <em>tiles<\/em> o <em>losetas<\/em> para crear las pantallas. En ellas, lo que se hace es generar un n\u00famero peque\u00f1o de gr\u00e1ficos, y combin\u00e1ndolos y repiti\u00e9ndolos de distintas maneras podemos crear multitud de estancias de un mapa ocupando muy poca memoria. Veamos un ejemplo con un trozo de mapa:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/pantalla_mapa.png\" rel=\"lightbox-0\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"320\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/pantalla_mapa.png\" alt=\"\" class=\"wp-image-2863\" srcset=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/pantalla_mapa.png 512w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/pantalla_mapa-300x188.png 300w\" sizes=\"auto, (max-width: 512px) 100vw, 512px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Vemos que hay varios elementos repetitivos, como por ejemplo las losetas del suelo; pero en realidad todo est\u00e1 colocado en base a una cuadr\u00edcula de elementos de 4&#215;4 caracteres. Las posibles <em>losetas<\/em> que, de momento, se utilizan en el mapa son las siguientes:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/tiles.png\" rel=\"lightbox-1\"><img loading=\"lazy\" decoding=\"async\" width=\"686\" height=\"606\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/tiles.png\" alt=\"\" class=\"wp-image-2864\" srcset=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/tiles.png 686w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/01\/tiles-300x265.png 300w\" sizes=\"auto, (max-width: 686px) 100vw, 686px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>As\u00ed, por un lado tenemos las definiciones de las diferentes losetas, y por otro la definici\u00f3n del mapa en s\u00ed. En esta \u00faltima estructura lo \u00fanico que tenemos que almacenar es qu\u00e9 loseta va en cada posici\u00f3n. Dado que la pantalla mide 32&#215;24 caracteres, y cada posici\u00f3n de loseta mide 4&#215;4 caracteres, tenemos que cada pantalla del mapa ocupar\u00e1 8&#215;6 = 24 bytes (si s\u00f3lo empleamos un byte por loseta, claro). Por supuesto, las losetas en s\u00ed ocupan m\u00e1s memoria: en este caso, cada loseta de 4&#215;4 caracteres ocupa 128 bytes de p\u00edxeles m\u00e1s 16 bytes para atributos de color; en total 144 bytes. Pero la ventaja es que una misma loseta se puede reutilizar varias veces en m\u00faltiples pantallas, por lo que el ahorro es muy grande. En la pantalla de arriba vemos que el grueso lo ocupa la loseta superior izquierda, y que las paredes de la izquierda y de arriba est\u00e1n hechas fundamentalmente con dos losetas concretas.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pintando el mapa<\/h2>\n\n\n\n<p>Ahora que expliqu\u00e9 la base, voy a comentar algunos detalles de mi implementaci\u00f3n. En primer lugar, las losetas mostradas arriba no tienen m\u00e1scara de transparencia (con la excepci\u00f3n de la puerta vertical&#8230; ya lo explicar\u00e9 luego). El motivo es que las losetas se utilizan para pintar el fondo de la pantalla, por lo que, dado que no hay nada <em>debajo<\/em>, no hace falta que tengan transparencia. Esto significa que, a la hora de pintarlas, tengo que tenerlo en cuenta. La primera idea ser\u00eda poner una comprobaci\u00f3n dentro del bucle que copia cada byte de un <em>sprite<\/em> al buffer de v\u00eddeo, pero tiene el inconveniente de que estamos comprobando lo mismo una y otra vez en todos los bytes que copiamos. Como vimos en las primeras entradas, pintar gr\u00e1ficos en pantalla consume <em>mucho<\/em> tiempo porque hay que copiar una cantidad ingente de bytes, y cualquier peque\u00f1o ahorro dentro del bucle supone un aumento brutal del rendimiento, pues se multiplica por los m\u00e1s de seis kilobytes que hay que copiar en cada frame. Es por esto que s\u00f3lo hago una comprobaci\u00f3n justo antes de entrar en el bucle externo (el que pinta las filas), y en funci\u00f3n de si el sprite tiene o no m\u00e1scara, voy a una rutina u otra. <a rel=\"noreferrer noopener\" href=\"https:\/\/blog.rastersoft.com\/?p=2776\" target=\"_blank\">La rutina que pinta con m\u00e1scara ya la vimos en la entrada n\u00famero 6<\/a>, as\u00ed que pondr\u00e9 a continuaci\u00f3n \u00fanicamente la rutina que pinta sin m\u00e1scara. Partimos de HL apuntando al sprite, de DE conteniendo la direcci\u00f3n de destino, calculada a partir de las coordenadas, y de BC conteniendo el alto en scanlines y el ancho en caracteres (esos datos los obtenemos con el c\u00f3digo com\u00fan con la rutina que pinta con m\u00e1scara):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">    ld A, C ; guardamos el n\u00famero de columnas en A\n    push DE\n    push BC\n    ld B, 0\n    exx\n    pop BC ; pasamos el n\u00famero de filas al juego alternativo de registros\n    pop IX ; y la direcci\u00f3n de destino a IX\n    ld DE, 32 ; valor a sumar para saltar al siguiente scanline\nloop1:\n    exx\n    ld D, IXh\n    ld E, IXl ; la pasamos al conjunto de registros principal\n    ld C, A ; B vale cero, as\u00ed que LDIR copiar\u00e1 A bytes\n    ldir ; copiamos una fila\n    exx\n    add IX, DE ; saltamos al siguiente scanline\n    djnz loop1<\/pre>\n\n\n\n<p>Esta rutina tiene la ventaja de que es mucho m\u00e1s r\u00e1pida que la que utiliza m\u00e1scaras, gracias a que se basa en LDIR. As\u00ed, cada byte necesita s\u00f3lo 23 Testados frente a los 61 que necesit\u00e1bamos en la rutina con m\u00e1scaras, lo que es un gran ahorro, y m\u00e1s si nos aseguramos de que el m\u00e1ximo n\u00famero posible de <em>tiles<\/em> no usan m\u00e1scara, la cual la reservaremos s\u00f3lo para los personajes y objetos m\u00f3viles, pues ellos s\u00ed queremos que se muevan \u00abpor encima\u00bb de lo que ya est\u00e1 pintado, y para alg\u00fan <em>tile<\/em> muy concreto.<\/p>\n\n\n\n<p>Una vez que tenemos ya esta rutina, toca almacenar el mapa. La idea consiste en almacenar un <em>array<\/em> de bytes. En mi juego no voy a utilizar una distribuci\u00f3n cl\u00e1sica de pantallas en la que el personaje se mueve por dentro de la pantalla, y cada vez que sale, la pantalla se borra y se pinta una nueva. En mi caso el personaje estar\u00e1 quieto en el medio de la pantalla, y todo el mapa se mover\u00e1 a derecha, izquierda, arriba o abajo. Esto significa que, al no haber fronteras definidas, todo el mapa ser\u00e1 un solo bloque. Este es el mapa de demostraci\u00f3n que hice:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">map_array:\n    defb 0x0A, 0x0A, 0x0A, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x90, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8C, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x91, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x02, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x88, 0x01, 0x01, 0x01, 0x04, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x89, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x03, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x85, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x85, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x85, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x8E, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8D, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x8F, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n    defb 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A\n\n<\/pre>\n\n\n\n<p>El mapa mide 32 <em>tiles<\/em> (256 caracteres) de ancho. Esto lo hice porque es el m\u00e1ximo valor que se puede almacenar en un byte para las coordenadas, y porque para multiplicar por el ancho s\u00f3lo hay que rotar cinco veces el valor, lo que es una operaci\u00f3n f\u00e1cil y r\u00e1pida. Por otro lado, he decidido que si un valor tiene el bit 7 a uno, significa que el personaje no puede <em>pisar<\/em> esa <em>loseta<\/em>. As\u00ed, las paredes, mesas, camas, etc. tendr\u00e1n dicho bit a 1 para evitar que el personaje las atraviese, y s\u00f3lo las losetas <em>normales<\/em> tendr\u00e1n dicho bit a 0.<\/p>\n\n\n\n<p>La correspondencia de cada n\u00famero es como sigue:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted mycode\">; 0 -&gt; no pintar\n; 1 -&gt; suelo normal\n; 2 -&gt; suelo roto\n; 3 -&gt; suelo con rejilla\n; 4 -&gt; minisuelo (suelo con una \u00fanica l\u00ednea, para muros horizontales)\n; 5 -&gt; muro vertical\n; 6 -&gt; muro horizontal\n; 7 -&gt; cruce de muros\n; 8 -&gt; parte superior de puerta vertical\n; 9 -&gt; parte inferior de puerta vertical\n; A -&gt; suelo exterior\n; B -&gt; minisuelo exterior (single-line)\n; C -&gt; muro en T superior\n; D -&gt; muro en T inferior\n; E -&gt; esquina inferior izquierda\n; F -&gt; esquina inferior derecha\n;10 -&gt; esquina superior izquierda\n;11 -&gt; esquina superior derecha\n<\/pre>\n\n\n\n<p>Los elementos 0, 4 y B pueden parecer extra\u00f1os, pero tienen sentido para aquellas losetas que estar\u00e1n tapadas por otras losetas que midan m\u00e1s de 4&#215;4 caracteres. De hecho, comparemos la loseta 1 con la 4 y la B:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/minilosetas.png\" rel=\"lightbox-2\"><img loading=\"lazy\" decoding=\"async\" width=\"305\" height=\"135\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/minilosetas.png\" alt=\"\" class=\"wp-image-2897\" srcset=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/minilosetas.png 305w, https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/minilosetas-300x133.png 300w\" sizes=\"auto, (max-width: 305px) 100vw, 305px\" \/><\/a><\/figure><\/div>\n\n\n\n<p>Vemos que son b\u00e1sicamente iguales, salvo porque la 4 y la B son m\u00e1s peque\u00f1as verticalmente. El motivo de que existan estas losetas es que pintar un sprite supone una carga de procesador muy elevada, pues hay que copiar muchos bytes de un lado para otro, por lo que si podemos ahorrar pintar algunos bytes, mejor. Para entenderlo mejor, veamos c\u00f3mo compongo el mapa para dar, adem\u00e1s, apariencia 3D.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Pintando en pseudo3D<\/h2>\n\n\n\n<p>La vista del mapa pretende ofrecer un pseudo3D. Al contrario que otros sistemas, como por ejemplo las vistas isom\u00e9tricas, donde la coordenada X e Y de la pantalla sale de una combinaci\u00f3n lineal de las coordenadas X, Y y Z de cada objeto, en este sistema la coordenada X de la pantalla es simplemente la misma que la del objeto, y la coordenada Y es la Y del objeto menos la Z. Sin embargo, esto es s\u00f3lo parte del problema del pintado. La otra parte es decidir el orden en que hay que pintar los objetos para asegurarse de que el efecto pseudo3D es consistente: por ejemplo, que si un personaje pasa por detr\u00e1s de una mesa o de una pared, quede parcialmente oculto. Para ello es necesario pintar todos los elementos en un orden concreto: de atr\u00e1s hacia adelante, de manera que los objetos que est\u00e1n m\u00e1s cercanos vayan tapando lo que hay detr\u00e1s. En el sistema que he escogido esto es muy sencillo: cuanto mayor sea la Y del objeto, m\u00e1s \u00ababajo\u00bb en la pantalla estar\u00e1 y, por tanto, habr\u00e1 que pintarlo m\u00e1s tarde.<\/p>\n\n\n\n<p>Sabiendo esto, el proceso es muy sencillo: si queremos pintar el mapa desde las coordenadas X0,Y0, lo que haremos ser\u00e1 pintar primero los <em>tiles<\/em> cuya coordenada Y sea igual a Y0. Luego pintaremos los personajes cuya coordenada Y sea igual a Y0. A continuaci\u00f3n pintaremos los <em>tiles<\/em> cuya coordenada Y sea igual a Y0+1, y seguiremos con los personajes cuya coordenada Y sea igual a Y0+1. Y as\u00ed sucesivamente.<\/p>\n\n\n\n<p>Ve\u00e1moslo de manera gr\u00e1fica:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/mapa_among-1.gif\" rel=\"lightbox-3\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"368\" src=\"https:\/\/blog.rastersoft.com\/wp-content\/uploads\/2021\/02\/mapa_among-1.gif\" alt=\"\" class=\"wp-image-2901\"\/><\/a><\/figure><\/div>\n\n\n\n<p>En el GIF anterior muestra el orden en el que se van pintando los <em>tiles<\/em>. Vemos que algunos objetos, como las camas, ocupan m\u00e1s de un <em>tile<\/em> en vertical. Esto es porque tienen <em>altura<\/em>, y, por tanto, tapar\u00e1n a un personaje que pase por detr\u00e1s. La \u00fanica precauci\u00f3n es que deben pintarse algo m\u00e1s arriba. En mi caso, como todos los <em>tiles<\/em> del suelo tienen 4 caracteres de altura, si al pintar un elemento \u00e9ste tiene m\u00e1s, lo que hago es pintarlo tantos caracteres hacia arriba como caracteres extra tenga. As\u00ed, al pintar la segunda fila de <em>tiles<\/em> se ve que un elemento es una cama, que tiene una altura de seis caracteres. Por tanto, debe pintarse en la coordenada Y=2 en lugar de la coordenada Y=4, que ser\u00eda la que le corresponder\u00eda a un <em>tile<\/em> de suelo, por ejemplo. Lo mismo ocurre con la esquina de la pared, en la tercera fila de <em>tiles<\/em>: dado que mide ocho caracteres de alto, se pinta a partir de Y=4 en lugar de Y=8. Vemos que el resultado es que el personaje, efectivamente, resulta <em>tapado<\/em> parcialmente por la cama que tiene delante, lo que potencia el efecto 3D.<\/p>\n\n\n\n<p>Se puede ver tambi\u00e9n que en las zonas de una fila que quedar\u00e1n cubiertas por un <em>tile<\/em> de la fila siguiente, he utilizado <em>tiles<\/em> incompletos, justo de los que hablaba antes. As\u00ed, en la fila anterior a una cama, he utilizado suelo que es la mitad de alto, y en la fila anterior de la esquina de la pared directamente no he pintado el <em>tile<\/em> de la baldosa en la zona que ir\u00e1 ocupada por la parte superior.<\/p>\n\n\n\n<p>\u00bfPor qu\u00e9 hago esto? Simplemente para ahorrar procesador. Podr\u00eda haber pintado la baldosa completa, de 4&#215;4 caracteres y el resultado habr\u00eda sido exactamente el mismo. Sin embargo, dado que la siguiente fila sobreescribir\u00e1 partes de la anterior, realmente estar\u00eda pintando dos veces una zona de la pantalla, lo que supone tirar a la basura tiempo de procesador (algo de lo que andamos muy justos), y adem\u00e1s haciendo justo lo que m\u00e1s tiempo consume: pintando cosas. Por eso cre\u00e9 esas <em>tiles<\/em> extra de baldosas con dos y una fila s\u00f3lo, y por eso existe el <em>tile<\/em> cero, que directamente no pinta nada en esa posici\u00f3n: para ahorrarnos el pintar algo que sabemos que ser\u00e1 borrado al pintar la siguiente fila.<\/p>\n\n\n\n<p>Por supuesto, esto puedo hacerlo con las baldosas porque se desde el principio cuales ser\u00e1n cubiertas por el elemento de la siguiente fila y cuanto. En cambio, vemos que el personaje lo pintamos completo porque de \u00e9l no podemos saber <em>a priori<\/em> qu\u00e9 partes ser\u00e1n tapadas por otros objetos. En este caso no hay atajos.<\/p>\n\n\n\n<p>Ah, y si not\u00e1is diferencias entre los <em>tiles<\/em> del principio del art\u00edculo y los que se ven en la animaci\u00f3n de aqu\u00ed abajo, es porque cambi\u00e9 los colores para darle un poco m\u00e1s de vidilla a los decorados.<\/p>\n\n\n\n<p>En la siguiente entrada veremos el gestor de tareas y la gesti\u00f3n del movimiento de los personajes.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Llega el momento de hacer el mapa. Para ello tenemos que recordar que el Spectrum no tiene la capacidad de memoria de los ordenadores actuales, lo que significa que no podemos crear pantallas a lo bruto y guardarlas tal cual, sino que tenemos que buscar la manera de guardarlas comprimidas, para que ocupen lo menos &hellip; <a href=\"https:\/\/blog.rastersoft.com\/?p=2862\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">Pintando en el Spectrum (12)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,17,7],"tags":[20],"class_list":["post-2862","post","type-post","status-publish","format-standard","hentry","category-programacion","category-retrocomputacion","category-tutoriales","tag-pintando-en-el-spectrum"],"_links":{"self":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2862","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2862"}],"version-history":[{"count":21,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2862\/revisions"}],"predecessor-version":[{"id":2937,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=\/wp\/v2\/posts\/2862\/revisions\/2937"}],"wp:attachment":[{"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2862"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2862"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.rastersoft.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2862"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}