Skip to content

Instantly share code, notes, and snippets.

@aman-tiwari
Last active May 25, 2017 06:05
Show Gist options
  • Select an option

  • Save aman-tiwari/a7d1078ac0ea6e039a788bb1f3e3e78a to your computer and use it in GitHub Desktop.

Select an option

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

aman-tiwari commented May 24, 2017

Copy link
Copy Markdown
Author

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