Created
February 2, 2017 15:38
-
-
Save vxgmichel/fd5bf7211d22ee34ea9067e23a6a2c4e to your computer and use it in GitHub Desktop.
Generate a twin dragon fractal using pygame
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import pygame | |
import random | |
import imageio | |
from fractions import gcd | |
lcm = lambda x, y: x * y // gcd(x, y) | |
def random_color(): | |
r = lambda: random.randint(0, 255) | |
return r(), r(), r() | |
def colorcycle(n): | |
lst = [random_color() for _ in range(n)] | |
while True: | |
yield from lst | |
def vectors(x=1, y=0, spiral=False): | |
while True: | |
yield x, y | |
x, y = (x-y, x+y) if spiral else (-x-y, x-y) | |
def translations(x=1, y=0, spiral=False): | |
g0 = vectors(x, y, spiral) | |
g1 = vectors(x, y, spiral) | |
next(g1) | |
return zip(g0, g1) | |
def shapes(shape=(0, 0, 1, 1), vector=(1, 0), spiral=False): | |
# First shape | |
x, y, w, h = shape | |
yield x, y, w, h | |
# Second shape | |
x += vector[0] | |
y += vector[1] | |
yield x, y, w, h | |
# Next shapes | |
for (i0, j0), (i1, j1) in translations(*vector, spiral): | |
x += i1 - max(0, i0) | |
y += j1 - max(0, j0) | |
w += abs(i0) | |
h += abs(j0) | |
yield x, y, w, h | |
def sprites(shape=(50, 50, 1, 1), vector=(1, 0), spiral=False): | |
shapegen = shapes(shape, vector, spiral) | |
tsgen = translations(*vector, spiral) | |
for _ in range(2): | |
x, y, w, h = next(shapegen) | |
surf = pygame.Surface((w, h)) | |
last = Twin(surf, (x, y)) | |
yield last | |
for shape, translation in zip(shapegen, tsgen): | |
last = Twin.from_sprite(last, translation, shape) | |
yield last | |
class Twin(pygame.sprite.Sprite): | |
colorgen = colorcycle(8) | |
def __init__(self, image, position): | |
pygame.sprite.Sprite.__init__(self) | |
self.image = image | |
self.image.fill( | |
(0, 0, 0), special_flags=pygame.BLEND_RGB_MIN) | |
self.image.fill( | |
next(self.colorgen), special_flags=pygame.BLEND_RGB_ADD) | |
self.rect = self.image.get_rect(topleft=position) | |
@classmethod | |
def from_sprite(cls, sprite, translation, shape): | |
x, y, w, h = shape | |
surf = pygame.Surface((w, h), flags=pygame.SRCALPHA) | |
surf.fill((0, 0, 0, 0)) | |
(i0, j0), (i1, j1) = translation | |
x0, y0 = sprite.rect.topleft | |
a = (x0-i0+i1) - x | |
b = (y0-j0+j1) - y | |
surf.blit(sprite.image, (a, b)) | |
a = (x0+i1) - x | |
b = (y0+j1) - y | |
surf.blit(sprite.image, (a, b)) | |
return cls(surf, (x, y)) | |
def main(width=161, height=161, nb_sprite=28, spiral=False, | |
speed=0.1, rotate=-0.15, fps=36, scale=1.5, | |
gif='twindragons.gif'): | |
pygame.init() | |
pygame.display.set_caption("Twin dragons") | |
steps = int(round(fps/speed)) | |
display_width = int(scale*width/2**0.5) | |
display_height = int(scale*height/2**0.5) | |
rotate_steps = int(round(fps/rotate)) if rotate else 1 | |
total_steps = lcm(abs(steps), abs(rotate_steps)) | |
screen = pygame.display.set_mode((display_width, display_height)) | |
clock = pygame.time.Clock() | |
group = pygame.sprite.Group() | |
spritegen = sprites((width*8, height*8, 1, 1), (0, 1), spiral) | |
surf = pygame.Surface((width*16, height*16), flags=pygame.SRCALPHA) | |
background_color = random_color() | |
images = [] | |
frame = 0 | |
screen.fill(background_color) | |
pygame.display.flip() | |
for i, sprite in zip(range(nb_sprite), spritegen): | |
group.add(sprite) | |
group.draw(surf) | |
while True: | |
for event in pygame.event.get(): | |
if event.type == pygame.QUIT: | |
return | |
if event.type == pygame.KEYDOWN: | |
if event.key == pygame.K_f: | |
pygame.display.toggle_fullscreen() | |
if pygame.key.get_pressed()[pygame.K_p]: | |
continue | |
frame += 1 | |
ratio = (frame % steps)/steps | |
angle = 360 * (frame % rotate_steps) / rotate_steps | |
if angle >= 180: | |
angle -= 360 | |
if angle < 180: | |
angle += 360 | |
delta = (16 - 16 ** (1-ratio)) / 2 | |
dx = int(round(delta * width)) | |
dy = int(round(delta * height)) | |
rect = pygame.Rect(dx, dy, 16*width-2*dx, 16*height-2*dy) | |
subsurf = surf.subsurface(rect) | |
scale_factor = scale * width / rect.width | |
rotated = pygame.transform.rotozoom(subsurf, angle, scale_factor) | |
rect = rotated.get_rect() | |
rect.inflate_ip(display_width-rect.width, display_height-rect.height) | |
screen.blit(rotated, (0, 0), rect) | |
pygame.display.flip() | |
if gif and len(images) < total_steps: | |
images.append(pygame.surfarray.array3d(screen)) | |
if gif and len(images) == total_steps: | |
imageio.mimwrite(gif, images, fps=fps) | |
print("Gif written to {}".format(gif)) | |
gif = None | |
screen.fill(background_color) | |
clock.tick(fps) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
bonjour vincent pourrais tu faire une video sur le premier niveaude double drago ou street of rage e pygame cr il n y a ren nul par sur youtube sauf des ados qui fon des trucks nul...
et aussi si tu eu tupeu just laisser la camera filmerton ecran je fais le montage video et aprs tu recuper les sous de youtube...ya zero français qui on fait y'a un creneau a prendre
voila bonne journée