Fr3deric
7 years ago
1 changed files with 232 additions and 0 deletions
@ -0,0 +1,232 @@
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env python3 |
||||
|
||||
import sys |
||||
import random |
||||
import math |
||||
import argparse |
||||
import collections |
||||
import blup.frame |
||||
import blup.output |
||||
import blup.animation |
||||
import blup.writebml |
||||
import colorsys |
||||
import functools |
||||
|
||||
|
||||
WIDTH = 22 |
||||
HEIGHT = 16 |
||||
DEPTH = 256 |
||||
|
||||
|
||||
class Point(collections.namedtuple('Point', ['x', 'y'])): |
||||
def __add__(self, other): |
||||
return Point(self.x + other.x, self.y + other.y) |
||||
def __sub__(self, other): |
||||
return Point(self.x - other.x, self.y - other.y) |
||||
def __mul__(self, other): |
||||
if isinstance(other, Point): |
||||
raise Exception('not implemented') |
||||
else: |
||||
return Point(self.x * other, self.y * other) |
||||
def __truediv__(self, other): |
||||
if isinstance(other, Point): |
||||
raise ValueError() |
||||
else: |
||||
return self * (1/other) |
||||
@property |
||||
def len(self): |
||||
return math.sqrt(self.x**2 + self.y**2) |
||||
@property |
||||
def n(self): |
||||
n = Point(self.y, -self.x) |
||||
return n / n.len |
||||
@property |
||||
def intp(self): |
||||
return Point(int(round(self.x)), int(round(self.y))) |
||||
|
||||
|
||||
def convert_color(c): |
||||
return list(map(lambda x: int(round(x*(DEPTH-1))), c)) |
||||
|
||||
|
||||
def get_random_color(): |
||||
return colorsys.hsv_to_rgb(random.random(), 0.5 + random.random() / 2, 1) |
||||
|
||||
|
||||
class CurveFunction(): |
||||
def __init__(self, p1, p2): |
||||
self.p1, self.p2 = p1, p2 |
||||
d = p2 - p1 |
||||
self.pp = p1 + d/2 + d.n * (d.len * 0.8) |
||||
|
||||
def __call__(self, t): |
||||
ret = (self.p1 - self.pp*2 + self.p2) * t**2 |
||||
ret += (self.p1 * -2 + self.pp * 2) * t |
||||
ret += self.p1 |
||||
return ret |
||||
|
||||
|
||||
|
||||
class Box(): |
||||
def __init__(self, pos, size, hue, swaptime, content=None, |
||||
contentcolor=None): |
||||
self.pos, self.size, self.hue, self.content, self.contentcolor = \ |
||||
pos, size, hue, content, contentcolor |
||||
self.swaptime = swaptime |
||||
self.covered = False |
||||
self.swapstart = None |
||||
self.newpos = None |
||||
self.cf = None |
||||
self.colorcycletime = 1 |
||||
|
||||
def swap(self, other): |
||||
self.newpos = other.pos |
||||
other.newpos = self.pos |
||||
|
||||
def update(self, t, dt): |
||||
self.hue += 0.05 # dt / self.colorcycletime |
||||
if self.hue > 1: |
||||
self.hue -= 1 |
||||
if self.newpos is not None: |
||||
if self.cf is None: |
||||
self.cf = CurveFunction(self.pos, self.newpos) |
||||
self.swapstart = t |
||||
elif t - self.swapstart >= self.swaptime: |
||||
self.pos = self.newpos |
||||
self.newpos = None |
||||
self.cf = None |
||||
self.swapstart = None |
||||
else: |
||||
self.pos = (self.cf((t - self.swapstart) / self.swaptime)).intp |
||||
|
||||
def draw(self, frame): |
||||
if self.covered: |
||||
for x in range(self.size): |
||||
for y in range(self.size): |
||||
if x == 0 or x == self.size - 1 \ |
||||
or y == 0 or y == self.size -1: |
||||
color = (0.2, 0.2, 0.2) |
||||
else: |
||||
color = colorsys.hsv_to_rgb(self.hue, 1, 1) |
||||
try: |
||||
frame.setPixel(self.pos.x + x, self.pos.y + y, |
||||
convert_color(color)) |
||||
except ValueError: |
||||
pass |
||||
else: |
||||
if self.content is not None: |
||||
for p in self.content: |
||||
try: |
||||
frame.setPixel(self.pos.x + p.x + 1, |
||||
self.pos.y + p.y + 1, |
||||
convert_color(self.contentcolor)) |
||||
except ValueError: |
||||
pass |
||||
|
||||
|
||||
class Game(): |
||||
def __init__(self, size, boxsize, gap, content, contentcolor, swaptime): |
||||
self.swaptime = swaptime |
||||
self.boxes = [] |
||||
boxbase = Point((size.x - (2*boxsize + gap)) / 2, |
||||
(size.y - (2*boxsize + gap)) / 2) |
||||
self.n_boxes = 4 |
||||
for i in range(self.n_boxes): |
||||
boxpos = boxbase + Point( |
||||
(i % (self.n_boxes/2)) * (boxsize + gap), |
||||
(i // (self.n_boxes/2)) * (boxsize + gap) |
||||
) |
||||
self.boxes.append(Box( |
||||
boxpos.intp, |
||||
boxsize, |
||||
i * (1/self.n_boxes), |
||||
swaptime |
||||
)) |
||||
winner = random.randint(0, self.n_boxes - 1) |
||||
self.boxes[winner].content = content |
||||
self.boxes[winner].contentcolor = contentcolor |
||||
self.statetimes = [2, 1, 5, 2, 1, 2] |
||||
self.statestarts = [0] |
||||
for t in self.statetimes[:-1]: |
||||
self.statestarts.append(self.statestarts[-1] + t) |
||||
self.done = False |
||||
|
||||
def update(self, t, dt): |
||||
state = 0 |
||||
for i, st in enumerate(self.statestarts): |
||||
if st < t: |
||||
state = i |
||||
else: |
||||
break |
||||
state_t = t - self.statestarts[state] |
||||
|
||||
if state == 1 or state == 4: |
||||
for i, b in enumerate(self.boxes): |
||||
if state_t >= i * (self.statetimes[state] / self.n_boxes): |
||||
b.covered = (state == 1) |
||||
elif state == 2: |
||||
if True not in map(lambda b: b.newpos is not None, self.boxes) \ |
||||
and random.random() > 0.2: |
||||
b1 = random.randint(0, self.n_boxes - 1) |
||||
b2 = random.randint(0, self.n_boxes - 1) |
||||
while b1 == b2: |
||||
b2 = random.randint(0, self.n_boxes - 1) |
||||
self.boxes[b1].swap(self.boxes[b2]) |
||||
|
||||
if state > 0 and state < 5: |
||||
for b in self.boxes: |
||||
b.update(t, dt) |
||||
|
||||
if state == len(self.statetimes) - 1: |
||||
self.done = True |
||||
|
||||
def draw(self, frame): |
||||
for b in self.boxes: |
||||
if b.newpos is None: |
||||
b.draw(frame) |
||||
for b in self.boxes: |
||||
if b.newpos is not None: |
||||
b.draw(frame) |
||||
|
||||
|
||||
BOXCONTENT = { |
||||
Point(0, 0), |
||||
Point(3, 0), |
||||
Point(0, 2), |
||||
Point(3, 2), |
||||
Point(1, 3), |
||||
Point(2, 3), |
||||
} |
||||
|
||||
|
||||
if __name__ == '__main__': |
||||
parser = argparse.ArgumentParser(description='Generate animations') |
||||
parser.add_argument('-d', '--delay', type=int, default=50) |
||||
parser.add_argument('-t', '--time', type=int, default=15) |
||||
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) |
||||
|
||||
|
||||
t = 0 |
||||
dt = args.delay / 1000 |
||||
gamestart = 0 |
||||
game = None |
||||
while t < args.time or not game.done: |
||||
t += dt |
||||
frame = blup.animation.AnimationFrame(dim, args.delay) |
||||
|
||||
if (game is None or game.done) and t < args.time: |
||||
game = Game(Point(WIDTH, HEIGHT), 6, 2, BOXCONTENT, |
||||
get_random_color(), 0.5) |
||||
gamestart = t |
||||
game.update(t - gamestart, dt) |
||||
game.draw(frame) |
||||
|
||||
anim.addFrame(frame) |
||||
|
||||
|
||||
blup.writebml.writeBml(anim, args.output_file) |
Loading…
Reference in new issue