|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import sys
|
|
|
|
import argparse
|
|
|
|
import time
|
|
|
|
import math
|
|
|
|
import colorsys
|
|
|
|
import blup.frame
|
|
|
|
import blup.output
|
|
|
|
import blup.animation
|
|
|
|
import blup.writebml
|
|
|
|
import numpy as np
|
|
|
|
import random
|
|
|
|
|
|
|
|
WIDTH = 22
|
|
|
|
HEIGHT = 16
|
|
|
|
DEPTH = 256
|
|
|
|
|
|
|
|
G = np.array([0, 9.81])
|
|
|
|
|
|
|
|
class Fireball:
|
|
|
|
def __init__(self, startpos, startspeed, startcolor, lifetime, t0):
|
|
|
|
self.startpos, self.startspeed, self.startcolor, self.lifetime = \
|
|
|
|
startpos, startspeed, startcolor, lifetime
|
|
|
|
self.t0 = t0
|
|
|
|
self.pos = startpos
|
|
|
|
self.color = startcolor
|
|
|
|
self.dead = False
|
|
|
|
|
|
|
|
def update_pos(self, t):
|
|
|
|
t = t - self.t0
|
|
|
|
if t > self.lifetime:
|
|
|
|
self.dead = True
|
|
|
|
return
|
|
|
|
self.pos = 0.5 * G * t**2 + self.startspeed * t + self.startpos
|
|
|
|
self.color = self.startcolor * (1 - t/self.lifetime)
|
|
|
|
if random.randint(1, 10) > 8:
|
|
|
|
self.color = np.array([0, 0, 0])
|
|
|
|
|
|
|
|
def draw(self, frame):
|
|
|
|
if not self.dead:
|
|
|
|
frame.setPixel(int(round(self.pos[0])), int(round(self.pos[1])),
|
|
|
|
tuple(map(lambda x: int(round(x)), self.color)))
|
|
|
|
|
|
|
|
class Rocket:
|
|
|
|
def __init__(self, startpos, startspeed, explode_height, t0, color):
|
|
|
|
self.startpos, self.startspeed, self.explode_height, self.t0 = \
|
|
|
|
startpos, startspeed, explode_height, t0
|
|
|
|
self.color = color
|
|
|
|
self.pos = None
|
|
|
|
self.exploded = False
|
|
|
|
|
|
|
|
def update(self, t):
|
|
|
|
t = t - self.t0
|
|
|
|
if t < 0 or self.exploded:
|
|
|
|
return
|
|
|
|
self.pos = 0.5 * G * t**2 + self.startspeed * t + self.startpos
|
|
|
|
if self.pos[1] <= self.explode_height:
|
|
|
|
self.exploded = True
|
|
|
|
self.color = np.array([0, 0, 0])
|
|
|
|
|
|
|
|
def draw(self, frame):
|
|
|
|
if self.pos is None or self.exploded:
|
|
|
|
return
|
|
|
|
frame.setPixel(int(round(self.pos[0])), int(round(self.pos[1])),
|
|
|
|
tuple(map(lambda x: int(round(x)), self.color)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def getRandomColor(maxval):
|
|
|
|
return list(map(lambda x: int(round(x*maxval)), colorsys.hsv_to_rgb(random.random(), 1, 1)))
|
|
|
|
|
|
|
|
def gen_rockets(num, now=0):
|
|
|
|
for i in range(num):
|
|
|
|
yield Rocket(
|
|
|
|
np.array([random.randint(0, dim.width-1), dim.height-1]),
|
|
|
|
np.array([random.randint(-8, 8), -20 + random.randint(-2, 2)]),
|
|
|
|
4 + random.randint(-2, 2),
|
|
|
|
now + random.randint(0, 40) / 10,
|
|
|
|
np.array([dim.depth-1] * 3)
|
|
|
|
)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
parser = argparse.ArgumentParser(description='Generate plasma animations')
|
|
|
|
parser.add_argument('-d', '--delay', type=int, default=50)
|
|
|
|
parser.add_argument('-t', '--time', type=int, default=0)
|
|
|
|
parser.add_argument('-n', '--num-rockets', type=int, default=3)
|
|
|
|
parser.add_argument('output_file')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
dim = blup.frame.FrameDimension(WIDTH, HEIGHT, DEPTH, 3)
|
|
|
|
anim = blup.animation.Animation(dim)
|
|
|
|
anim.tags['description'] = ' '.join(sys.argv)
|
|
|
|
|
|
|
|
rockets = list(gen_rockets(args.num_rockets))
|
|
|
|
|
|
|
|
fbs = []
|
|
|
|
t = 0
|
|
|
|
while True:
|
|
|
|
frame = blup.animation.AnimationFrame(dim, args.delay)
|
|
|
|
|
|
|
|
for fb in fbs:
|
|
|
|
fb.update_pos(t)
|
|
|
|
try:
|
|
|
|
fb.draw(frame)
|
|
|
|
except ValueError:
|
|
|
|
continue
|
|
|
|
fbs = list(filter(lambda f: not f.dead, fbs))
|
|
|
|
|
|
|
|
for r in rockets:
|
|
|
|
r.update(t)
|
|
|
|
try:
|
|
|
|
r.draw(frame)
|
|
|
|
except ValueError:
|
|
|
|
continue
|
|
|
|
if r.exploded:
|
|
|
|
color = np.array(getRandomColor(dim.depth-1))
|
|
|
|
for i in range(random.randint(15, 25)):
|
|
|
|
v = np.array([
|
|
|
|
random.choice([-1, 1]) * random.randint(0, 25),
|
|
|
|
random.choice([-1, 1]) * random.randint(0, 25),
|
|
|
|
])
|
|
|
|
fbs.append(Fireball(r.pos, v, color, 1.5 + random.randint(-1, 1), t))
|
|
|
|
rockets = list(filter(lambda r: not r.exploded, rockets))
|
|
|
|
|
|
|
|
anim.addFrame(frame)
|
|
|
|
|
|
|
|
if len(rockets) == 0 and len(fbs) == 0:
|
|
|
|
if t < args.time:
|
|
|
|
frame = blup.animation.AnimationFrame(dim, 700)
|
|
|
|
anim.addFrame(frame)
|
|
|
|
rockets = list(gen_rockets(args.num_rockets, t))
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
t += args.delay / 1000
|
|
|
|
|
|
|
|
blup.writebml.writeBml(anim, args.output_file)
|