"""Gera os 11 quadros (46x45, RGBA) da explosao do missil do Stellar Highway. Substitui a "Missile Explosion Animation" do nyknck (sem licenca). Desenho proprio, determinístico (PRNG com semente fixa, sem Pillow: o PNG e escrito com zlib), dedicado ao dominio publico (CC0). python3 -I explosion.py """ import math, os, random, struct, sys, zlib W, H, N = 46, 45, 11 CX, CY = 22.5, 22.0 # (limite de distancia normalizada, cor) do centro para fora PALETTE = [(0.30, (255, 248, 214)), (0.55, (255, 214, 64)), (0.78, (255, 140, 24)), (1.01, (214, 58, 24))] SMOKE = (74, 62, 70) def png(path, px): raw = b''.join(b'\x00' + bytes(v for p in px[y * W:(y + 1) * W] for v in p) for y in range(H)) def chunk(t, d): c = struct.pack('>I', len(d)) + t + d return c + struct.pack('>I', zlib.crc32(t + d) & 0xffffffff) data = b'\x89PNG\r\n\x1a\n' + chunk(b'IHDR', struct.pack('>IIBBBBB', W, H, 8, 6, 0, 0, 0)) \ + chunk(b'IDAT', zlib.compress(raw, 9)) + chunk(b'IEND', b'') open(path, 'wb').write(data) def frame(t): rng = random.Random(1000 + t) # raio do clarao: cresce rapido ate o quadro 5, depois encolhe; fumaca e fagulhas ate o fim grow = min(t, 5) / 5.0 fire_r = 4 + 17 * math.sin(grow * math.pi / 2) if t <= 5 else 21 - (t - 5) * 3.2 fire_r = max(fire_r, 0) lobes = [rng.uniform(0.75, 1.15) for _ in range(12)] smoke_a = 0 if t < 3 else min(1.0, (t - 2) / 3.0) * (1.0 if t < 8 else (11 - t) / 3.0) smoke_r = 8 + t * 1.6 sparks = [(rng.uniform(0, 2 * math.pi), rng.uniform(0.5, 1.0)) for _ in range(10)] px = [(0, 0, 0, 0)] * (W * H) for y in range(H): for x in range(W): dx, dy = x + 0.5 - CX, y + 0.5 - CY d = math.hypot(dx, dy) ang = math.atan2(dy, dx) lobe = lobes[int((ang + math.pi) / (2 * math.pi) * 12) % 12] col = None if fire_r > 0: edge = fire_r * lobe if d < edge: nd = d / edge + (0.12 if t > 5 else 0.0) * (t - 5) * 0.4 for lim, c in PALETTE: if nd < lim: col = c + (255,) break if col is None: col = PALETTE[-1][1] + (255,) if col is None and smoke_a > 0 and d < smoke_r * lobe and (x + y + t) % 2 == 0: col = SMOKE + (int(200 * smoke_a),) px[y * W + x] = col or (0, 0, 0, 0) # fagulhas: pontos que se afastam do centro for a, s in sparks: r = (4 + t * 2.0) * s * 1.6 if t >= 1 and r < 22: sx, sy = int(CX + math.cos(a) * r), int(CY + math.sin(a) * r) if 0 <= sx < W - 1 and 0 <= sy < H - 1 and t < 10: px[sy * W + sx] = (255, 226, 120, 255) if t < 7: px[sy * W + sx + 1] = (255, 160, 40, 255) return px out = sys.argv[1] os.makedirs(out, exist_ok=True) for i in range(N): png(os.path.join(out, f'{i}.png'), frame(i))