hrxdev
Español

#3 Construye una prisión con el ratón, y salas que se encuentran solas

· Nick

El segundo hito está terminado, y por primera vez hay algo que mirar. El cliente de Godot ya se apoya en el núcleo de la simulación, y puedes construir con el ratón una prisión de una sola planta: colocar suelos, trazar paredes, poner puertas, marcar salas y derribar cosas. Todo son cubos simples y colores planos, y todavía no hay gente. Pero es un lugar, y puedes pasear la cámara por él.

Qué se puede hacer ahora

Empiezas una partida nueva, eliges el tamaño del mapa (64, 128 o 256 baldosas de lado) y una semilla opcional, y obtienes una cuadrícula vacía. La cámara es ortográfica, con una inclinación fija. Gira en pasos estrictos de 90°, hace zoom hacia el cursor, se desplaza con las teclas o con el botón central y tiene un modo cenital para construir. Con una cámara que girase libremente, las paredes taparían las salas; por eso no lo hace.

Los suelos y las demoliciones toman un rectángulo. Las paredes siguen un contorno (o una línea recta si mantienes Mayús). Una puerta es un clic, y elige su dirección según las paredes vecinas, con una tecla para girarla. Mientras arrastras, la zona bajo el cursor se muestra como un fantasma: las baldosas verdes se construirán, las rojas se omitirán, y una etiqueta indica cuántas y por qué. No se envía nada al mundo hasta que sueltas, y si el núcleo dice que ni una sola baldosa cambiaría, no se envía nada en absoluto. El clic derecho o Escape cancelan.

El modelo de mundo tiene varias plantas, así que hay un selector de planta, y las plantas por encima de la actual se ocultan. Las salas tienen su propia herramienta, que se explica más abajo. Una capa de depuración muestra los bordes de los bloques, las baldosas transitables, la baldosa bajo el cursor y un panel de tiempos. Todas las palabras de la interfaz están en inglés.

La vista previa es la real

Un fantasma que no coincide con el resultado es peor que ningún fantasma. Por eso el cliente no adivina lo que hará un comando de construcción. El núcleo puede responder a “qué pasaría si ejecutaras esto” para la misma zona, baldosa a baldosa, con un motivo por cada baldosa que rechazaría. La comprobación que rellena la vista previa es la misma regla que usa el comando cuando se ejecuta de verdad, así que ambas no pueden divergir. El cliente solo dibuja la respuesta. Solo vuelve a preguntar al núcleo cuando cambia algo que afecta a la respuesta: la herramienta, la zona arrastrada, la planta o el propio mapa.

El mismo principio da forma al resto del cliente: lee el estado del mundo y envía comandos, y no tiene lógica de simulación propia. Por ahora el núcleo hace sus ticks en el hilo principal, y un comando procedente de un clic se aplica al comienzo del siguiente fotograma, antes de que el mundo haga su tick. Si los tiempos de tick empiezan a dispararse cuando el mundo esté lleno de gente, el plan es mover el núcleo a su propio hilo, con un umbral medido que indique cuándo hacerlo.

Salas que se encuentran solas

Estudié dos formas de crear salas. Prison Architect te deja dibujar una zona, que entonces es un objeto con sus propias baldosas. Es fácil de entender, pero en una prisión falla: un bloque de celdas entero sería una única zona, y cuando reconstruyes una pared hay que volver a pintarla. La otra forma es encontrar automáticamente las áreas cerradas, pero entonces no puedes marcar un patio que no tiene paredes alrededor.

Lo que elegí es una mezcla. Lo único que se guarda es un tipo de sala en cada baldosa: celda, comedor, baños, enfermería, sala de visitas, patio de ejercicio, etc. Todo lo demás se deduce de las paredes. Un espacio es un grupo de baldosas abiertas unidas por sus lados, en un mismo nivel, y está cerrado si no toca el borde del mapa ni un vacío. Una sala es el conjunto de baldosas de un mismo tipo dentro de un mismo espacio. Las paredes y las puertas son límites, y un tipo pintado bajo una pared se conserva pero se ignora, así que vuelve si quitas la pared.

Esto da un comportamiento que resulta natural sin que haya que explicarlo. Si atraviesas una sala con una pared, se convierte en dos salas del mismo tipo. Si quitas la pared, se funden. Si pones una puerta donde había una pared, no cambia nada. Una sala que no es válida no se borra, porque eso sería lo contrario de “sin dolor”; se muestra en rojo con los motivos: no está cerrada, comparte espacio con otro tipo, es demasiado pequeña o no tiene puerta. Puedes pintar un rectángulo, rellenar con un clic todo un espacio cerrado con un único tipo, o borrarlo.

La lista de salas son datos derivados, así que no se guarda ni forma parte del hash del mundo; solo el tipo de cada baldosa. Se reconstruye tras los comandos y tras los sistemas, y comprobar un mundo sin cambios no cuesta nada. En este hito se recalcula entero el nivel que ha cambiado, lo que tarda alrededor de medio milisegundo en un mapa de 256×256; hacerlo bloque a bloque puede esperar hasta que las regiones de pathfinding necesiten la misma maquinaria. La regla a la que lo someto es que una reconstrucción incremental debe dar el mismo resultado que una completa.

Reconstruir solo lo que cambió, cortar plantas gratis

El mapa se dibuja como una malla por bloque y por nivel, no como un objeto por pared. Cada bloque tiene un contador de versión en el núcleo, y el renderizador recuerda qué versión dibujó por última vez. Cuando el mundo cambia, solo los bloques con una versión más nueva entran en una cola, y la cola se procesa con un presupuesto de tiempo por fotograma, de modo que un cambio enorme se reparte en unos cuantos fotogramas en lugar de congelar uno solo. Pintar un tipo de sala no sube la versión del mapa, así que nunca despierta al constructor de mallas.

El corte por plantas sigue la misma idea de hacer menos. Las plantas por encima de la actual simplemente se ocultan. Las paredes de la planta actual se aplastan hasta un metro mediante un shader, con un material compartido y un único valor de altura, de modo que cambiar de planta o alternar las paredes completas no reconstruye nada. Pasar por cuatro niveles provoca cero reconstrucciones de mallas.

Un hueco de diez centímetros

Cuando probé la primera prisión de una planta en la comprobación final, había un suelo en el nivel de arriba, y desde un lado se veía una fina línea clara entre lo alto de una pared y la losa que tenía encima. En una esquina se veía el suelo flotando en el aire. Sospeché del corte por plantas, luego del z-fighting, luego del suavizado.

No era ninguno de ellos. El suelo era un único cuadrilátero plano sin grosor, dibujado a la altura de su nivel más diez centímetros. Las paredes del nivel de abajo llegaban exactamente hasta los tres metros. El suelo del nivel siguiente empezaba a los tres metros diez. El hueco medía diez centímetros de ancho, y a través de él se veía la cara superior iluminada de la pared. En horizontal todo encajaba a la perfección, y por eso tardé en verlo.

La solución es que ahora un suelo es una losa con grosor real, que llega hacia abajo hasta el comienzo de su nivel. La parte superior queda a la misma altura, así que la selección de baldosas con el ratón y todas las capas siguen igual. Las caras laterales se omiten donde un suelo o una pared se tocan dentro del mismo bloque y se dibujan en los bordes de bloque, de modo que la malla de un bloque nunca depende de sus vecinos. Eso deja un borde oscuro de diez centímetros en el extremo de la losa. Miré capturas de antes y de después, y decidí conservarlo. Se lee como el canto de un suelo, que es lo que es.

¿Aguanta?

La última tarea del hito era construir con el ratón una prisión de una planta y ver si duele. En su mayor parte, no. Lo que encontró la prueba además del hueco de arriba fue pequeño y molesto: los botones de herramienta no dejaban de estar resaltados al elegir otra herramienta con el ratón, y no había forma de salir del diálogo de Nueva partida con Escape. Ambos están corregidos. Un menú de pausa está en la lista de ideas para más adelante.

Lo siguiente

Lo siguiente es M2, el movimiento y la rutina diaria. El mundo recibe regiones y alcanzabilidad, búsqueda de caminos que funciona entre plantas y campos de flujo para las multitudes. Por fin el núcleo tiene trabajo real en cada tick, así que la condición del benchmark dejará de dormir. Consulta la hoja de ruta.

← #2 · Todas las entradas del devlog