← ArmasObjeto 3Dfogon/service-rifle
Rifle de servicio
Arrastrá para girarlo// «Rifle de servicio» · propio
// A generic black assault rifle standing in profile: a dark grey receiver, a short handguard, a curved magazine, a pistol grip, a fixed stock and a small sight on top. No real brand or model.
// A generic assault rifle standing in profile (muzzle to +x), resting on its magazine and grip. No real model.
const BODY = ["#33363c", "#3d4047", "#484c54"];
const DARK = ["#1c1d20", "#232528", "#2b2d31"];
const STEEL = ["#5a5f67", "#6b7079", "#7d838c"];
const shade = (tones, z, lo, hi) => tones[Math.max(0, Math.min(tones.length - 1, Math.floor(((z - lo) / Math.max(1, hi - lo)) * tones.length + (rand() - 0.5) * 0.6)))];
const slab = (x0, x1, z0, z1, tones, y0 = 22, y1 = 25) => {
for (let x = x0; x <= x1; x++) for (let z = z0; z <= z1; z++) for (let y = y0; y <= y1; y++) set(x, y, z, shade(tones, z, z0, z1));
};
// Stock: a fixed one, taller at the butt, with a rubber pad.
for (let x = 2; x <= 13; x++) {
const t = (x - 2) / 11;
const lo = Math.round(11 + t * 3);
const hi = Math.round(20 - t * 0);
for (let z = lo; z <= hi; z++) for (let y = 22; y <= 25; y++) set(x, y, z, x <= 3 ? DARK[0] : shade(BODY, z, lo, hi));
}
for (let x = 6; x <= 10; x++) for (let z = 14; z <= 16; z++) for (let y = 22; y <= 25; y++) set(x, y, z, null); // the gap in the stock
// Receiver.
slab(13, 28, 13, 20, BODY);
for (let x = 14; x <= 27; x++) for (const y of [22, 25]) set(x, y, 20, "#565a63"); // a lit top edge
slab(19, 22, 15, 17, DARK, 22, 22); // the ejection port, on the side that faces the viewer
set(24, 22, 16, STEEL[2]);
set(16, 22, 15, "#b5462f"); // the selector's red dot
// Handguard with cooling slots.
slab(28, 38, 14, 19, DARK);
for (let x = 30; x <= 36; x += 2) for (const y of [22, 25]) { set(x, y, 16, BODY[2]); set(x, y, 17, BODY[2]); }
slab(28, 38, 20, 20, BODY, 23, 24);
// Barrel, gas block and muzzle.
slab(38, 45, 16, 17, STEEL, 23, 24);
slab(40, 41, 15, 19, BODY, 23, 24);
slab(44, 46, 15, 18, DARK, 22, 25);
// Sights and a carry rail on top.
slab(15, 26, 21, 21, BODY, 23, 24);
slab(15, 17, 22, 24, DARK, 23, 24);
slab(40, 41, 20, 23, DARK, 23, 24);
slab(19, 24, 22, 23, STEEL, 23, 24);
// Pistol grip, leaning back.
for (let z = 3; z <= 12; z++) {
const x0 = Math.round(14 - (12 - z) * 0.3);
for (let x = x0; x <= x0 + 3; x++) for (let y = 22; y <= 25; y++) set(x, y, z, shade(DARK, z, 3, 12));
}
// Trigger guard and trigger.
for (let x = 18; x <= 21; x++) for (let y = 23; y <= 24; y++) set(x, y, 10, DARK[1]);
for (let z = 10; z <= 12; z++) for (let y = 23; y <= 24; y++) set(21, y, z, DARK[1]);
set(19, 23, 11, STEEL[1]); set(19, 24, 11, STEEL[1]); set(19, 23, 12, STEEL[1]); set(19, 24, 12, STEEL[1]);
// Magazine: curved forward, down to the floor.
for (let z = 0; z <= 12; z++) {
const lean = Math.round(Math.pow((12 - z) / 12, 1.6) * 5);
for (let x = 23 + lean; x <= 27 + lean; x++) for (let y = 22; y <= 25; y++) set(x, y, z, z % 3 === 1 && (y === 22 || y === 25) ? STEEL[0] : shade(BODY, z, 0, 12));
}
// A sling loop at the butt.
set(4, 22, 12, STEEL[1]); set(4, 25, 12, STEEL[1]);import { draw } from "./assets/voxel";
import { serviceRifle } from "./assets/service-rifle";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, serviceRifle, 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 service-rifle
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["service-rifle"] })
# Queda en client/assets/service-rifle.ts
# https://fogon.gg/object/service-rifle