← Weapons3D assetfogon/soldier-blue
Soldado azul
Drag to turn it// «Soldado azul» · propio
// A chunky blocky toy soldier of the blue team: blue jacket and blue cap, black trousers and boots, a dark vest with pouches, skin-coloured face and hands, holding a short black rifle across the chest.
// A chunky blocky toy soldier of the blue team: team jacket and cap, black trousers and boots, a dark vest with pouches,
// skin face and hands, and a short black rifle held across the chest. Faces the front (-y). The legs walk.
const TEAM = ["#1b3f7d", "#24529c", "#3068bb", "#4b85d6"];
const skin = ["#c98d63", "#dca377", "#eab78c", "#f3c8a0"];
const hair = ["#2e2118", "#3d2c20"];
const vest = ["#353a2e", "#444a3b", "#535a48", "#636b55"];
const cloth = ["#141518", "#1d1f23", "#27292e", "#32353b"];
const boot = ["#0c0c0e", "#151517", "#222226"];
const gun = ["#101114", "#191a1e", "#25272c", "#3a3d44"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
// The torso: the jacket, lighter at the shoulders, with a collar.
for (let x = 15; x <= 32; x++)
for (let y = 20; y <= 27; y++)
for (let z = 14; z <= 28; z++) {
if (z === 28 && (x === 15 || x === 32)) continue;
let tone = 1 + (z >= 26 ? 1 : 0) + (y === 20 && z > 20 ? 1 : 0) - (z < 17 ? 1 : 0) - (rand() < 0.06 ? 1 : 0);
set(x, y, z, TEAM[clampi(tone, 0, 3)]);
}
box(20, 19, 27, 27, 19, 28, TEAM[3]);
box(22, 19, 28, 25, 19, 28, skin[1]);
// The belt.
box(15, 20, 14, 32, 27, 15, cloth[1]);
box(15, 19, 14, 32, 19, 15, "#3a2c1c");
box(22, 18, 14, 25, 18, 15, "#b9963c");
// The vest: a dark plate front and back, straps over the shoulders and three pouches at the waist.
box(17, 19, 16, 30, 19, 26, vest[1]);
box(17, 28, 16, 30, 28, 26, vest[1]);
for (const x of [17, 18, 29, 30]) box(x, 19, 27, x, 28, 29, vest[2]);
for (let x = 17; x <= 30; x++) for (let z = 16; z <= 26; z++) if ((z === 21 || z === 24) && rand() < 0.9) set(x, 19, z, vest[0]);
for (const px of [17, 22, 27]) {
box(px, 18, 16, px + 3, 18, 19, vest[2]);
box(px, 18, 20, px + 3, 18, 20, vest[3]);
set(px + 1, 17, 19, vest[0]);
set(px + 2, 17, 19, vest[0]);
}
box(19, 29, 17, 28, 29, 23, vest[2]);
box(19, 29, 24, 28, 29, 24, vest[3]);
// The head: skin, with eyes, a mouth and hair at the back and the sides.
for (let x = 17; x <= 30; x++)
for (let y = 17; y <= 28; y++)
for (let z = 29; z <= 39; z++) {
const corner = (x === 17 || x === 30) && (y === 17 || y === 28);
if (corner && (z === 29 || z === 39)) continue;
const hairy = z >= 32 && (y >= 26 || ((x <= 17 || x >= 30) && y >= 23)) || z >= 38;
let tone = 2 + (z > 35 ? 1 : 0) - (z < 31 ? 1 : 0) + (x === 17 ? 1 : 0);
set(x, y, z, hairy ? hair[z > 35 ? 1 : 0] : skin[clampi(tone, 0, 3)]);
}
for (const ex of [20, 26]) {
box(ex, 17, 34, ex + 1, 17, 35, "#241a15");
set(ex, 17, 35, "#f5f1e8");
box(ex - 1, 17, 37, ex + 2, 17, 37, hair[0]);
}
box(22, 17, 31, 25, 17, 31, "#a8654c");
box(23, 16, 32, 24, 16, 33, skin[1]);
for (const [ex, tone] of [[16, 3], [31, 1]]) box(ex, 22, 33, ex, 23, 35, skin[tone]);
// The cap: a flat crown with a brim to the front.
for (let x = 16; x <= 31; x++)
for (let y = 16; y <= 29; y++)
for (let z = 40; z <= 43; z++) {
if (z === 43 && (x < 18 || x > 29 || y < 18 || y > 27)) continue;
set(x, y, z, z === 40 ? TEAM[0] : TEAM[clampi(1 + (z === 43 ? 2 : 0) + (z === 42 && (x === 16 || y === 16) ? 1 : 0) - (rand() < 0.06 ? 1 : 0), 0, 3)]);
}
box(18, 13, 40, 29, 15, 40, TEAM[1]);
box(18, 13, 39, 29, 13, 39, TEAM[0]);
box(22, 15, 41, 25, 15, 42, "#d8c27a");
// The arms: sleeves down from the shoulders, forearms bent in to the rifle.
for (const [x0, x1, lit] of [[11, 14, 1], [33, 36, 0]])
for (let x = x0; x <= x1; x++)
for (let y = 21; y <= 26; y++)
for (let z = 20; z <= 28; z++) {
if (z === 28 && (x === 11 || x === 36)) continue;
set(x, y, z, TEAM[clampi(1 + (z >= 26 ? 1 : 0) + (x === 11 ? lit : 0) - (z < 22 ? 1 : 0), 0, 3)]);
}
line(12.5, 21, 21, 17.5, 18, 20.5, 1.7, TEAM[2]);
line(34.5, 21, 22, 30.5, 18, 25, 1.7, TEAM[1]);
// The rifle, across the chest: the stock down at one side, the muzzle up at the other.
const rz = (x) => 17 + (x - 11) * 0.42;
for (let x = 11; x <= 37; x++) {
const z0 = Math.round(rz(x));
let lo = 0, hi = 2, tones = gun, base = 1;
if (x <= 16) { lo = -1; hi = 2; base = 1; }
else if (x <= 24) { base = 2; }
else if (x <= 31) { base = 1; }
else { lo = 1; hi = 1; base = 2; }
for (let z = z0 + lo; z <= z0 + hi; z++)
for (const y of [16, 17]) {
let tone = base + (z === z0 + hi && y === 16 ? 1 : 0) - (y === 17 ? 1 : 0);
if (x > 24 && x <= 31 && (x % 2 === 0) && z === z0 + 1) tone--;
if (x === 11) tone = 0;
set(x, y, z, tones[clampi(tone, 0, 3)]);
}
}
// (the magazine, curved forward; a sight on top; the front sight)
for (let k = 1; k <= 6; k++) {
const x = 21 + Math.round(k * 0.35), z = Math.round(rz(21)) - k;
for (const y of [16, 17]) for (let i = 0; i < 3; i++) set(x + i, y, z, gun[clampi((y === 16 ? 1 : 0) + (i === 0 ? 1 : 0), 0, 3)]);
}
box(19, 16, Math.round(rz(19)) + 3, 21, 17, Math.round(rz(19)) + 3, gun[3]);
box(34, 16, Math.round(rz(34)) + 2, 34, 17, Math.round(rz(34)) + 3, gun[1]);
// The hands, closed over it.
for (const hx of [17, 29]) {
const z0 = Math.round(rz(hx + 1));
for (let x = hx; x <= hx + 2; x++) for (let z = z0 - 1; z <= z0 + 2; z++) for (const y of [15, 16, 17, 18]) if (y === 15 || z === z0 - 1 || z === z0 + 2 || y === 18) set(x, y, z, skin[clampi(2 + (z === z0 + 2 ? 1 : 0) - (z === z0 - 1 ? 1 : 0), 0, 3)]);
for (let z = z0; z <= z0 + 1; z++) set(hx + 1, 15, z, skin[1]);
}
// The legs: black trousers and boots. Each one swings from the hip.
function leg(x0) {
for (let x = x0; x <= x0 + 6; x++)
for (let y = 20; y <= 27; y++)
for (let z = 4; z <= 13; z++) {
let tone = 1 + (y === 20 && z >= 8 && z <= 9 ? 1 : 0) + (x === x0 ? 1 : 0) - (z < 6 ? 1 : 0) - (rand() < 0.08 ? 1 : 0);
set(x, y, z, cloth[clampi(tone, 0, 3)]);
}
for (let x = x0; x <= x0 + 6; x++)
for (let y = 17; y <= 27; y++)
for (let z = 0; z <= 4; z++) {
if (y < 20 && z > 2) continue;
if (z === 4 && y > 20 && false) continue;
set(x, y, z, z === 0 ? "#3a3a3f" : boot[clampi(1 + (y < 20 && z === 2 ? 1 : 0) + (x === x0 ? 1 : 0) - (z === 1 ? 1 : 0), 0, 2)]);
}
box(x0 + 2, 19, 3, x0 + 4, 19, 4, "#3a3a3f");
}
part("left_leg", [19, 24, 14]);
leg(16);
part("right_leg", [28, 24, 14]);
leg(25);
animate("left_leg", { type: "swing", axis: "x", speed: 5, amplitude: 0.4 });
animate("right_leg", { type: "swing", axis: "x", speed: -5, amplitude: 0.4 });import { draw } from "./assets/voxel";
import { soldierBlue } from "./assets/soldier-blue";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, soldierBlue, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: its longest side, in px
// angle: turn on the floor, in radians
// t: seconds; if it moves, that animates it# In a terminal, in the game's folder
fogon assets add soldier-blue
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["soldier-blue"] })
# It lands in client/assets/soldier-blue.ts
# https://fogon.gg/object/soldier-blue