← Antiguo y prehistoriaObjeto 3Dfogon/grain-sacks
Bolsas de arpillera
Arrastrá para girarlo// «Bolsas de arpillera» · propio
// A pile of four fat burlap sacks, three on the ground and one on top, tied necks, tan with darker weave, one open showing golden grain.
// A pile of four fat burlap sacks: two lying side by side, one across on top, and one standing open, full of grain.
const burlap = ["#8a6c3f", "#9c7d4c", "#b0915c", "#c2a36c", "#d0b47e", "#dcc392"];
const seam = "#6f5530";
const rope = "#4a3520";
const grain = ["#c8921a", "#d9a520", "#e8b93a", "#f2cb5a"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
// A sack: a plump rounded box of cloth with a loose weave, lighter on top.
function sack(cx, cy, cz, rx, ry, rz, opts = {}) {
for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++)
for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++)
for (let z = Math.max(0, Math.floor(cz - rz)); z <= Math.ceil(cz + rz); z++) {
const nx = (x - cx) / rx, ny = (y - cy) / ry, nz = (z - cz) / rz;
const d = Math.pow(Math.abs(nx), 2.6) + Math.pow(Math.abs(ny), 2.6) + Math.pow(Math.abs(nz), 2.6);
if (d > 1) continue;
if (opts.cut != null && z > opts.cut) continue;
let tone = 3 + (nz > 0.5 ? 1 : nz < -0.35 ? -1 : 0);
tone += -nx - ny > 0.8 ? 1 : -nx - ny < -0.8 ? -1 : 0;
if ((x + 2 * y + 3 * z) % 5 === 0) tone--;
if (rand() < 0.06) tone--;
let c = burlap[clampi(tone, 0, 5)];
// The seam along its length.
const along = opts.seam === "x" ? Math.abs(y - cy) < 0.6 : opts.seam === "y" ? Math.abs(x - cx) < 0.6 : false;
if (along && nz > 0.2) c = seam;
set(x, y, z, c);
}
}
// A tied neck at the end of a lying sack: a short bunch, a dark rope around it and a tuft of cloth past the knot.
function neck(x, y, z, dx, dy) {
for (let k = 0; k <= 4; k++) {
const r = k < 2 ? 2.6 - k * 0.5 : k === 2 ? 1.7 : 2.2 + (k - 3) * 0.7;
for (let u = -4; u <= 4; u++)
for (let v = -4; v <= 4; v++) {
if (Math.hypot(u, v) > r) continue;
const c = k === 2 ? rope : burlap[clampi((k >= 3 ? 4 : 3) + (v > 0 ? 1 : 0) - ((u + v + 8) % 2 && k >= 3 ? 1 : 0), 0, 5)];
set(x + dx * k + (dx ? 0 : u), y + dy * k + (dy ? 0 : u), Math.max(0, z + v), c);
}
}
}
// Two lying on the ground, side by side, their necks to the left.
sack(31, 14, 6, 11.5, 8.2, 6.4, { seam: "x" });
neck(19, 14, 6, -1, 0);
sack(31, 31, 6, 11.5, 8.2, 6.4, { seam: "x" });
// One across on top of them, sagging into the gap, its neck to the front.
sack(31, 22.5, 15.5, 7.8, 12, 5.6, { seam: "y" });
neck(31, 10, 15.5, 0, -1);
// One standing open beside them, its mouth rolled down, full of golden grain.
const OX = 9.5, OY = 31;
sack(OX, OY, 11, 8, 8, 11.4, { cut: 19 });
for (let x = 0; x <= 19; x++)
for (let y = 21; y <= 41; y++) {
const d = Math.hypot(x - OX, y - OY);
if (d < 6.2) set(x, y, 19, grain[clampi(1 + Math.floor(rand() * 3), 0, 3)]);
if (d < 4) set(x, y, 20, grain[clampi(2 + Math.floor(rand() * 2), 0, 3)]);
if (d < 1.8) set(x, y, 21, grain[3]);
if (d >= 6.2 && d < 8.4) for (const z of [19, 20]) set(x, y, z, burlap[z === 20 ? 5 : 3]);
}
// A rope round its middle, and grain spilled on the ground in front of it.
for (let x = 0; x <= 19; x++)
for (let y = 21; y <= 41; y++) if (get(x, y, 14) && (!get(x - 1, y, 14) || !get(x, y - 1, 14) || !get(x + 1, y, 14) || !get(x, y + 1, 14))) set(x, y, 14, rope);
for (let i = 0; i < 34; i++) {
const a = rand() * Math.PI * 2, r = rand() * 5;
set(11 + Math.cos(a) * r, 17 + Math.sin(a) * r * 0.7, 0, grain[1 + Math.floor(rand() * 3)]);
}import { draw } from "./assets/voxel";
import { grainSacks } from "./assets/grain-sacks";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, grainSacks, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add grain-sacks
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["grain-sacks"] })
# Queda en client/assets/grain-sacks.ts
# https://fogon.gg/object/grain-sacks