← Ancient and prehistory3D assetfogon/town-wall
Muralla con almenas
Drag to turn it// «Muralla con almenas» · propio
// A straight section of sandstone town wall: big blocks with mortar lines, a darker foot, a pale band near the top and a row of square merlons.
// A straight section of sandstone town wall: big blocks, a darker foot, a pale band and square merlons.
const stone = ["#a37c4b", "#b38c57", "#c19a64", "#cda870", "#d8b57e"];
const footStone = ["#806038", "#8f6d42", "#9c794c"];
const mortar = "#84653c";
const trim = ["#d4bd8c", "#e0cb9c", "#ebd8ad", "#f2e2bd"];
const clampi = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
const X0 = 2, X1 = 45, Y0 = 19, Y1 = 28, TOP = 27;
const hash = (a, b) => {
const s = Math.sin(a * 12.9898 + b * 78.233) * 43758.5453;
return s - Math.floor(s);
};
function blockAt(u, z, tones, base) {
const row = Math.floor(z / 4);
const len = 8 + (row % 3);
const shift = (row % 2) * 4 + ((row * 5) % 3);
const k = Math.floor((u + shift) / len);
if (z % 4 === 3 || (u + shift) % len === 0) return mortar;
let tone = base + Math.floor(hash(k, row) * 3);
if (rand() < 0.12) tone--;
return tones[clampi(tone, 0, tones.length - 1)];
}
// The wall.
for (let x = X0; x <= X1; x++)
for (let y = Y0; y <= Y1; y++)
for (let z = 0; z <= TOP; z++) {
const u = x === X0 || x === X1 ? y + 2 : x;
set(x, y, z, blockAt(u, z, stone, z > 16 ? 2 : 1));
}
// The foot: darker, a block wider.
for (let x = X0 - 1; x <= X1 + 1; x++)
for (let y = Y0 - 1; y <= Y1 + 1; y++)
for (let z = 0; z <= 5; z++) {
const u = x < X0 || x > X1 ? y + 2 : x + 3;
const c = blockAt(u, z, footStone, 0);
set(x, y, z, z === 5 ? footStone[2] : c);
}
// The pale band.
for (let x = X0 - 1; x <= X1 + 1; x++)
for (let y = Y0 - 1; y <= Y1 + 1; y++)
for (let z = TOP - 3; z <= TOP - 2; z++) set(x, y, z, (x + 5) % 11 === 0 ? "#bfa878" : trim[clampi((z === TOP - 2 ? 2 : 1) - (rand() < 0.15 ? 1 : 0), 0, 3)]);
// The walk on top and the merlons along its front and back edges.
for (let x = X0; x <= X1; x++) for (let y = Y0; y <= Y1; y++) set(x, y, TOP, stone[clampi(3 - (rand() < 0.2 ? 1 : 0), 0, 4)]);
for (let x = X0; x <= X1; x++) {
const m = (x - X0) % 8;
if (m > 4) continue;
for (const y of [Y0, Y0 + 1, Y1 - 1, Y1])
for (let z = TOP + 1; z <= TOP + 6; z++) {
let tone = z >= TOP + 5 ? 3 : 2;
if (m === 0 || m === 4) tone--;
if (rand() < 0.12) tone--;
set(x, y, z, z === TOP + 6 ? trim[clampi(tone - 1, 0, 3)] : stone[clampi(tone + 1, 0, 4)]);
}
}
// An arrow slit in the middle.
box(23, Y0, 13, 24, Y0, 20, "#2a1d12");
box(22, Y0, 16, 25, Y0, 17, "#2a1d12");import { draw } from "./assets/voxel";
import { townWall } from "./assets/town-wall";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, townWall, 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 town-wall
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["town-wall"] })
# It lands in client/assets/town-wall.ts
# https://fogon.gg/object/town-wall