fogón

← ArmasObjeto 3Dfogon/arma-shurikens

Shurikens

de fogonCC03345 bloques
ShurikensArrastrá para girarlo
// «Shurikens» · propio
// Three steel ninja throwing stars (shurikens) fanned out, with a red cloth wrap.

const colors = () => {};
const STEEL = ["#59626f", "#7f8a97", "#a6b1be", "#ccd7e2"];
const CLOTH = ["#6f161d", "#8f1f27", "#ad2b34", "#c93f48", "#e06068"];

// ---- helper: one flat four-pointed shuriken ----
function shuriken(cx, cy, ang) {
  const R = 13, W = 5.0;
  const ca = Math.cos(ang), sa = Math.sin(ang);
  const x0 = Math.max(0, Math.floor(cx - R)), x1 = Math.min(47, Math.ceil(cx + R));
  const y0 = Math.max(0, Math.floor(cy - R)), y1 = Math.min(47, Math.ceil(cy + R));
  for (let x = x0; x <= x1; x++) {
    for (let y = y0; y <= y1; y++) {
      const dx = x - cx, dy = y - cy;
      const u = dx * ca + dy * sa;
      const v = -dx * sa + dy * ca;
      const au = Math.abs(u), av = Math.abs(v);
      const d = Math.min(au / R + av / W, av / R + au / W);
      if (d > 1) continue;
      const r2 = au * au + av * av;
      if (r2 < 5) continue;                 // centre hole
      let top = 4;
      if (d > 0.86) top = 1;                // thin blade rim
      else if (d > 0.62) top = 3;
      let ci;
      if (r2 < 11) ci = 0;                  // dark ring around hole
      else if (d > 0.86) ci = 3;            // bright sharpened edge
      else if (d > 0.62) ci = 2;
      else if (d > 0.32) ci = 1;
      else ci = 2;
      for (let z = 0; z <= top; z++) {
        let k = (z === top) ? ci : Math.max(0, ci - 1);
        if (z === top && rand() < 0.07) k = Math.min(3, k + 1);
        set(x, y, z, STEEL[k]);
      }
    }
  }
}

// ---- three shurikens fanned out, tips toward -y ----
shuriken(18.0, 18.2, -22 * Math.PI / 180);
shuriken(24.0, 17.0, 0);
shuriken(30.0, 18.2, 22 * Math.PI / 180);

// ---- red cloth wrap: main band across the tails ----
for (let x = 11; x <= 37; x++) {
  let t = 1;
  if (x < 16) t = (x - 10) / 6;
  if (x > 32) t = (38 - x) / 6;
  if (t <= 0.06) continue;
  const ry = 4.8 * t, rz = 8.8 * t;
  for (let y = 24; y <= 36; y++) {
    for (let z = 0; z <= 13; z++) {
      const dy = (y - 30) / ry;
      const dz = z / rz;
      const q = dy * dy + dz * dz;
      if (q > 1) continue;
      let idx = q > 0.72 ? 4 : q > 0.42 ? 3 : q > 0.18 ? 2 : 1;
      if (x % 5 === 0) idx = Math.max(0, idx - 2);
      set(x, y, z, CLOTH[idx]);
    }
  }
}

// ---- knot sitting on the band ----
for (let x = 19; x <= 29; x++) {
  for (let y = 25; y <= 35; y++) {
    for (let z = 4; z <= 13; z++) {
      const q = ((x - 24) / 4.6) ** 2 + ((y - 30) / 4.6) ** 2 + ((z - 8) / 3.6) ** 2;
      if (q > 1) continue;
      let idx = q > 0.7 ? 4 : q > 0.42 ? 3 : q > 0.2 ? 2 : 1;
      if ((x + y) % 5 === 0) idx = Math.max(0, idx - 2);
      set(x, y, z, CLOTH[idx]);
    }
  }
}

// ---- loose cloth tails, hanging out behind the knot ----
function tail(p0, p1, p2) {
  for (let i = 0; i <= 70; i++) {
    const t = i / 70;
    const x = (1 - t) * (1 - t) * p0[0] + 2 * (1 - t) * t * p1[0] + t * t * p2[0];
    const y = (1 - t) * (1 - t) * p0[1] + 2 * (1 - t) * t * p1[1] + t * t * p2[1];
    const w = 2.5 - 0.8 * t;
    const px = Math.round(x), py = Math.round(y);
    for (let dx = -3; dx <= 3; dx++) {
      for (let dy = -3; dy <= 3; dy++) {
        if (dx * dx + dy * dy > w * w) continue;
        for (let z = 0; z <= 2; z++) {
          let idx = z === 2 ? 4 : z === 1 ? 3 : 2;
          if ((px + dx + 40) % 4 === 0) idx = Math.max(0, idx - 1);
          set(px + dx, py + dy, z, CLOTH[idx]);
        }
      }
    }
  }
}

part("tail1", [27, 34, 0]);
tail([27, 34], [32, 39], [30, 44]);

part("tail2", [21, 34, 0]);
tail([21, 34], [16, 39], [18, 44]);

animate("tail1", { type: "swing", axis: "z", speed: 1.4, amplitude: 0.14 });
animate("tail2", { type: "swing", axis: "z", speed: 1.1, amplitude: 0.17 });