Skip to content

Instantly share code, notes, and snippets.

@aman-tiwari
Last active May 25, 2017 06:05
Show Gist options
  • Save aman-tiwari/a7d1078ac0ea6e039a788bb1f3e3e78a to your computer and use it in GitHub Desktop.
Save aman-tiwari/a7d1078ac0ea6e039a788bb1f3e3e78a to your computer and use it in GitHub Desktop.
A little particle system for your terminal : )
from itertools import chain
from math import sqrt
from random import random
import drawille
def wrap(x, low, high):
if x > high:
return low
elif x < low:
return high
return x
class Particle(object):
__slots__ = ['x', 'y', 'x_velocity', 'y_velocity']
def __init__(self, x, y, x_velocity, y_velocity):
self.x = x
self.y = y
self.x_velocity = x_velocity
self.y_velocity = y_velocity
def make_particle(x, y, x_velocity, y_velocity):
return Particle(x, y, x_velocity, y_velocity)
def particle_system(width, height,
n_particles,
infulence_distance,
attract,
repel,
repel_distance,
steer):
drag = 0.04
# x, y, x_velocity, y_velocity
particles = [make_particle(random() * width, random() * height, 0.0, 0.0)
for _ in range(n_particles)]
prev_positions = [[], [], [], []]
while True:
for particle in particles:
for other in particles:
if particle != other:
dx = other.x - particle.x
dy = other.y - particle.y
distance = sqrt((dx * dx) + (dy * dy))
if distance < infulence_distance:
accel_x = 0.0
accel_y = 0.0
accel_x += dx * attract
accel_y += dy * attract
if distance < repel_distance:
inverse_dist = (repel_distance /
(distance + 0.1)) ** 2
accel_x += dx * inverse_dist * repel
accel_y += dy * inverse_dist * repel
accel_x += (other.x_velocity -
particle.x_velocity) * steer
accel_y += (other.y_velocity -
particle.y_velocity) * steer
particle.x_velocity += accel_x
particle.y_velocity += accel_y
particle.x_velocity *= 1.0 - drag
particle.y_velocity *= 1.0 - drag
particle.x += particle.x_velocity
particle.y += particle.y_velocity
particle.x = wrap(particle.x, 0, width)
particle.y = wrap(particle.y, 0, height)
positions = []
# x y size inversely related to x y velocity
for particle in particles:
scale_x = max(1, min(10, int(4.0 / particle.x_velocity)))
scale_y = min(10, int(4.0 / particle.y_velocity))
for x_offset in range(scale_x):
for y_offset in range(scale_y):
positions.append(
(particle.x + x_offset, particle.y + y_offset))
positions.append((particle.x, particle.y))
positions.append((width + 10, height + 10))
positions.append((0, 0))
prev_positions = prev_positions[1:]
prev_positions.append(positions)
yield chain( # drawille.line(0, 0, width - 1, 0),
#drawille.line(width - 1, 0, width - 1, height - 1),
#drawille.line(0, 0, 0, height - 1),
#drawille.line(0, height - 1, width - 1, height - 1),
*prev_positions)
canvas = drawille.Canvas()
width, height = drawille.getTerminalSize()
print width, height
# if you get _curses.error: addstr() returned ERR lower the width & height
# multipliers
drawille.animate(canvas, particle_system, 1. / 24, width * 2.0 - 10, height * 3.0 - 10,
120, 150, 0.001, -0.02, 30, 0.1)
@aman-tiwari
Copy link
Author

aman-tiwari commented May 24, 2017

you might need to change the numbers width and height are multiplied by to get it to fill up your terminal or if you get _curses.error: addstr() returned ERR or you can make your terminal bigger

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment