← LibraryConceptmormon/blockyard-map
Blockyard: el mapa, a pie y con rifle
Original work by Saltline ↗
Clone
fogon pieces add blockyard-mapgit clone https://git.fogon.gg/mormon/blockyard-map.gitfogon new blockyard-map --from blockyard-maphttps://fogon.gg/piece/52/blockyard-el-mapa-a-pie-y-con-rifleBlockyard: el mapa, a pie y con rifle
El mapa Blockyard de Contrafuego, armado con los modelos originales del pack «Blockyard: objetos de una terminal de contenedores» (blockyard-props): una terminal de 66 × 56 m con una base en cada punta, tres carriles entre ellas (norte, medio y sur) separados por pilas de contenedores, y dos sitios abiertos. Viene como concepto completo de un juego de disparos en primera persona: el trazado como datos, la función que lo dibuja, las colisiones para caminar y para las balas, y el rifle en la mano con todo lo que pasa al disparar.

En la demo caminás por el patio con el rifle original y disparás. Cada tiro patea, hace un fogonazo, deja una trazadora y una marca donde pega, y suena (el sonido está hecho por código). Repartidos por el patio hay blancos de acero: caen cuando les das y se vuelven a parar a los cinco segundos.
- Teclado y mouse: WASD o flechas para caminar, Shift para correr, el mouse mira, clic dispara (también F o espacio), R recarga, M muestra el patio desde arriba.
- Teléfono: la mitad izquierda de la pantalla camina, la derecha mira, y hay un botón de fuego y uno de recarga.
Nada pasa por una sala: es solo la página.
Necesita el pack
Los modelos no están en esta pieza: los carga del pack publicado. En tu juego hacen falta las dos:
fogon pieces add blockyard-props # el cargador de los modelos, la luz y las cajas de colisión
fogon pieces add blockyard-map # el mapa, las colisiones y el rifle en mano
El código de esta pieza importa del pack por sus rutas (client/blockyard/…, shared/blockyard/…), que es donde fogon pieces add lo deja. En el código fuente de esta demo hay una copia idéntica de esos tres archivos del pack (client/blockyard/props.ts, client/blockyard/light.ts, shared/blockyard/sizes.ts) solo para que compile; no se comparten desde acá.
Qué trae
Dos carpetas, y las dos se llevan:
| Archivo | Qué hay |
|---|---|
shared/blockyard-map/layout.ts | El patio como números, sin three.js (lo puede leer una sala). WALLS y PROPS: qué hay y dónde (121 objetos). yardBoxes(): todo lo sólido. yardMap(): el mapa con la forma que pide el kit «Duelo por equipos». YARD, YARD_BASES, YARD_MID, y modelOf(i) / containerColor(i): qué modelo va en cada lugar. |
shared/blockyard-map/hit.ts | Caminar y disparar entre cajas, también sin three.js. slide(boxes, x, z): un cuerpo que no atraviesa lo sólido y resbala contra las paredes. castShot(boxes, origen, dirección): dónde termina una bala (punto, cara, distancia). castSphere(...): para blancos redondos. |
client/blockyard-map/yard.ts | buildYard(): el patio completo (piso, muros y los 121 objetos; cada modelo repetido se dibuja de una vez, con instancias). yardLamps(): dónde están las luces. yardDusk(scene, renderer): la luz del pack, centrada en el patio y con sombras que lo cubren. |
client/blockyard-map/gun.ts | createGun(camera, scene, rifle): el rifle en la mano. Cadencia, cargador y recarga; retroceso (del arma y de la mira), fogonazo con su luz, trazadora, marca y polvo donde pega, y el estampido, hechos por código. No sabe qué es sólido: vos le decís dónde termina cada tiro. |
Lo demás es la demo (client/main.ts: los controles, los blancos, la vista desde arriba) y una sala vacía.
Cómo se usa en un juego
Todo está en metros, con y hacia arriba; x va de oeste a este (−38…28) y z de norte a sur (−28…28).
Dibujar el patio:
import { buildYard, yardDusk } from "./blockyard-map/yard";
yardDusk(scene, renderer); // cielo, sol con sombras, y el entorno que reflejan los metales
scene.add(await buildYard()); // { lamps: true } enciende las torres; { instanced: false } deja cada objeto suelto
Caminar sin atravesar los contenedores:
import { yardBoxes } from "../shared/blockyard-map/layout";
import { slide } from "../shared/blockyard-map/hit";
const boxes = yardBoxes();
// cada cuadro: movés el cuerpo a donde quiere ir, y slide() lo saca de lo sólido
[body.x, body.z] = slide(boxes, body.x + vx * dt, body.z + vz * dt);
camera.position.set(body.x, 1.68, body.z);
El rifle y los tiros:
import { rifle } from "./blockyard/props"; // (del pack)
import { castShot } from "../shared/blockyard-map/hit";
import { createGun } from "./blockyard-map/gun";
scene.add(camera); // el rifle cuelga de la cámara
const gun = createGun(camera, scene, await rifle());
// cada cuadro:
if (triggerHeld)
gun.fire((origin, direction) => {
const hit = castShot(boxes, [origin.x, origin.y, origin.z], [direction.x, direction.y, direction.z]);
return hit && { point: hit.point, normal: hit.normal }; // { kind: "metal" } suena a chapa y no deja agujero
});
gun.update(dt, walkingSpeed);
camera.rotation.set(pitch + gun.recoil.pitch, yaw + gun.recoil.yaw, 0, "YXZ");
gun.fire() respeta la cadencia y el cargador: solo te llama cuando sale un tiro de verdad, con la posición del ojo y hacia dónde va (la puntería más un poco de dispersión, que crece si no soltás el gatillo). gun.ammo, gun.reloading y gun.reload() son para tu pantalla. Las opciones: rate (10 tiros por segundo), magazine (30), reloadTime, spread, volume (0 lo calla), marks (cuántas marcas quedan en las paredes) y hold (dónde cuelga).
En un juego con sala, la sala decide a quién le pegaste: castShot y slide no usan three.js justamente para que el servidor haga la misma cuenta con las mismas cajas.
Con el kit «Duelo por equipos» (team-deathmatch): el patio ya viene como mapa, con sus cajas, las dos bases y el medio. En la sala y en la página:
import { yardMap } from "../shared/blockyard-map/layout";
const map = yardMap(); // { bounds, boxes, bases, mid }: lo que pide deathmatch(map)
y en la página se dibuja con buildYard() en lugar de las cajas grises del kit.
El trazado
- Las bases están contra los muros oeste y este (
YARD_BASES). Delante de cada una hay una fila de contenedores con tres salidas: norte, medio y sur. - El medio tiene un contenedor cruzado, barreras, un tanque y cajones para cubrirse.
- Sitio A (norte) y sitio B (sur) son los dos claros, con contenedores sueltos, cajones, pallets, una estantería y un autoelevador.
- Las pilas que separan los carriles tienen dos y tres contenedores de alto: no se ve de un carril al otro.
Cambiar el mapa es cambiar PROPS ([objeto, x, z, girado, altura]) y WALLS: lo dibujado y lo sólido salen de la misma lista.
Qué no está respecto del juego
- El piso de la terminal (líneas pintadas, juntas, charcos y reflejos), el fondo (barco, grúas, mar, cielo con nubes) y la lluvia: el juego los hace con sombreadores propios que no se pueden exportar. El patio usa la superficie
asphaltdel pack y el atardecer dedusk. - Los colores de los contenedores caen en el mismo lugar que en el juego; los logos y las matrículas no siempre (el pack trae un modelo por color).
- Las luces de las torres están apagadas por defecto:
buildYard({ lamps: true })pone una luz por torre. - El jugador no tiene cuerpo ni manos, no salta ni se agacha, y no hay enemigos: los blancos de la demo son nuestros, hechos por código. Para un juego completo con equipos, bots y rondas, sumale
team-deathmatch. - Las colisiones son las cajas del juego: un poco más simples que los modelos (ver el README del pack).
Origen y permiso
Los modelos con los que se arma el patio y el rifle son del juego Saltline (https://claude.ai/artifact/BGY1SztrAYcJQHSsnHHGmp) y se publican con permiso de su autor en la pieza blockyard-props, de donde esta los carga. No son de dominio público ni tienen una licencia abierta: si querés usarlos fuera de Fogón, o venderlos, preguntale a su autor.
El trazado del mapa, las colisiones, el rifle en mano (retroceso, fogonazo, trazadora, marcas, sonido), los blancos y la demo son nuestros.
Pick a file.
| Version | When | Size | Commit |
|---|---|---|---|
| v2 in the demo | Nov 12, 2026 | 1.3 MB | 05787f9 |
| v1 | Nov 12, 2026 | 1.3 MB | e426350 |
Nobody has published a version made from this piece yet.
Put together the request for your agent
Pick what you want to do, copy the request and paste it into your AI (Claude, ChatGPT, Codex…). It does the rest.