← Monstruos y enemigosObjeto 3Dfogon/dragon-de-lava
Dragón de lava
Arrastrá para girarlo// «Dragón de lava» · gpt-6-sol (medium)
// A big boss: a huge cartoon lava dragon on four legs, horizontal, head toward -y: black volcanic rock scales with glowing orange-yellow lava cracks, curved horns, burning yellow eyes, an open mouth with a lava glow, big spiked bat wings raised, and a long spiked tail.
const rock = "#25232c", rockLight = "#3b3941", rockDark = "#17151d";
const lava = "#ed571d", hot = "#ffad26", yellow = "#ffe25a";
const membrane = "#81342e", membraneLight = "#a8442d";
function wing(side) {
const X = x => side < 0 ? x : 48 - x;
const name = side < 0 ? "leftWing" : "rightWing";
part(name, [X(16), 24, 27]);
// A scalloped bat-wing silhouette, raised behind the shoulders.
const outline = [
[16, 26], [13, 34], [8, 41], [3, 43], [4, 37],
[8, 35], [6, 30], [12, 32], [11, 26]
];
function inside(x, z) {
let hit = false;
for (let i = 0, j = outline.length - 1; i < outline.length; j = i++) {
const a = outline[i], b = outline[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;
}
for (let x = 3; x <= 16; x++)
for (let z = 26; z <= 43; z++)
if (inside(x + 0.5, z + 0.5)) {
const y = Math.round(24 + (16 - x) * 0.38);
const c = z > 36 ? membraneLight : membrane;
set(X(x), y, z, c);
set(X(x), y + 1, z, "#57282b");
if (rand() < 0.09) set(X(x), y - 1, z, "#d35b28");
}
const rib = (x0, z0, x1, z1) => {
const y0 = Math.round(24 + (16 - x0) * 0.38) - 1;
const y1 = Math.round(24 + (16 - x1) * 0.38) - 1;
line(X(x0), y0, z0, X(x1), y1, z1, 1, rockDark);
line(X(x0), y0 - 1, z0, X(x1), y1 - 1, z1, 0, "#df6428");
};
rib(16, 27, 3, 43);
rib(16, 27, 8, 35);
rib(16, 27, 6, 30);
line(X(16), 24, 27, X(13), 25, 34, 1, rockLight);
animate(name, { type: "swing", axis: "y", speed: side < 0 ? 3 : -3, amplitude: 0.35 });
}
wing(-1);
wing(1);
function leg(name, x, y, speed) {
part(name, [x, y, 16]);
ellipsoid(x, y, 10, 3.5, 3.5, 7, rockDark);
ellipsoid(x, y - 1, 10, 3, 3, 6, rock);
ellipsoid(x, y - 2, 2, 3.5, 4, 2, rockLight);
box(x - 3, y - 5, 0, x + 3, y + 1, 1, rockDark);
for (let dx of [-2, 0, 2]) {
box(x + dx, y - 6, 0, x + dx, y - 4, 2, rockLight);
set(x + dx, y - 7, 0, "#ec9a3d");
}
// Chunky orange seams at the knee.
line(x - 2, y - 3, 9, x, y - 3, 7, 0, lava);
line(x, y - 3, 7, x + 2, y - 2, 8, 0, hot);
animate(name, { type: "swing", axis: "x", speed, amplitude: 0.3 });
}
leg("frontLeft", 17, 16, 3);
leg("frontRight", 31, 16, -3);
leg("rearLeft", 17, 30, -3);
leg("rearRight", 31, 30, 3);
part("body");
ellipsoid(24, 24, 19, 10, 12, 9, rockDark);
ellipsoid(24, 23, 20, 9, 11, 8, rock);
ellipsoid(24, 16, 19, 8, 6, 7, rockLight);
// Curving, tapering tail with an ember-colored underside.
for (let i = 0; i < 12; i++) {
const y = 33 + i;
const r = Math.max(1.3, 5 - i * 0.32);
ellipsoid(24 + Math.round(Math.sin(i * 0.32) * 2), y, 17 + Math.round(i * 0.12),
r, 2.5, r * 0.72, i % 3 === 0 ? rockLight : rock);
}
line(24, 39, 15, 25, 45, 17, 0, lava);
line(25, 43, 17, 25, 46, 18, 0, hot);
// Raised volcanic plates down the back and tail.
for (let y of [19, 23, 27, 31, 35, 39, 43]) {
const tip = y < 35 ? 32 : Math.max(21, 31 - (y - 35));
const base = y < 35 ? 27 : Math.max(19, 25 - (y - 35) * 0.5);
for (let z = Math.ceil(base); z <= tip; z++) {
const w = Math.max(0, Math.floor((tip - z) * 0.42));
box(24 - w, y, z, 24 + w, y + 1, z, z === tip ? "#dc6930" : rockDark);
}
}
// Oversized friendly-cartoon dragon head and square snout.
ellipsoid(24, 10, 22, 9, 8, 7, rockDark);
ellipsoid(24, 9, 23, 8, 7, 6, rock);
box(19, 2, 21, 29, 8, 24, rockLight);
box(20, 1, 22, 28, 4, 24, rock);
box(19, 2, 20, 29, 5, 20, rockDark);
// Deep open mouth, molten throat, and a projecting lower jaw.
box(19, 1, 16, 29, 4, 19, "#100e18");
box(21, 3, 17, 27, 4, 18, "#d83c16");
box(22, 2, 17, 26, 3, 18, hot);
box(20, 2, 13, 28, 8, 15, rockDark);
box(21, 1, 14, 27, 5, 15, rockLight);
box(21, 2, 16, 27, 3, 16, lava);
for (let x of [20, 23, 26, 28]) {
set(x, 1, 19, "#ffdf91");
set(x, 1, 16, "#ffdf91");
}
// Wide glowing eyes beneath heavy brows.
for (let x of [19, 29]) {
box(x - 2, 3, 25, x + 2, 5, 28, rockDark);
box(x - 1, 2, 25, x + 1, 3, 27, yellow);
set(x, 1, 26, "#fff5a1");
box(x - 2, 1, 28, x + 2, 4, 29, rockDark);
}
for (let x of [21, 27]) {
set(x, 1, 22, rockDark);
set(x, 1, 23, rockDark);
}
// Paired backward-curving horns.
for (let x of [17, 31]) {
line(x, 10, 27, x, 12, 32, 2, rockDark);
line(x, 12, 32, x + (x < 24 ? -2 : 2), 16, 35, 1, rockLight);
line(x + (x < 24 ? -2 : 2), 16, 35,
x + (x < 24 ? -3 : 3), 18, 36, 0, "#d47a3b");
}
// Small armor scales on the shoulders and upper back.
for (let y = 16; y <= 32; y += 3)
for (let x = 17; x <= 31; x += 3) {
const q = 1 - ((x - 24) / 10) ** 2 - ((y - 24) / 12) ** 2;
if (q > 0.16 && rand() < 0.8) {
const z = Math.round(19 + 9 * Math.sqrt(q));
set(x, y, z, rand() < 0.35 ? "#50434a" : rockLight);
}
}
// Surface-following lava fissures belong to one glowing color-cycling part.
part("lavaCracks");
const crackColors = ["#aa261d", lava, hot, yellow];
function frontPoint(cx, cy, cz, rx, ry, rz, x, z, color) {
const q = 1 - ((x - cx) / rx) ** 2 - ((z - cz) / rz) ** 2;
if (q > 0.04) {
const y = Math.round(cy - ry * Math.sqrt(q)) - 1;
set(x, y, z, color);
if (rand() < 0.22) set(x, y - 1, z, hot);
}
}
for (let x = 17; x <= 31; x++) {
const z = 20 + Math.round(2 * Math.sin(x * 0.8));
frontPoint(24, 23, 20, 9, 11, 8, x, z, crackColors[x % 4]);
if (x % 4 === 0) {
frontPoint(24, 23, 20, 9, 11, 8, x, z + 1, lava);
frontPoint(24, 23, 20, 9, 11, 8, x + 1, z - 1, hot);
}
}
for (let x = 19; x <= 29; x++) {
const z = 18 + Math.round(Math.sin(x * 0.9));
frontPoint(24, 10, 22, 9, 8, 7, x, z, x % 3 ? lava : hot);
}
for (let y = 18; y <= 31; y += 4)
for (let dx of [-7, 7]) {
const x = 24 + dx;
const z = 22 + Math.round(Math.sin(y) * 2);
frontPoint(24, 23, 20, 9, 11, 8, x, z, hot);
}
animate("lavaCracks", {
type: "colors",
palette: ["#92231b", "#e94c19", "#ffad26", "#ffe45d"],
pattern: "noise",
glow: 0.8
});import { draw } from "./assets/voxel";
import { dragonDeLava } from "./assets/dragon-de-lava";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, dragonDeLava, 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 dragon-de-lava
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["dragon-de-lava"] })
# Queda en client/assets/dragon-de-lava.ts
# https://fogon.page/object/dragon-de-lava