← MedievalObjeto 3Dfogon/puente-levadizo
Puente levadizo
Arrastrá para girarlo// «Puente levadizo» · gpt-6-sol (medium)
// A castle gatehouse with a drawbridge: a thick grey stone front wall with crenellations on top and two square towers on the sides, a tall dark arched opening in the middle, two black iron chains running from holes above the arch down to the outer end of a thick plank drawbridge made of dark brown boards with iron bands, hinged at the bottom of the arch and lowered over a strip of blue moat water in front. The drawbridge deck is the moving part.
const stone = ["#827f75", "#918d82", "#a19b8d", "#ada799"];
const mortar = "#696961";
const iron = "#25282b";
const ironEdge = "#505356";
function masonry(x, y, z, front) {
let c = stone[Math.floor(rand() * stone.length)];
if (z < 4 && rand() < 0.45) c = "#74746d";
if (rand() < 0.018 && z < 18) c = "#737d66";
if (front && (z % 5 === 0 || (x + (Math.floor(z / 5) % 2) * 3) % 7 === 0))
c = mortar;
return c;
}
// Shallow blue moat, with broken reflections.
box(3, 4, 0, 45, 25, 0, "#254d68");
for (let x = 3; x <= 45; x++)
for (let y = 4; y <= 25; y++) {
set(x, y, 1, rand() < 0.23 ? "#366c86" : "#2b5872");
if (rand() < 0.045) set(x, y, 1, "#5490a0");
}
for (let i = 0; i < 65; i++) {
const x = 4 + Math.floor(rand() * 40);
const y = 5 + Math.floor(rand() * 19);
if (x < 17 || x > 31)
box(x, y, 2, Math.min(x + 1, 44), y, 2, "#70a5aa");
}
// Stone landing on the viewer's bank.
box(16, 2, 0, 32, 5, 2, "#77776e");
for (let x = 16; x <= 32; x++)
for (let y = 2; y <= 5; y++)
set(x, y, 2, masonry(x, y, 2, y === 2));
// Main curtain wall. Leave a tall, rounded arch clear through its thickness.
function inArch(x, z) {
if (z < 3) return false;
if (z <= 21) return x >= 19 && x <= 29;
const half = ({22: 4, 23: 3, 24: 2, 25: 1, 26: 0})[z];
return half !== undefined && Math.abs(x - 24) <= half;
}
for (let x = 12; x <= 36; x++)
for (let y = 27; y <= 36; y++)
for (let z = 0; z <= 32; z++)
if (!inArch(x, z)) set(x, y, z, masonry(x, y, z, y === 27));
// Dark recess at the far end of the passage; iron portcullis in its shadow.
box(19, 37, 3, 29, 37, 21, "#292520");
for (let x = 20; x <= 28; x += 2) {
box(x, 36, 4, x, 36, 20, iron);
for (let z = 5; z <= 20; z += 4) set(x, 35, z, ironEdge);
}
for (let z of [8, 17]) box(19, 35, z, 29, 35, z, iron);
// Pale, individually legible stones outlining the arch.
for (let z = 3; z <= 21; z++) {
set(18, 26, z, z % 4 === 0 ? "#78766d" : "#c2bbab");
set(30, 26, z, z % 4 === 0 ? "#78766d" : "#c2bbab");
}
for (let z = 22; z <= 27; z++) {
const half = ({22: 5, 23: 4, 24: 3, 25: 2, 26: 1, 27: 0})[z];
for (const x of [24 - half, 24 + half])
box(x, 26, z, x, 27, z, z % 2 ? "#bbb5a6" : "#d0c8b5");
}
box(22, 26, 28, 26, 26, 28, "#c0b7a4");
// Wall walk, darker coping, and chunky alternating battlements.
box(14, 26, 33, 34, 37, 33, "#aaa597");
box(14, 26, 34, 34, 27, 34, "#696b68");
for (let x = 14; x <= 34; x += 5) {
box(x, 26, 35, Math.min(x + 2, 34), 28, 37, "#a8a397");
box(x, 26, 37, Math.min(x + 2, 34), 27, 37, "#c1baaa");
}
// Square, projecting flanking towers.
for (const [a, b] of [[3, 14], [34, 45]]) {
for (let x = a; x <= b; x++)
for (let y = 21; y <= 37; y++)
for (let z = 0; z <= 39; z++)
set(x, y, z, masonry(x, y, z, y === 21));
// Broad corner quoins and bands emphasize the hand-cut masonry.
for (let z = 1; z <= 38; z += 5) {
for (const x of [a, b])
box(x, 20, z, x, 22, z + 2, z % 10 === 1 ? "#c6bdab" : "#aaa596");
}
for (let z of [9, 17, 29, 38])
box(a, 20, z, b, 21, z, z === 38 ? "#c2bba9" : "#77766e");
// Arrow slits, with light stone lintels.
const mid = Math.floor((a + b) / 2);
for (const [lo, hi] of [[12, 17], [24, 30]]) {
box(mid, 20, lo, mid + 1, 21, hi, "#202429");
box(mid - 1, 20, hi + 1, mid + 2, 20, hi + 1, "#c3baaa");
set(mid, 19, lo + 2, "#535453");
}
// Flat slate cap beneath a full square crenellated parapet.
box(a, 21, 40, b, 37, 40, "#454b51");
for (let x = a; x <= b; x++)
for (let y = 21; y <= 37; y++)
if (x === a || x === b || y === 21 || y === 37) {
set(x, y, 41, "#9f9b90");
if ((x === a || x === b ? y : x) % 4 < 2)
box(x, y, 42, x, y, 43, "#b0a999");
}
}
// Heraldic cloth hanging on the two tower faces.
for (const [x, cloth] of [[11, "#922f39"], [36, "#344f94"]]) {
box(x, 19, 18, x + 2, 19, 25, cloth);
box(x, 19, 26, x + 2, 20, 26, "#b99448");
for (let z = 19; z <= 25; z++) {
set(x, 18, z, "#c7a35a");
set(x + 2, 18, z, "#c7a35a");
}
box(x + 1, 18, 21, x + 1, 18, 24, "#e0bd67");
box(x, 18, 22, x + 2, 18, 22, "#e0bd67");
set(x + 1, 19, 17, "#c7a35a");
}
// Small royal pennants above the towers.
for (const [x, color] of [[8, "#a5373f"], [40, "#355ca0"]]) {
box(x, 29, 41, x, 29, 45, "#4a4138");
box(x + 1, 29, 43, x + 4, 29, 44, color);
set(x + 4, 29, 43, null);
box(x + 1, 28, 44, x + 3, 28, 44, "#d3ad5b");
}
// Chain holes and fixed hinge pins.
for (const x of [19, 29]) {
box(x - 1, 25, 26, x + 1, 25, 28, "#514f4c");
set(x, 24, 27, "#17191c");
box(x - 1, 26, 3, x + 1, 27, 5, iron);
set(x, 25, 5, "#77756b");
}
// Two heavy chains, slanting down toward the outer end of the bridge.
for (const x of [19, 29]) {
line(x, 24, 27, x, 7, 7, 0, "#181b1e");
for (let i = 0; i <= 17; i++) {
const y = 24 - i;
const z = Math.round(27 - 20 * i / 17);
set(x, y, z, i % 3 === 0 ? "#727577" : "#303438");
if (i % 2 === 0)
set(x + (x === 19 ? -1 : 1), y, z, "#292d30");
}
}
// The entire plank deck swings from its hinge at the foot of the arch.
part("drawbridge", [24, 26, 4]);
for (let x = 19; x <= 29; x++)
for (let y = 6; y <= 26; y++)
for (let z = 3; z <= 5; z++) {
const seam = x === 21 || x === 24 || x === 27;
const c = seam ? "#39271d" :
rand() < 0.18 ? "#795038" : (z === 5 ? "#68442e" : "#4d3225");
set(x, y, z, c);
}
// Staggered plank joins and warm highlights along the grain.
for (let x = 20; x <= 28; x += 3)
for (let y = 8 + (x % 3); y <= 24; y += 7) {
box(x, y, 5, Math.min(x + 1, 29), y, 5, "#3b281e");
set(x, y + 2, 5, "#9a6540");
}
for (let y of [7, 13, 20, 25]) {
box(19, y, 6, 29, y + 1, 6, iron);
for (let x of [20, 23, 26, 28]) {
set(x, y, 7, "#85837a");
set(x, y + 1, 6, ironEdge);
}
}
// Metal-capped leading edge and chain attachment rings.
box(19, 6, 3, 29, 6, 5, "#303135");
for (const x of [19, 29]) {
box(x, 7, 6, x, 8, 7, "#292c2e");
set(x, 7, 8, "#777a77");
}
animate("drawbridge", {type:"swing", axis:"x", speed:1, amplitude:0.5});import { draw } from "./assets/voxel";
import { puenteLevadizo } from "./assets/puente-levadizo";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, puenteLevadizo, 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 puente-levadizo
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["puente-levadizo"] })
# Queda en client/assets/puente-levadizo.ts
# https://fogon.page/object/puente-levadizo