fogón

← Monstruos y enemigosObjeto 3Dfogon/murcielago

Murciélago

de fogonCC05784 bloques
MurciélagoArrastrá para girarlo
// «Murciélago» · gpt-6-sol (medium)
// A chunky cartoon bat flying, centered: a round dark purple furry body with a cute-scary face toward -y, big pointy ears, glowing yellow eyes and two little white fangs, and two wide leathery wings spread out to the sides with visible finger bones and scalloped edges.

// Chunky flying bat. All geometry is lowered so its lowest blocks reach z=0.
const floorOffset = 10;
const put = (x, y, z, color) => set(x, y, z - floorOffset, color);
const oval = (x, y, z, rx, ry, rz, color) =>
  ellipsoid(x, y, z - floorOffset, rx, ry, rz, color);
const cube = (x0, y0, z0, x1, y1, z1, color) =>
  box(x0, y0, z0 - floorOffset, x1, y1, z1 - floorOffset, color);
const ball = (x, y, z, r, color) =>
  sphere(x, y, z - floorOffset, r, color);
const tube = (x0, y0, z0, x1, y1, z1, r, color) =>
  line(x0, y0, z0 - floorOffset, x1, y1, z1 - floorOffset, r, color);
const joint = (name, x, y, z) =>
  part(name, [x, y, z - floorOffset]);

joint("body", 24, 23, 25);
animate("body", { type: "bob", axis: "z", speed: 3, amplitude: 2 });

const plum = "#382044";
const purple = "#512b60";
const litPurple = "#684078";
const shadow = "#291834";

function furryEllipsoid(cx, cy, cz, rx, ry, rz) {
  for (let x = Math.floor(cx - rx); x <= cx + rx; x++)
    for (let y = Math.floor(cy - ry); y <= cy + ry; y++)
      for (let z = Math.floor(cz - rz); z <= cz + rz; z++) {
        const q = ((x - cx) / rx) ** 2 +
                  ((y - cy) / ry) ** 2 +
                  ((z - cz) / rz) ** 2;
        if (q > 1) continue;

        let color = z < cz - 3 ? plum : purple;
        if (z > cz + 2 && y < cy + 2) color = litPurple;
        if (q > 0.72 && rand() < 0.12)
          color = z < cz ? shadow : litPurple;
        put(x, y, z, color);
      }
}

// Round body, oversized head, and small fur tufts.
furryEllipsoid(24, 25, 22, 8, 7, 10);
furryEllipsoid(24, 20, 29, 9, 8, 9);
for (const [x, z] of [[18, 18], [21, 15], [24, 14], [27, 15], [30, 18]])
  tube(x, 18, z + 3, x, 17, z, 1, plum);

// These two feet now reach the floor at z=0.
oval(19, 21, 12, 2, 2, 2, plum);
oval(29, 21, 12, 2, 2, 2, plum);

// Tall pointed ears with lighter inner patches.
for (const side of [-1, 1]) {
  const cx = 24 + side * 8;
  for (let z = 35; z <= 44; z++) {
    const width = Math.max(0, Math.floor((44 - z) * 0.38));
    const back = 23 - Math.floor((z - 35) * 0.12);
    for (let x = cx - width; x <= cx + width; x++)
      for (let y = 16; y <= back; y++)
        put(x, y, z, z < 39 ? purple : plum);

    if (z >= 37 && z <= 42 && width >= 1)
      for (let x = cx - width + 1; x <= cx + width - 1; x++)
        put(x, 15, z, z > 40 ? "#a66090" : "#864772");
  }
}

// Muzzle, grin, fangs, and glowing yellow eyes.
oval(24, 13, 24, 5, 3, 3, "#714778");
oval(24, 10, 25, 2, 1, 1, "#9a668e");
cube(21, 9, 22, 27, 9, 22, shadow);
for (const x of [21, 27]) {
  cube(x, 8, 21, x + 1, 8, 23, "#fff4e5");
  put(x, 8, 20, "#e1d9e4");
}
for (const x of [19, 29]) {
  oval(x, 12, 31, 3, 2, 3, shadow);
  oval(x, 10, 31, 2, 1, 2, "#ffca36");
  put(x, 9, 32, "#fff5a2");
  put(x + 1, 9, 31, "#ffe875");
  tube(x - 2, 10, 35, x + 2, 10, 34, 1, plum);
}

// Wing outline: the lower edge dips between its finger tips.
const outline = [
  [8, 29], [11, 36], [16, 38], [22, 36],
  [21, 31], [18, 33], [16, 27], [14, 30],
  [12, 24], [10, 26], [8, 23]
];

function insideWing(d, z) {
  let inside = 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) &&
        d < (b[0] - a[0]) * (z - a[1]) / (b[1] - a[1]) + a[0])
      inside = !inside;
  }
  return inside;
}

for (const side of [-1, 1]) {
  const name = side < 0 ? "leftWing" : "rightWing";
  joint(name, 24 + side * 8, 24, 29);
  animate(name, {
    type: "swing",
    axis: "y",
    speed: side < 0 ? 8 : -8,
    amplitude: 0.5
  });

  for (let d = 8; d <= 22; d++)
    for (let z = 23; z <= 38; z++) {
      if (!insideWing(d + 0.5, z + 0.5)) continue;
      const edge = !insideWing(d - 0.5, z + 0.5) ||
                   !insideWing(d + 1.5, z + 0.5) ||
                   !insideWing(d + 0.5, z - 0.5) ||
                   !insideWing(d + 0.5, z + 1.5);
      const color = edge ? "#321b42" :
        z >= 33 ? "#89518e" : (rand() < 0.17 ? "#754079" : "#63336c");
      for (let y = 24; y <= 25; y++)
        put(24 + side * d, y, z, color);
    }

  // Raised finger bones fan outward from each shoulder.
  const bone = "#b078ab";
  tube(24 + side * 8, 23, 29, 24 + side * 11, 23, 35, 1, "#a46b9c");
  tube(24 + side * 11, 23, 35, 24 + side * 16, 23, 37, 0, bone);
  tube(24 + side * 11, 23, 35, 24 + side * 22, 23, 35, 0, bone);
  tube(24 + side * 11, 23, 35, 24 + side * 18, 23, 32, 0, bone);
  tube(24 + side * 10, 23, 31, 24 + side * 16, 23, 27, 0, bone);
  tube(24 + side * 9, 23, 28, 24 + side * 12, 23, 24, 0, bone);
  ball(24 + side * 11, 23, 35, 1, "#bd83ae");
}