## Noite de Processing - 28 de fevereiro de 2023 # Particle Life ## Versão 0 ```processing= // John na Noite de Processing int N = 800; int especies_N = 4; float color_step = 256.0 / especies_N; int right, left, top, bottom; float[][] leis; Ball[] balls; void setup(){ size( 800, 650 );//displayWidth right = width +10; left = -10; top = -10; bottom = height +10; colorMode(HSB); balls = new Ball[N]; for(int i = 0; i < N; i++ ) balls[i] = new Ball(); leis = new float[especies_N][especies_N]; for(int j = 0; j < especies_N; j++ ){ for(int i = 0; i < especies_N; i++ ){ leis[i][j] = random(-3, 3); print( leis[i][j] + ", " ); } println("."); } noSmooth(); } void draw(){ background(0); noStroke(); for(int i = 0; i < N; i++ ){ balls[i].tick(); balls[i].display(); for(int j = i; j < N; j++ ){ PVector forca = PVector.sub(balls[i].pos, balls[j].pos); float dsq = forca.magSq(); if( dsq < 10000 ){ boolean collision = false; PVector fA = forca.get(); float mag = map( dsq, 10000, 0, 0, 0.001 ); if( dsq < 10 ){ float coll = map( dsq, 10, 0, 0, 1 ); fA.setMag( coll ); collision = true; } else{ fA.setMag( leis[ balls[i].especie ][ balls[j].especie ] * mag ); } balls[i].vel.add( fA ); PVector fB; if( collision ){ fB = fA.get().mult(-1); } else{ fB = forca.get().mult(-1); fB.setMag( leis[ balls[j].especie ][ balls[i].especie ] * mag ); } balls[j].vel.add( fB ); } } } } class Ball{ PVector pos, vel; int especie; Ball(){ pos = new PVector(random(width), random(height)); vel = new PVector(random(-1,1),random(-1,1)); especie = int(random(especies_N)); } void tick(){ pos.add( vel ); vel.mult(0.98);//inercia if( pos.x > right ) pos.x = left; if( pos.x < left ) pos.x = right; if( pos.y > bottom ) pos.y = top; if( pos.y < top ) pos.y = bottom; } void display(){ fill( color(especie*color_step, 255, 255) ); ellipse(pos.x, pos.y, 6, 6); } } ``` ## Versão 1 (outro esquema de loop) ```processing= //V2 int N = 800; int especies_N = 4; float color_step = 256.0 / especies_N; int right, left, top, bottom; float[][] leis; Ball[] balls; void setup(){ size( 800, 650 );//displayWidth right = width +10; left = -10; top = -10; bottom = height +10; colorMode(HSB); balls = new Ball[N]; for(int i = 0; i < N; i++ ) balls[i] = new Ball(); leis = new float[especies_N][especies_N]; for(int j = 0; j < especies_N; j++ ){ for(int i = 0; i < especies_N; i++ ){ leis[i][j] = random(-3, 3); print( leis[i][j] + ", " ); } println("."); } noSmooth(); } void draw(){ background(0); noStroke(); for(int i = 0; i < N; i++ ){ balls[i].tick(); balls[i].display(); for(int j = 0; j < N; j++ ){ PVector forca = PVector.sub(balls[i].pos, balls[j].pos); float dsq = forca.magSq(); if( dsq < 10000 ){ float mag = map( dsq, 10000, 0, 0, 0.001 ); if( dsq < 10 ){ mag = map( dsq, 10, 0, 0, 1 ); forca.setMag( mag ); } else{ forca.setMag( leis[ balls[i].especie ][ balls[j].especie ] * mag ); } balls[i].vel.add( forca ); } } } //println(frameRate); } class Ball{ PVector pos, vel; int especie; Ball(){ pos = new PVector(random(width), random(height)); vel = new PVector(random(-1,1),random(-1,1)); especie = int(random(especies_N)); } void tick(){ pos.add( vel ); vel.mult(0.98);//inercia if( pos.x > right ) pos.x = left; if( pos.x < left ) pos.x = right; if( pos.y > bottom ) pos.y = top; if( pos.y < top ) pos.y = bottom; } void display(){ fill( color(especie*color_step, 255, 255) ); ellipse(pos.x, pos.y, 6, 6); } } ``` ## Versão JavaScript do prof. Claudio Esperança https://observablehq.com/@esperanc/particle-life ## Uma versão Python (horrivelmente lerda) ```python= # usando py5 (py5coding.org) module mode agora import py5 N = 100 especies_n = 4 color_step = 256.0 / especies_n leis = [[0] * especies_n for _ in range(especies_n)] balls = [] def setup(): global right, left, top, bottom py5.size(800, 650) # displayWidth py5.no_smooth() right = py5.width + 10 left = -10 top = -10 bottom = py5.height + 10 py5.color_mode(py5.HSB) balls[:] = [Ball() for _ in range(N)] for j in range(especies_n): for i in range(especies_n): leis[i][j] = py5.random(-3, 3) print(leis) def draw(): py5.background(0) py5.no_stroke() for ball_i in balls: ball_i.tick() ball_i.display() for ball_j in balls: forca = ball_i.pos - ball_j.pos dsq = forca.mag_sq if ball_i is not ball_j and dsq < 10000: if(dsq < 10): m = py5.remap(dsq, 10, 0, 0, 1) if m < 0: forca *= -1 m = -m forca.mag = m else: m = py5.remap(dsq, 10000, 0, 0, 0.001) lm = leis[ball_i.especie][ball_j.especie] * m if lm < 0: forca *= -1 lm = -lm forca.mag = lm ball_i.vel += forca py5.window_title(f'{py5.get_frame_rate():.1f}') class Ball: def __init__(self): self.pos = py5.Py5Vector(py5.random(py5.width), py5.random(py5.height)) self.vel = py5.Py5Vector(py5.random(-1, 1), py5.random(-1, 1)) self.especie = int(py5.random(especies_n)) def tick(self): self.pos += self.vel self.vel *= 0.98 if self.pos.x > right: self.pos.x = left if self.pos.x < left: self.pos.x = right if self.pos.y > bottom: self.pos.y = top if self.pos.y < top: self.pos.y = bottom def display(self): py5.fill(self.especie * color_step, 255, 255) py5.ellipse(self.pos.x, self.pos.y, 6, 6) py5.run_sketch() ```