fogón

← BibliotecaObjetomormon/blockyard-props

Blockyard: la terminal de contenedores

m@mormonObjeto, Permiso del autor
v2hace 2 días

Obra original de Saltline ↗

Clonar
FOGONfogon pieces add blockyard-props
GITgit clone https://git.fogon.gg/mormon/blockyard-props.git
REMIXfogon new blockyard-props --from blockyard-props
ZIPblockyard-props.zipBajar
Controles

Blockyard: objetos de una terminal de contenedores

Un pack de modelos para three.js: los objetos originales del mapa Blockyard de Contrafuego, tal como salen del juego. Contenedores de 20 y 40 pies en ocho colores, un autoelevador, la garita, torres de luz, barreras, cajones, pallets, una bobina de cable, un tanque IBC y más, cada uno con sus texturas PBR, sus calcos y sus rótulos. Con ellos vienen el rifle del jugador y siete superficies (asfalto, hormigón, ladrillo, chapa).

No están rehechos: se exportaron del juego en marcha (ver Origen y permiso).

Todos los objetos del pack, uno al lado del otro

En la demo: la lista de la izquierda tiene todo lo que trae el pack, en cuatro pestañas (Objetos, Contenedores, Superficies, Todo junto). Elegí uno y lo ves solo, girando: arrastrá para mirarlo, la rueda o dos dedos acercan, y las flechas ↑↓ recorren la lista. Abajo están su tamaño, sus triángulos y la línea de código que lo trae (un clic la copia). En los controles: Caja de colisión dibuja la caja con la que choca en el juego (amarilla) y las cajas finas (celestes), Mojado lo oscurece y abrillanta como bajo la lluvia, y la grilla es de un metro.

El mapa armado con estos objetos es otra pieza: «Blockyard: el mapa, a pie y con rifle» (blockyard-map).

Qué trae

Dos carpetas, y las dos se llevan (fogon pieces add blockyard-props):

ArchivoQué hay
client/blockyard/props.tsEl cargador. loadProps(), piece(name) / pieceNow(name), pieceNames(), bounds(name), info(name) (caja, triángulos, colisiones finas y lámparas), rifle(), surfaceNames(), wallMaterial(name) y slab(name, ancho, alto, fondo) para las superficies, setWetness(0…1), setBase(url), disposeProps().
client/blockyard/light.tsdusk(scene, renderer): la hora de la terminal. Cielo, sol bajo con sombras, luz de relleno, niebla y el entorno que reflejan los metales (sin un entorno, el acero sale negro).
shared/blockyard/sizes.tsSin three.js (lo puede leer una sala). PROP_SIZE: la caja de colisión de cada objeto, la del juego. propBox(name, x, z, turned, y): esa caja puesta en un lugar. CONTAINER_COLORS y propOf(model).

Los modelos no viajan con el código: están en public/blockyard/ de esta demo (blockyard.glb, 6 MB, y catalog.json) y el cargador los baja de ahí. Lo demás es la demo (client/main.ts) y una sala vacía.

Los objetos

NombreQué esTamaño (m)Triángulos
container20_<color>Contenedor de 20 pies6,07 × 2,59 × 2,45~5.300
container40_<color>Contenedor de 40 pies12,20 × 2,59 × 2,44~6.400
light_mastTorre de luz0,99 × 14 × 1,902.794
floodlight_standReflector de pie0,92 × 2,24 × 1,661.438
guard_boothGarita3,11 × 2,55 × 2,773.088
shelf_rackEstantería de depósito, cargada2,75 × 4,20 × 1,137.032
jersey_barrierBarrera de hormigón3,00 × 0,86 × 0,61604
pallet_stackPila de pallets1,27 × 1,15 × 1,052.560
crate_woodCajón de madera1,11 × 1,00 × 0,911.476
crate_stackTres cajones apilados, con sus cinchas1,21 × 1,91 × 1,042.552
ibc_toteTanque IBC de 1000 litros1,20 × 1,15 × 1,002.122
forkliftAutoelevador3,41 × 2,19 × 1,2511.628
cable_reelBobina de cable1,29 × 1,30 × 0,862.442
tire_stackPila de cubiertas0,80 × 0,99 × 0,812.560
dumpsterContenedor de basura1,92 × 1,21 × 1,242.742
tarp_cargoCarga bajo lona2,41 × 1,44 × 1,482.968
sandbagsBolsas de arena1,99 × 0,90 × 0,632.646
rifleEl rifle del jugador, sin las manos0,07 × 0,34 × 0,8830.702

Los colores de los contenedores: red, blue, green, yellow, orange, white, grey, teal (16 modelos: cada uno con su logo, su matrícula y sus chorreaduras de óxido). Las superficies: asphalt, concrete, concrete_dirty, concrete_painted, brick, floor_epoxy, corrugated_roof.

En total: 32 objetos, 173.398 triángulos, 131 texturas en WebP (1024 px las más grandes) y 102 materiales.

Cómo se usa en un juego

Todo está en metros, con y hacia arriba. Cada objeto sale parado sobre el piso, centrado en x y z, con su lado largo sobre x: se pone con position y se gira con rotation.y.

import { loadProps, piece, slab } from "./blockyard/props";
import { dusk } from "./blockyard/light";

await loadProps();                          // baja blockyard.glb (6 MB) una sola vez
dusk(scene, renderer);                      // cielo, sol, y el entorno: sin él los metales salen negros

const forklift = await piece("forklift");
forklift.position.set(4, 0, -2);
scene.add(forklift);

scene.add(await piece("container40_teal"));
scene.add(slab("brick", 6, 3, 0.3));        // una pared de ladrillo de 6 × 3 m

Cada copia comparte geometría y materiales con las demás: ochenta contenedores ocupan en memoria lo que uno de cada color. Por lo mismo, si cambiás un material cambian todas (clonalo antes si querés uno distinto).

La luz. dusk() alumbra 30 m alrededor del origen; para una escena más grande decile dónde y cuánto: dusk(scene, renderer, { center: [-5, 0], reach: 48 }). Si ya tenés tu propia luz, lo único que hace falta es un scene.environment.

El rifle, colgado de la cámara (apunta a −Z, que es hacia donde mira):

import { rifle } from "./blockyard/props";

const gun = await rifle();
gun.position.set(0.115, -0.125, -0.3);
camera.add(gun);
scene.add(camera);

(La pieza blockyard-map trae el resto: retroceso, fogonazo, trazadora, marcas de impacto y sonido.)

En la sala, para que los objetos frenen a los jugadores y a las balas, sus cajas salen de sizes.ts:

import { propBox } from "../shared/blockyard/sizes";

const boxes = [propBox("forklift", 4, -2), propBox("container40_teal", 0, 0), propBox("container20_red", 0, 0, false, 2.59)];
// cada una: [minX, minY, minZ, maxX, maxY, maxZ]

Servir los modelos desde tu juego (para no depender de esta demo): copiá public/blockyard/ a tu public/ y avisale al cargador una vez, antes de cargar:

await loadProps({ base: "./blockyard/" });

Las cajas de colisión

PROP_SIZE trae la caja que el juego usa para cada objeto: [largo en x, alto, fondo en z], centrada y apoyada en el piso. Casi todas coinciden con el modelo a menos de 6 cm. Las que no:

ObjetoModelo (m)Caja (m)Por qué
light_mast0,99 × 14 × 1,900,5 × 14 × 0,5La caja es el poste; la base y los brazos con las lámparas (a 13 m) sobresalen.
floodlight_stand0,92 × 2,24 × 1,661 × 2,2 × 1Una pata del trípode sale 78 cm hacia −z.
guard_booth3,11 × 2,55 × 2,772,6 × 2,7 × 2,2El alero del techo y el aire acondicionado sobresalen unos 30 cm; la caja es 15 cm más alta que el techo.
dumpster1,92 × 1,21 × 1,241,9 × 1,35 × 1,1La caja es 14 cm más alta; la tapa sobresale 10 cm hacia −z.
tarp_cargo2,41 × 1,44 × 1,482,4 × 1,5 × 1,4La lona cae 7 cm más allá hacia +z.

info(name).colliders trae además las cajas finas del juego (el autoelevador tiene once: chasis, mástil, uñas, techo). En la demo, el control Caja de colisión las dibuja sobre el modelo.

Qué se perdió respecto del juego

Los modelos son los del juego: la misma geometría, los mismos colores por vértice, las mismas texturas. Lo que el juego agrega al dibujar no se puede guardar en un archivo de modelo, y no está:

  • La lluvia sobre las superficies. El juego moja cada material según hacia dónde mira la cara (charcos arriba, chorreaduras en las paredes, una franja salpicada contra el piso) y le agrega gotas. setWetness() es un reemplazo parejo: oscurece y abrillanta todo por igual.
  • La variación a gran escala: manchas de suciedad que el juego calcula por posición en el mundo, para que dos contenedores iguales no se vean iguales.
  • El detalle fino del rifle: desgaste, rayas y gotas, que el juego calcula en su sombreador. Quedan sus colores, su rugosidad y su oscurecido por vértice. Tampoco están la retícula de la mira, ni las manos.
  • Las variantes por semilla. En el juego cada objeto sale un poco distinto (otro logo, otra matrícula, otras manchas, otra carga en la estantería). Acá hay uno de cada uno; los contenedores, uno por color.
  • Las luces de las torres son, en el juego, luces de verdad con halo; acá el foco brilla (material emisivo) e info(name).lamps dice dónde está cada lámpara y hacia dónde apunta, para ponerle una luz.

Tres ajustes menores: algunas rugosidades que el juego multiplica por más de 1 viajan aparte (el cargador las repone; otro visor de glTF las ve en 1), el tinte de la pintura está cocido en la textura de color (por eso hay una por color) y la munición de latón del cargador del rifle usa las coordenadas de textura de su malla en vez de la proyección del juego.

Origen y permiso

Los modelos, los materiales y el rifle son del juego Saltline (https://claude.ai/artifact/BGY1SztrAYcJQHSsnHHGmp) y están acá con permiso de su autor. 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 cargador, la luz, las cajas de colisión como datos, la demo y las herramientas de exportación son nuestros.

Cómo se hizo

Saltline no trae archivos de modelo: construye cada objeto por código al arrancar y fabrica sus texturas en la placa de video. Para tenerlos como archivo hubo que sacarlos del juego andando (las herramientas quedan en tools/, en la carpeta del estudio: no viajan con la pieza publicada):

  1. tools/export/export.ts abre el juego en un Chrome sin ventana, le pide cada objeto a su propio constructor, lee cada textura de la placa de video, pasa los materiales a materiales estándar y los guarda con el exportador de glTF de three.js. Sale un .glb crudo de 60 MB.
  2. tools/build.ts lo achica con glTF-Transform: une las mallas por material, suelda vértices, pasa las texturas a WebP y comprime la geometría con meshopt. Quedan 6 MB, y catalog.json con la caja y los datos de cada objeto.