├── demo └── demo.gif ├── readme.md └── sketch_Localized_Attraction_Repulsion ├── Particle.pde ├── sketch_Localized_Attraction_Repulsion.pde └── utils.pde /demo/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ciphrd/LocalizedAttractionRepulsion/1aeb5394162832671d3afc63adfad4dbe7f76314/demo/demo.gif -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Localized Attraction-Repulsion (Particle System) [Processing] 2 | 3 | *This project was released under the MIT License* 4 | 5 | * Instagram: [https://instagram.com/ciphrd](https://instagram.com/ciphrd) 6 | * Blog: [https://ciphered.xyz](https://ciphered.xyz) 7 | * Atomic Clusters article: [https://ciphered.xyz/2020/07/28/lar-(localized-attraction-repulsion):-generative-matter/](https://ciphered.xyz/2020/07/28/lar-(localized-attraction-repulsion):-generative-matter/) 8 | 9 | ![LAR demo](demo/demo.gif) 10 | 11 | This project implements the very basis of localized attraction repulsion between particle. The attraction repulsion of particle is a system where each particle is both attracted and repelled by all the other particles of the system. By introducing an attraction range and a repulsion range, the behavior of the particles starts to mimic life-like behaviors and it gives more flexibility to the system. 12 | 13 | The idea is very simple, and I will use this project as a base for more advanced techniques that relies on this. 14 | 15 | ## How to run 16 | 17 | * [Download Processing](https://processing.org/download/) and install it 18 | * Clone this repo 19 | * Open the `sketch_Localized_Attraction_Repulsion.pde` file with Processing 20 | * Run -------------------------------------------------------------------------------- /sketch_Localized_Attraction_Repulsion/Particle.pde: -------------------------------------------------------------------------------- 1 | class Particle { 2 | PVector position; 3 | PVector velocity; 4 | PVector acceleration; 5 | float radius = 5; 6 | 7 | public Particle (float x, float y) { 8 | this.position = new PVector(x, y); 9 | this.velocity = new PVector(0, 0); 10 | this.acceleration = new PVector(0, 0); 11 | } 12 | 13 | // adds the acceleration to the velocity and then the velocity to the 14 | // position, apply friction 15 | public void update () { 16 | this.velocity.add(this.acceleration); 17 | this.acceleration.mult(0); 18 | // velocity gets clamped if over the threshold 19 | float mag = this.velocity.mag(); 20 | if (mag > maxVelocity) { 21 | this.velocity = this.velocity.normalize().mult(maxVelocity); 22 | } 23 | this.position.add(this.velocity); 24 | this.velocity.mult(frictionDecay); 25 | } 26 | 27 | public void draw () { 28 | // draw vectors 29 | // drawVector(acceleration.copy().mult(60), position.x, position.y, new int[]{0, 255, 0, 255}); 30 | 31 | noFill(); 32 | stroke(255); 33 | strokeWeight(2); 34 | 35 | pushMatrix(); 36 | translate(position.x, position.y); 37 | 38 | circle(0, 0, radius*2); 39 | 40 | popMatrix(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sketch_Localized_Attraction_Repulsion/sketch_Localized_Attraction_Repulsion.pde: -------------------------------------------------------------------------------- 1 | // @author ciphrd https://ciphered.xyz 2 | // @license MIT 3 | // 4 | // Localized Attraction-Repulsion 5 | // 6 | // Particles are subject to attraction / repulsion, but the attraction / repulsion only works 7 | // within a specific range, allowing for more diverse behaviors. 8 | // 9 | // This system is described in the following article: 10 | // https://ciphered.xyz/2020/07/28/localized-attraction-repulsion:-generative-matter/ 11 | // 12 | 13 | 14 | // the maximum velocity a particle can reach (it gets clamped if over this value) 15 | float maxVelocity = 1.0; 16 | float frictionDecay = 0.7; 17 | 18 | // attraction strength (Sa in the article) 19 | float attrStrength = 32.0; 20 | // repulsion strength (Sr in the article) 21 | float repStrength = 30.0; 22 | // attraction strength towards the center 23 | float centerAttraction = 0.0001; 24 | 25 | // attraction/repulsion range 26 | float attrRange = 13; 27 | float repRange = 20; 28 | 29 | // collision strength and response strength 30 | float colStrength = 0.5; 31 | float colResponse = 0.3; 32 | 33 | 34 | PVector center = new PVector(256, 256); 35 | 36 | Particle[] particles = new Particle[800]; 37 | 38 | void setup () { 39 | size(512, 512); 40 | 41 | for (int i = 0; i < particles.length; i++) { 42 | particles[i] = new Particle( 43 | random(200) + 156, 44 | random(200) + 156 45 | ); 46 | } 47 | } 48 | 49 | void draw () { 50 | background(0); 51 | 52 | 53 | for (int i = 0; i < particles.length; i++) { 54 | Particle p1 = particles[i]; 55 | PVector col = new PVector(0, 0); 56 | 57 | for (int j = 0; j < particles.length; j++) { 58 | if (i != j) { 59 | Particle p2 = particles[j]; 60 | 61 | PVector D = p2.position.copy().sub(p1.position); 62 | float r = D.mag(); 63 | D = D.normalize(); 64 | 65 | if (r > 0.5) { // prevent weird behavior from particles overlaping 66 | if (r <= attrRange) { 67 | PVector Fa = D.copy().mult(attrStrength).div(r*r); 68 | p1.acceleration.add(Fa); 69 | } 70 | 71 | if (r <= repRange) { 72 | PVector Fr = D.copy().mult(-repStrength).div(r*r); 73 | p1.acceleration.add(Fr); 74 | } 75 | 76 | if (r < p1.radius + p2.radius) { 77 | PVector mv = D.copy().mult(-((p1.radius + p2.radius) - r)); 78 | p1.velocity.add(mv.copy().mult(colStrength)); 79 | p2.velocity.add(mv.mult(-colResponse)); 80 | } 81 | } 82 | } 83 | } 84 | 85 | // we add attraction to the center 86 | p1.acceleration.add(p1.position.copy().sub(center).mult(-centerAttraction)); 87 | 88 | p1.update(); 89 | p1.draw(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /sketch_Localized_Attraction_Repulsion/utils.pde: -------------------------------------------------------------------------------- 1 | // just some utility functions 2 | 3 | void drawVector (PVector V, float x, float y, int[] col) { 4 | stroke(col[0], col[1], col[2], col[3]); 5 | strokeWeight(2); 6 | pushMatrix(); 7 | translate(x, y); 8 | float ang = atan2(V.y, V.x) + PI; 9 | line(0, 0, V.x, V.y); 10 | line(V.x, V.y, V.x + cos(ang+PI*.2) * 10, V.y + sin(ang+PI*.2) * 10); 11 | line(V.x, V.y, V.x + cos(ang-PI*.2) * 10, V.y + sin(ang-PI*.2) * 10); 12 | popMatrix(); 13 | } 14 | --------------------------------------------------------------------------------