← BásicoObjeto 3Dfogon/molino-de-viento
Molino de viento
Arrastrá para girarlo// «Molino de viento» · gpt-6-sol (medium)
// Windmill («Molino de viento»).
const grass = ["#76a649", "#83af52", "#8bb85a", "#6e9d43"];
const stone = ["#d4ccb1", "#ddd5bc", "#e8dfc8", "#c6bda4"];
const roof = ["#a44730", "#b45134", "#c05a39", "#913d2c"];
// Low, irregular grassy island.
for (let x = 3; x <= 45; x++) {
for (let y = 4; y <= 44; y++) {
const d = ((x - 24) / 20) ** 2 + ((y - 24) / 18) ** 2;
if (d < 1 + (rand() - 0.5) * 0.075) {
set(x, y, 0, rand() < 0.3 ? "#665539" : "#594a32");
set(x, y, 1, rand() < 0.3 ? "#796641" : "#675537");
set(x, y, 2, grass[Math.floor(rand() * grass.length)]);
if (rand() < 0.09) set(x, y, 3, "#91b85c");
}
}
}
// A few exposed stones around the rim.
for (let i = 0; i < 60; i++) {
const a = rand() * Math.PI * 2;
const x = Math.round(24 + Math.cos(a) * (18 + rand()));
const y = Math.round(24 + Math.sin(a) * (16 + rand()));
if (get(x, y, 1)) set(x, y, 1, rand() < 0.5 ? "#806d4d" : "#9a8260");
}
// Cream-colored, slightly tapering masonry tower.
for (let z = 3; z <= 30; z++) {
const inset = z >= 22 ? 2 : z >= 12 ? 1 : 0;
const x0 = 17 + inset, x1 = 31 - inset;
const y0 = 18 + inset, y1 = 32 - inset;
for (let x = x0; x <= x1; x++) {
for (let y = y0; y <= y1; y++) {
let c = stone[rand() < 0.12 ? Math.floor(rand() * stone.length) : 0];
if (z % 7 === 3 && (x === x0 || x === x1 || y === y0 || y === y1)) c = "#c5bba1";
if (x === x0 || y === y0) c = rand() < 0.2 ? "#e9e1cb" : "#ded5bd";
set(x, y, z, c);
}
}
}
// Raised corner quoins and narrow vertical plaster bands.
for (let z = 4; z <= 29; z++) {
const inset = z >= 22 ? 2 : z >= 12 ? 1 : 0;
const a = 17 + inset, b = 31 - inset, f = 18 + inset, back = 32 - inset;
for (const x of [a, b]) {
set(x, f - 1, z, z % 6 === 0 ? "#f0e7d0" : "#e3dbc4");
set(x, back, z, "#c8bfa8");
}
if (z % 5 === 0) {
for (let x = a + 1; x < b; x++) set(x, f - 1, z, "#e7dec6");
for (let y = f; y <= back; y++) set(b + 1, y, z, "#d0c6aa");
}
}
box(16, 17, 3, 32, 33, 4, "#bcb39a");
box(17, 17, 5, 31, 18, 5, "#e4dac1");
// Small dark timber door, recessed into the front wall.
box(21, 16, 4, 27, 18, 13, "#e8dfc5");
box(22, 15, 4, 26, 17, 12, "#614a30");
for (let x = 22; x <= 26; x++) {
box(x, 14, 4, x, 14, 11, x % 2 ? "#795738" : "#8a6340");
}
box(21, 14, 12, 27, 16, 13, "#c5b99e");
set(25, 13, 8, "#d4b36c");
box(21, 14, 4, 21, 15, 12, "#eee5d0");
box(27, 14, 4, 27, 15, 12, "#eee5d0");
// Narrow upper window and side window with chunky pale surrounds.
box(22, 17, 18, 26, 19, 24, "#eee5cf");
box(23, 16, 19, 25, 17, 23, "#584f3d");
box(24, 15, 19, 24, 15, 23, "#ae9166");
box(22, 15, 18, 26, 16, 18, "#e9dec5");
box(22, 15, 24, 26, 16, 24, "#e9dec5");
box(30, 23, 17, 32, 27, 22, "#e6dcc3");
box(32, 24, 18, 32, 26, 21, "#6e6854");
box(33, 25, 18, 33, 25, 21, "#c5a878");
box(32, 23, 17, 33, 27, 17, "#c8bda3");
// Steep stepped roof of red clay tiles.
for (let z = 30; z <= 38; z++) {
const step = z - 30;
const x0 = 14 + step, x1 = 34 - step;
const y0 = 15 + step, y1 = 35 - step;
for (let x = x0; x <= x1; x++) {
for (let y = y0; y <= y1; y++) {
const edge = x === x0 || x === x1 || y === y0 || y === y1;
let c = roof[(x + y + z) % 3];
if (edge || z % 2 === 0) c = roof[(x + 2 * y + z) % 4];
if (rand() < 0.07) c = "#d06a42";
set(x, y, z, c);
}
}
}
for (let x = 14; x <= 34; x++) {
set(x, 14, 30, "#713b2b");
set(x, 35, 30, "#713b2b");
}
for (let y = 15; y <= 34; y++) {
set(14, y, 30, "#813d2b");
set(34, y, 30, "#813d2b");
}
// Little black roof finial.
box(23, 24, 39, 25, 26, 39, "#724631");
box(24, 25, 40, 24, 25, 43, "#343832");
set(24, 25, 44, "#bb9856");
// Fence behind and to the left of the mill.
for (const x of [7, 12, 17]) {
box(x, 32, 3, x, 32, 10, "#765135");
set(x, 32, 11, "#ac7d4c");
}
for (const z of [6, 9]) {
line(7, 32, z, 17, 32, z, 0, z === 9 ? "#a77948" : "#805735");
}
// Pale stepping-stone path leading to the door.
for (let y = 6; y <= 15; y += 2) {
const cx = 24 + Math.round((15 - y) * 0.42);
box(cx - 2, y, 3, cx + 1, y + 1, 3, "#c7c2aa");
set(cx - 1, y, 4, "#e1dcc6");
if (y > 8) set(cx + 1, y + 1, 4, "#ded9c1");
}
// Bushes: small blocky green clumps and warm brown stems.
function bush(x, y, h) {
box(x, y, 3, x + 1, y + 1, 3 + h, "#648b3b");
box(x - 2, y, 4, x + 2, y + 2, 4 + h, "#659841");
box(x - 1, y - 1, 5, x + 2, y + 1, 5 + h, "#82ab4c");
box(x, y, 5 + h, x + 1, y + 1, 5 + h, "#9abf62");
set(x - 2, y, 5, "#a6bf66");
set(x + 2, y + 2, 5, "#496f34");
}
bush(8, 19, 1);
bush(37, 26, 1);
bush(12, 12, 0);
box(14, 27, 3, 15, 28, 5, "#588840");
set(14, 27, 6, "#a5c568");
// Four fixed diagonal wooden sails. Their open slats make the blades
// distinct from the masonry and let the tower show through them.
const sails = [
[ 1, 1, 16],
[-1, 1, 12],
[-1, -1, 16],
[ 1, -1, 13]
];
for (const [dx, dz, length] of sails) {
const px = -dz, pz = dx;
for (let i = 3; i <= length; i++) {
const x = 24 + dx * i, z = 27 + dz * i;
// Heavy central spar and the parallel outside rail.
set(x, 12, z, "#64482e");
set(x, 11, z, i % 4 === 0 ? "#b28751" : "#8d633a");
const width = i > length - 2 ? 1 : i < 6 ? 2 : 3;
for (let t = 1; t <= width; t++) {
const sx = x + px * t, sz = z + pz * t;
if (t === width) {
set(sx, 12, sz, "#64492e");
set(sx, 11, sz, "#a27643");
} else if (i % 3 !== 1) {
set(sx, 12, sz, (i + t) % 3 === 0 ? "#b68b55" : "#8f6a40");
}
}
// Bright transverse braces at regular intervals.
if (i % 3 === 0 && i < length - 1) {
for (let t = 0; t <= width; t++) {
set(x + px * t, 10, z + pz * t, "#c0985d");
}
}
}
const tx = 24 + dx * length, tz = 27 + dz * length;
set(tx, 11, tz, "#aa7944");
set(tx + dx, 12, tz + dz, "#674a30");
}
// Short axle, dark socket, and prominent pale metal hub.
box(23, 11, 26, 25, 14, 28, "#634d35");
for (let x = 22; x <= 26; x++) {
for (let z = 25; z <= 29; z++) {
if ((x - 24) ** 2 + (z - 27) ** 2 <= 6) {
set(x, 9, z, "#b5b4a1");
if (x === 22 || z === 29) set(x, 9, z, "#e2ddc8");
}
}
}
box(23, 8, 26, 25, 8, 28, "#d5d3be");
set(24, 7, 27, "#8f9486");
set(24, 6, 27, "#d0ceba");import { draw } from "./assets/voxel";
import { molinoDeViento } from "./assets/molino-de-viento";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, molinoDeViento, 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 molino-de-viento
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["molino-de-viento"] })
# Queda en client/assets/molino-de-viento.ts
# https://fogon.page/object/molino-de-viento