← MedievalObjeto 3Dfogon/torre-de-vigia
Torre de vigía
Arrastrá para girarlo// «Torre de vigía» · gpt-6-sol (medium)
// A tall wooden watchtower: four thick log legs with diagonal cross braces rising to a square plank platform with a log railing, topped by a small pointed thatched roof on four posts, a wooden ladder climbing one side, and a small red pennant on a pole at the very top. Much taller than wide.
const timber = "#573824";
const timberLight = "#795032";
const timberDark = "#39271e";
const iron = "#282b2b";
const stone = ["#827e71", "#999386", "#6d6b62"];
const straw = ["#bc904f", "#cba462", "#a77c42", "#d5b370"];
function log(x0, y0, z0, x1, y1, z1) {
box(x0, y0, z0, x1, y1, z1, timber);
line(x0, y0, z0, x1, y1, z1, 0, timberLight);
}
// Four stone footings and heavy upright logs.
for (const x of [14, 33]) {
for (const y of [14, 33]) {
box(x - 2, y - 2, 0, x + 2, y + 2, 2, stone[0]);
for (let i = 0; i < 14; i++) {
set(x - 2 + Math.floor(rand() * 5),
y - 2 + Math.floor(rand() * 5),
Math.floor(rand() * 3),
rand() < 0.18 ? "#69715a" : stone[1 + Math.floor(rand() * 2)]);
}
box(x - 1, y - 1, 2, x + 1, y + 1, 30, timber);
box(x - 1, y - 1, 3, x - 1, y - 1, 29, timberLight);
for (const z of [5, 17, 28]) {
box(x - 1, y - 1, z, x + 1, y + 1, z, iron);
set(x, y - 2, z, "#9d9375");
}
}
}
// Diagonal cross-bracing on all four open sides.
for (const y of [14, 33]) {
line(15, y, 7, 32, y, 24, 1, timberDark);
line(32, y, 7, 15, y, 24, 1, timberLight);
line(15, y, 25, 32, y, 8, 0, timber);
}
for (const x of [14, 33]) {
line(x, 15, 8, x, 32, 25, 1, timberDark);
line(x, 32, 8, x, 15, 25, 1, timberLight);
}
// Stout beams immediately beneath the lookout floor.
for (const y of [13, 24, 34]) log(12, y, 28, 36, y, 28);
for (const x of [13, 24, 34]) log(x, 12, 28, x, 36, 28);
// Broad plank platform, with individually readable boards.
box(10, 10, 29, 38, 38, 29, timberDark);
for (let y = 10; y <= 38; y += 2) {
box(10, y, 30, 38, Math.min(y + 1, 38), 30,
y % 4 === 2 ? "#a57848" : "#93673e");
for (let x = 12; x <= 37; x += 8) {
set(x, y, 30, "#6e492f");
}
}
for (const y of [10, 38]) box(10, y, 29, 38, y, 31, timberDark);
for (const x of [10, 38]) box(x, 10, 29, x, 38, 31, timberDark);
for (let x = 13; x <= 36; x += 5) {
for (const y of [9, 39]) set(x, y, 30, "#a49a78");
}
// Railing, leaving an opening at the front for the ladder.
for (const x of [12, 18, 30, 36]) {
box(x, 11, 31, x + 1, 12, 35, timber);
box(x, 36, 31, x + 1, 37, 35, timber);
}
for (const y of [18, 25, 32]) {
box(11, y, 31, 12, y + 1, 35, timber);
box(36, y, 31, 37, y + 1, 35, timber);
}
for (const z of [32, 35]) {
for (const y of [11, 37]) {
box(13, y, z, 20, y, z, timberLight);
box(28, y, z, 35, y, z, timberLight);
if (y === 37) box(21, y, z, 27, y, z, timberLight);
}
for (const x of [11, 37]) box(x, 13, z, x, 35, z, timberLight);
}
// Four roof-supporting posts, above the railing.
for (const x of [13, 35]) {
for (const y of [13, 35]) {
box(x - 1, y - 1, 31, x + 1, y + 1, 37, timberDark);
box(x - 1, y - 1, 33, x - 1, y - 1, 37, timberLight);
box(x - 1, y - 1, 35, x + 1, y + 1, 35, iron);
}
}
// Sloping ladder on the front, anchored at the platform opening.
for (let z = 1; z <= 31; z++) {
const y = 5 + Math.round(z * 6 / 31);
for (const x of [21, 27]) {
set(x, y, z, timberDark);
set(x, y - 1, z, timberLight);
}
if (z >= 2 && z <= 29 && z % 3 === 2) {
box(22, y - 1, z, 26, y, z, "#a77a49");
set(23, y - 1, z, "#c09257");
}
}
// Dark rafters under the overhanging thatch.
for (const y of [11, 24, 37]) log(10, y, 36, 38, y, 36);
for (const x of [11, 24, 37]) log(x, 10, 36, x, 38, 36);
// Layered, pointed thatched roof.
const roofLayers = [
[37, 9, 39], [38, 11, 37], [39, 14, 34],
[40, 17, 31], [41, 20, 28], [42, 22, 26], [43, 24, 24]
];
for (const [z, lo, hi] of roofLayers) {
for (let x = lo; x <= hi; x++) {
for (let y = lo; y <= hi; y++) {
const edge = Math.min(x - lo, hi - x, y - lo, hi - y);
let color = straw[(Math.floor(x / 4) + Math.floor(y / 5) + z) % straw.length];
if (edge === 0 && rand() < 0.55) color = "#957044";
if (rand() < 0.09) color = "#dfbb76";
set(x, y, z, color);
if (edge === 0 && z < 41 && rand() < 0.25) {
set(x, y, z - 1, "#aa7d42");
}
}
}
}
// Finial and flagpole.
box(24, 24, 43, 24, 24, 45, iron);
set(24, 24, 45, "#d6b966");
// The pennant turns gently around the pole.
part("pennant", [24, 24, 44]);
for (let x = 25; x <= 33; x++) {
const tip = x >= 31;
set(x, 24, 44, x % 3 === 0 ? "#911f2a" : "#b62c35");
if (!tip) set(x, 24, 43, "#801f2a");
}
for (let x = 25; x <= 29; x++) set(x, 23, 44, "#cc994c");
set(28, 23, 43, "#e3bb64");
set(29, 23, 43, "#e3bb64");
animate("pennant", { type: "swing", axis: "z", speed: 3, amplitude: 0.3 });
part("body", [24, 24, 0]);import { draw } from "./assets/voxel";
import { torreDeVigia } from "./assets/torre-de-vigia";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, torreDeVigia, 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 torre-de-vigia
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["torre-de-vigia"] })
# Queda en client/assets/torre-de-vigia.ts
# https://fogon.page/object/torre-de-vigia