#!/usr/bin/python3 # -*- coding: utf-8 -*- # -*- mode: Python -*- ''' v0.1.0 An example particle system reproducing some kind of flock simulation Licensed under GNU GPLv3 by cocoa ''' from __future__ import print_function import math import random import sys import os import time import redis import ast import argparse from os import path, getcwd abspath, filename = path.split(path.realpath(__file__ )) sys.path.insert(0, path.join(abspath,"../lib")) from clitools import Clitools MAX_WIDTH = 800 MIN_WIDTH = 0 MAX_HEIGHT = 800 MIN_HEIGHT = 0 MAX_SPEED = 10 WHITE = 16777215 argsparser = argparse.ArgumentParser(description="Dummy generator") argsparser.add_argument("-f","--fps",help="Frame Per Second",default=30,type=int) argsparser.add_argument("-v","--verbose",action="store_true",help="Verbose output") argsparser.add_argument("-n","--number",help="Particule Number",default=50,type=int) args = argsparser.parse_args() verbose = args.verbose fps = args.fps patricle_number = args.number scene_width = MAX_WIDTH - MIN_WIDTH scene_height = MAX_HEIGHT - MIN_HEIGHT center_x = MIN_WIDTH + scene_width / 2 center_y = MIN_HEIGHT + scene_height / 2 cli = Clitools({ "verbose" : verbose, "looptime" : 1 / fps, "name" : "generator::particles_example" }) class Particle(object): def __init__(self, x = 0, y = 0, color = 0, dx = 0, dy = 0): self.x = x self.y = y self.color = color # Store speed in 2 dimensions self.dx = dx self.dy = dy def interact(self, bodies): """ Computes particles interactions This is a good place to calculate distance between particles for example """ for other in bodies: if other is self: continue # For example, we average our speed with the other particle dist_x = other.x - self.x dist_y = other.y - self.y dist = math.sqrt(dist_x*dist_x + dist_y*dist_y) if dist == 0 : dist = 1 if dist > 50 : continue if dist > 5 : factor = math.sqrt(50-dist) -1 if factor > 1: factor = 1 self.dx = 0.5*self.dx + 0.5*((1 -factor)*self.dx + factor*other.dx) + (random.random() - 0.5) * 2 self.dy = 0.5*self.dy + 0.5*((1 -factor)*self.dy + factor*other.dy) + (random.random() - 0.5) * 2 else: # Too close: avoid self.dx += random.random() self.dy += random.random() def move(self): """ Computes how particle move The basis is to add speed to current position You can also add friction or compute distance to border in order to slow down """ self.x += self.dx self.y += self.dy if self.dx > MAX_SPEED: self.dx = MAX_SPEED if self.dx < -MAX_SPEED: self.dx = -MAX_SPEED if self.dy > MAX_SPEED: self.dy = MAX_SPEED if self.dy < -MAX_SPEED: self.dy = -MAX_SPEED if self.x > MAX_WIDTH: self.x = MIN_WIDTH if self.x < MIN_WIDTH: self.x = MAX_WIDTH if self.y > MAX_HEIGHT: self.y = MIN_HEIGHT if self.y < MIN_HEIGHT: self.y = MAX_HEIGHT class Simulator(object): def __init__(self, particles): """ Defines the initial particles """ # In this example, we will randomly dispatch a flock for i in range(0,patricle_number): x = random.randint(MIN_WIDTH,MAX_WIDTH) y = random.randint(MIN_HEIGHT,MAX_HEIGHT) dx = random.randint(-MAX_SPEED, MAX_SPEED) dy = random.randint(-MAX_SPEED, MAX_SPEED) color = WHITE p = Particle(x,y,color,dx=dx,dy=dy) cli.debug( "init: i:{} dx:{} dy:{} p:{}".format(i,dx,dy,vars(p))) particles.append( p ) self.particles = particles def redraw(self): """ Sends to standard output A good place to use certain particles properties and draw more / less things """ pl = [] for p in self.particles: color = p.color pl.append([p.x+1,p.y+1,0]) pl.append([p.x+1,p.y+1,color]) pl.append([p.x,p.y,color]) print(pl,flush = True) def tick(self): for p in self.particles: p.interact(self.particles) p.move() self.redraw() if __name__ == "__main__": particles = [] simulator = Simulator(particles) try: while True: cli.startFrame() simulator.tick() cli.endFrame() except KeyboardInterrupt: pass