← Monstruos y enemigosObjeto 3Dfogon/gargola
Gárgola
Arrastrá para girarlo// «Gárgola» · gpt-6-sol (medium)
// A crouching cartoon stone gargoyle on a small stone pedestal, facing -y: grey stone with darker cracks and moss spots, a grinning face with horns and glowing blue eyes, pointed ears, clawed hands on its knees, and two bat wings folded up behind its back.
const stone = ["#626c73", "#79848a", "#929da0"];
const dark = "#465158";
const light = "#adb8b8";
const moss = "#577d62";
function rocky(cx, cy, cz, rx, ry, rz) {
for (let x = Math.floor(cx - rx); x <= Math.ceil(cx + rx); x++)
for (let y = Math.floor(cy - ry); y <= Math.ceil(cy + ry); y++)
for (let z = Math.floor(cz - rz); z <= Math.ceil(cz + rz); z++) {
const d = ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2 + ((z - cz) / rz) ** 2;
if (d > 1) continue;
let c = z < cz - rz * 0.35 ? stone[0] : z > cz + rz * 0.35 ? stone[2] : stone[1];
if (rand() < 0.055) c = rand() < 0.5 ? stone[0] : stone[2];
set(x, y, z, c);
}
}
// Low, beveled display pedestal.
box(8, 10, 0, 40, 38, 1, "#48545b");
box(9, 11, 2, 39, 37, 3, "#68747a");
box(11, 13, 4, 37, 35, 5, "#929c9e");
box(11, 13, 4, 37, 13, 4, "#b2bbbb");
box(11, 35, 4, 37, 35, 4, "#58646b");
for (let i = 0; i < 45; i++) {
const x = 11 + Math.floor(rand() * 27);
const y = 13 + Math.floor(rand() * 23);
set(x, y, 5, rand() < 0.28 ? moss : "#818e90");
}
// Each folded bat wing is a separate moving part.
function inside(poly, x, z) {
let hit = false;
for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {
const a = poly[i], b = poly[j];
if ((a[1] > z) !== (b[1] > z) &&
x < (b[0] - a[0]) * (z - a[1]) / (b[1] - a[1]) + a[0]) hit = !hit;
}
return hit;
}
function wing(side) {
const mirror = x => side < 0 ? x : 48 - x;
const poly = [
[17, 27], [15, 34], [11, 43], [9, 39],
[6, 41], [7, 34], [4, 32], [7, 28],
[10, 29], [9, 24], [14, 27]
];
part(side < 0 ? "leftWing" : "rightWing",
[side < 0 ? 17 : 31, 31, 28]);
for (let x = 4; x <= 17; x++)
for (let z = 23; z <= 43; z++) {
if (!inside(poly, x + 0.5, z + 0.5)) continue;
const edge = !inside(poly, x - 0.5, z + 0.5) ||
!inside(poly, x + 1.5, z + 0.5) ||
!inside(poly, x + 0.5, z - 0.5) ||
!inside(poly, x + 0.5, z + 1.5);
for (let y = 32; y <= 33; y++)
set(mirror(x), y, z,
edge ? dark : rand() < 0.17 ? "#75818b" : "#66727d");
}
// Raised ribs make the wing shape legible from the front.
for (const [x, z] of [[11, 43], [6, 41], [4, 32], [9, 24]]) {
line(mirror(17), 31, 28, mirror(x), 31, z, 0, "#9aa5a7");
}
line(mirror(11), 31, 43, mirror(6), 31, 41, 0, dark);
line(mirror(6), 31, 41, mirror(4), 31, 32, 0, dark);
animate(side < 0 ? "leftWing" : "rightWing",
{ type: "swing", axis: "y", speed: side < 0 ? 2 : -2, amplitude: 0.3 });
}
wing(-1);
wing(1);
part("body");
// Haunches and enormous planted feet.
rocky(17, 20, 14, 6, 7, 7);
rocky(31, 20, 14, 6, 7, 7);
rocky(16, 17, 8, 5, 7, 3);
rocky(32, 17, 8, 5, 7, 3);
for (const x of [13, 16, 19, 29, 32, 35]) {
box(x, 10, 6, x + 1, 14, 8, stone[2]);
set(x, 9, 6, light);
}
rocky(24, 25, 23, 9, 8, 10);
rocky(24, 18, 21, 7, 4, 7);
box(20, 14, 18, 28, 15, 18, "#687773");
// Shoulders, bent arms, and hands resting on the knees.
for (const side of [-1, 1]) {
const shoulder = side < 0 ? 16 : 32;
const elbow = side < 0 ? 12 : 36;
const hand = side < 0 ? 17 : 31;
rocky(shoulder, 22, 27, 4, 5, 5);
line(shoulder, 19, 26, elbow, 17, 19, 3, stone[0]);
line(elbow, 17, 19, hand, 13, 17, 2, stone[1]);
rocky(hand, 13, 17, 3, 3, 2);
for (let i = -2; i <= 2; i += 2) {
const fx = hand + i;
line(fx, 11, 17, fx, 9, 15, 1, stone[2]);
set(fx, 9, 14, light);
}
}
// Oversized head, pointed ears, and swept horns.
rocky(24, 19, 32, 10, 8, 8);
for (const side of [-1, 1]) {
const ear = side < 0
? [[15, 34], [9, 40], [10, 33], [14, 30]]
: [[33, 34], [39, 40], [38, 33], [34, 30]];
for (let x = side < 0 ? 9 : 33; x <= (side < 0 ? 15 : 39); x++)
for (let z = 30; z <= 40; z++)
if (inside(ear, x + 0.5, z + 0.5))
for (let y = 17; y <= 20; y++)
set(x, y, z, y === 17 ? stone[2] : stone[0]);
const hx = side < 0 ? 18 : 30;
line(hx, 17, 38, hx + side * 2, 17, 42, 2, stone[0]);
line(hx + side * 2, 17, 42, hx + side * 4, 17, 44, 1, light);
}
// Cheeks and a broad, friendly toothy grin.
rocky(19, 13, 29, 4, 3, 3);
rocky(29, 13, 29, 4, 3, 3);
box(20, 10, 27, 28, 12, 30, stone[1]);
box(22, 9, 30, 26, 10, 31, stone[2]);
box(20, 9, 27, 28, 9, 28, "#303c46");
set(19, 10, 28, dark);
set(29, 10, 28, dark);
for (const x of [21, 23, 25, 27]) set(x, 8, 28, "#d3d7cc");
set(24, 8, 27, "#819098");
// Heavy brows frame bright cyan eyes.
for (const x of [19, 29]) {
box(x - 2, 11, 33, x + 2, 13, 35, "#35464f");
box(x - 1, 10, 34, x + 1, 10, 35, "#36d9ef");
set(x, 9, 35, "#d1ffff");
line(x - 3, 12, 37, x + 2, 12, 37, 1, stone[0]);
}
// A few deliberately placed cracks and moss flecks.
line(15, 12, 33, 17, 11, 31, 0, "#3e4c53");
line(17, 11, 31, 16, 12, 29, 0, "#3e4c53");
line(31, 13, 38, 33, 14, 36, 0, "#49565c");
line(23, 15, 18, 25, 15, 16, 0, "#48565c");
for (const [x, y, z] of [
[13, 17, 20], [14, 16, 21], [34, 17, 21],
[35, 17, 20], [16, 12, 14], [32, 12, 13],
[18, 13, 38], [30, 13, 39], [22, 15, 25]
]) set(x, y, z, moss);import { draw } from "./assets/voxel";
import { gargola } from "./assets/gargola";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, gargola, 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 gargola
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["gargola"] })
# Queda en client/assets/gargola.ts
# https://fogon.page/object/gargola