├── .gitignore ├── LICENSE ├── README.md ├── chapter0 ├── Example_0_1_Random_Walk │ └── Example_0_1_Random_Walk.pde ├── Example_0_2_Random_Distribution │ └── Example_0_2_Random_Distribution.pde ├── Example_0_3_Random_Walk_Tends_To_Right │ └── Example_0_3_Random_Walk_Tends_To_Right.pde ├── Example_0_4_Gaussian_Distribution │ └── Example_0_4_Gaussian_Distribution.pde ├── Example_0_5_Accept_Reject_Distribution │ └── Example_0_5_Accept_Reject_Distribution.pde └── Example_0_6_Perlin_Noise_Walker │ └── Example_0_6_Perlin_Noise_Walker.pde ├── chapter1 ├── Example_1_10_Accelerating_Towards_Mouse │ ├── Example_1_10_Accelerating_Towards_Mouse.pde │ └── Mover.pde ├── Example_1_1_Bouncing_Ball_No_Vectors │ └── Example_1_1_Bouncing_Ball_No_Vectors.pde ├── Example_1_2_Bouncing_Ball_Vectors │ └── Example_1_2_Bouncing_Ball_Vectors.pde ├── Example_1_3_Vector_Subtraction │ └── Example_1_3_Vector_Subtraction.pde ├── Example_1_4_Vector_Multiplication │ └── Example_1_4_Vector_Multiplication.pde ├── Example_1_5_Vector_Magnitude │ └── Example_1_5_Vector_Magnitude.pde ├── Example_1_6_Vector_Normalize │ └── Example_1_6_Vector_Normalize.pde ├── Example_1_7_Motion_101_Velocity │ ├── Example_1_7_Motion_101_Velocity.pde │ └── Mover.pde ├── Example_1_8_Motion_101_Velocity_And_Constant_Acceleration │ ├── Example_1_8_Motion_101_Velocity_And_Constant_Acceleration.pde │ └── Mover.pde └── Example_1_9_Motion_101_Velocity_And_Random_Acceleration │ ├── Example_1_9_Motion_101_Velocity_And_Random_Acceleration.pde │ └── Mover.pde ├── chapter11 └── Example_11_1_Flappy_Bird │ ├── Bird.pde │ ├── Example_11_1_Flappy_Bird.pde │ └── Pipe.pde ├── chapter2 ├── Example_2_1_Forces │ ├── Example_2_1_Forces.pde │ └── Mover.pde ├── Example_2_2_Forces_Acting_On_Two_Objects │ ├── Example_2_2_Forces_Acting_On_Two_Objects.pde │ └── Mover.pde ├── Example_2_3_Gravity_Scaled_By_Mass │ ├── Example_2_3_Gravity_Scaled_By_Mass.pde │ └── Mover.pde ├── Example_2_4_Including_Friction │ ├── Example_2_4_Including_Friction.pde │ └── Mover.pde ├── Example_2_5_Fluid_Resistance │ ├── Example_2_5_Fluid_Resistance.pde │ ├── Liquid.pde │ └── Mover.pde ├── Example_2_6_Attraction │ ├── Attractor.pde │ ├── Example_2_6_Attraction.pde │ └── Mover.pde ├── Example_2_7_Attraction_With_Many_Movers │ ├── Attractor.pde │ ├── Example_2_7_Attraction_With_Many_Movers.pde │ └── Mover.pde ├── Example_2_8_Two_Body_Attraction │ ├── Body.pde │ └── Example_2_8_Two_Body_Attraction.pde └── Example_2_9_N_Bodies │ ├── Body.pde │ └── Example_2_9_N_Bodies.pde ├── chapter3 ├── Example_3_10_A_Spring_Connection │ ├── Bob.pde │ ├── Example_3_10_A_Spring_Connection.pde │ └── Spring.pde ├── Example_3_11_Swinging_Pendulum │ ├── Example_3_11_Swinging_Pendulum.pde │ └── Pendulum.pde ├── Example_3_1_Angular_Motion_Using_Rotate │ └── Example_3_1_Angular_Motion_Using_Rotate.pde ├── Example_3_2_Forces_With_Arbitrary_Angular_Motion │ ├── Attractor.pde │ ├── Example_3_2_Forces_With_Arbitrary_Angular_Motion.pde │ └── Mover.pde ├── Example_3_3_Pointing_In_The_Direction_Of_Motion │ ├── Example_3_3_Pointing_In_The_Direction_Of_Motion.pde │ └── Mover.pde ├── Example_3_4_Polar_To_Cartesian │ └── Example_3_4_Polar_To_Cartesian.pde ├── Example_3_5_Simple_Harmonic_Motion │ └── Example_3_5_Simple_Harmonic_Motion.pde ├── Example_3_6_Simple_Harmonic_Motion_II │ └── Example_3_6_Simple_Harmonic_Motion_II.pde ├── Example_3_7_Oscillator_Objects │ ├── Example_3_7_Oscillator_Objects.pde │ └── Oscillator.pde ├── Example_3_8_Static_Wave │ └── Example_3_8_Static_Wave.pde └── Example_3_9_The_Wave │ └── Example_3_9_The_Wave.pde ├── chapter4 ├── Example_4_1_Single_Particle │ ├── Example_4_1_Single_Particle.pde │ └── Particle.pde ├── Example_4_2_Array_Of_Particles │ ├── Example_4_2_Array_Of_Particles.pde │ └── Particle.pde ├── Example_4_3_A_Particle_Emitter │ ├── Emitter.pde │ ├── Example_4_3_A_Particle_Emitter.pde │ └── Particle.pde ├── Example_4_4_A_System_Of_Systems │ ├── Emitter.pde │ ├── Example_4_4_A_System_Of_Systems.pde │ └── Particle.pde ├── Example_4_5_Particle_System_With_Inheritance_And_Polymorphism │ ├── Confetti.pde │ ├── Emitter.pde │ ├── Example_4_5_Particle_System_With_Inheritance_And_Polymorphism.pde │ └── Particle.pde ├── Example_4_6_Particle_System_With_Forces │ ├── Emitter.pde │ ├── Example_4_6_Particle_System_With_Forces.pde │ └── Particle.pde ├── Example_4_7_Particle_System_With_Repeller │ ├── Emitter.pde │ ├── Example_4_7_Particle_System_With_Repeller.pde │ ├── Particle.pde │ └── Repeller.pde ├── Example_4_8_Image_Texture_System_Smoke │ ├── Emitter.pde │ ├── Example_4_8_Image_Texture_System_Smoke.pde │ ├── Particle.pde │ └── data │ │ └── texture.png └── Example_4_9_Additive_Blending │ ├── Emitter.pde │ ├── Example_4_9_Additive_Blending.pde │ ├── Particle.pde │ └── data │ └── texture.png ├── chapter5 ├── Example_5_10_Combining_Seek_Separate │ ├── Example_5_10_Combining_Seek_Separate.pde │ └── Vehicle.pde ├── Example_5_11_Flocking │ ├── Boid.pde │ ├── Example_5_11_Flocking.pde │ └── Flock.pde ├── Example_5_12_Bin_Lattice_Spatial_Separation │ ├── Boid.pde │ ├── Example_5_12_Bin_Lattice_Spatial_Separation.pde │ └── Flock.pde ├── Example_5_13_QuadTree │ ├── Example_5_13_QuadTree.pde │ └── QuadTree.pde ├── Example_5_14_COS_SIN_LUT │ └── Example_5_14_COS_SIN_LUT.pde ├── Example_5_1_Seek │ ├── Example_5_1_Seek.pde │ └── Vehicle.pde ├── Example_5_2_Arrive │ ├── Example_5_2_Arrive.pde │ └── Vehicle.pde ├── Example_5_3_Stay_Within_Walls │ ├── Example_5_3_Stay_Within_Walls.pde │ └── Vehicle.pde ├── Example_5_4_Flow_Field │ ├── Example_5_4_Flow_Field.pde │ ├── FlowField.pde │ └── Vehicle.pde ├── Example_5_5_Create_Path_Object │ ├── Example_5_5_Create_Path_Object.pde │ └── Path.pde ├── Example_5_6_Simple_Path_Following │ ├── Example_5_6_Simple_Path_Following.pde │ ├── Path.pde │ └── Vehicle.pde ├── Example_5_7_Multiple_Segments │ ├── Example_5_7_Multiple_Segments.pde │ └── Path.pde ├── Example_5_8_Path_Following │ ├── Example_5_8_Path_Following.pde │ ├── Path.pde │ └── Vehicle.pde └── Example_5_9_Separation │ ├── Example_5_9_Separation.pde │ └── Vehicle.pde ├── chapter7 ├── Example_7_1_Wolfram_Elementary_Cellular_Automata │ └── Example_7_1_Wolfram_Elementary_Cellular_Automata.pde ├── Example_7_2_Game_of_Life │ └── Example_7_2_Game_of_Life.pde └── Example_7_3_Object_Oriented_Game_of_Life │ ├── Cell.pde │ └── Example_7_3_Object_Oriented_Game_of_Life.pde └── chapter8 ├── Example_8_1_Recursive_Circles_Once └── Example_8_1_Recursive_Circles_Once.pde ├── Example_8_2_Recursive_Circles_Twice └── Example_8_2_Recursive_Circles_Twice.pde ├── Example_8_3_Recursive_Circles_Four_Times └── Example_8_3_Recursive_Circles_Four_Times.pde ├── Example_8_4_Cantor_Set └── Example_8_4_Cantor_Set.pde ├── Example_8_5_Koch_Curve ├── Example_8_5_Koch_Curve.pde └── KochLine.pde ├── Example_8_6_Recursive_Tree └── Example_8_6_Recursive_Tree.pde ├── Example_8_7_Stochastic_Tree └── Example_8_7_Stochastic_Tree.pde ├── Example_8_8_LSystem_String_Only └── Example_8_8_LSystem_String_Only.pde └── Example_8_9_LSystem ├── Example_8_9_LSystem.pde ├── LSystem.pde └── Turtle.pde /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 The Nature of Code 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Nature of Code: Porting from p5.js to Processing 2 | 3 | This repository is a collaborative effort to port the code examples from [Daniel Shiffman's book *The Nature of Code*](https://natureofcode.com/) from the JavaScript library **p5.js** to the **Processing** programming language. 4 | 5 | ## Repository Structure 6 | 7 | The code examples are organized by chapters, starting from Chapter 0. Within each chapter, examples are numbered sequentially (e.g., `Example_0_1`, `Example_0_2`). 8 | 9 | ``` 10 | /chapter0/ 11 | Example_0_1/ 12 | Example_0_2/ 13 | ... 14 | /chapter1/ 15 | Example_1_1/ 16 | Example_1_2/ 17 | ... 18 | ``` 19 | 20 | Each example is contained in its respective folder to make navigation straightforward. 21 | The names of the main sketche files should be the same as the folder they are in 22 | 23 | ## Porting Example 24 | 25 | To see how the first example in the book was ported (Example_0_1) by Dan, check out [this livestream](https://www.youtube.com/live/qNqKeMa9yBU?si=kevmtdfZMXmcXi2N&t=3218). 26 | 27 | ## Contribution Guidelines 28 | 29 | We welcome contributions from the community! If you'd like to help port examples to Processing, please follow these guidelines: 30 | 31 | 1. Ensure the ported code adheres to Processing's syntax yet stays in the same style conventions. 32 | 2. Keep the functionality and code structure as close to the original p5.js example as possible. 33 | 3. Test your code to ensure it runs properly in Processing. 34 | 4. Make sure to change window size from (640,240) -> (640,360) and make sure everything is still centered and looks correct in the new window size 35 | 5. Replace the p5.js function `createP()` to the Processing function `println()` 36 | 37 | all the code examples are available in the [*The Nature of Code* Website](https://natureofcode.com/). 38 | 39 | Feel free to open a pull request or raise an issue if you have questions or suggestions! 40 | -------------------------------------------------------------------------------- /chapter0/Example_0_1_Random_Walk/Example_0_1_Random_Walk.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Walker walker; 6 | 7 | void setup() { 8 | size(640, 360); 9 | walker = new Walker(); 10 | background(255); 11 | } 12 | 13 | void draw() { 14 | walker.step(); 15 | walker.show(); 16 | } 17 | 18 | class Walker { 19 | float x,y; 20 | 21 | Walker() { 22 | this.x = width / 2; 23 | this.y = height / 2; 24 | } 25 | 26 | void show() { 27 | stroke(0); 28 | point(this.x, this.y); 29 | } 30 | 31 | void step() { 32 | int choice = floor(random(4)); 33 | if (choice == 0) { 34 | this.x++; 35 | } else if (choice == 1) { 36 | this.x--; 37 | } else if (choice == 2) { 38 | this.y++; 39 | } else { 40 | this.y--; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter0/Example_0_2_Random_Distribution/Example_0_2_Random_Distribution.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // An array to keep track of how often random numbers are picked 6 | 7 | int[] randomCounts; 8 | int total = 20; 9 | 10 | void setup() { 11 | size(640, 360); 12 | randomCounts = new int[total]; 13 | for (int i = 0; i < total; i++) { 14 | randomCounts[i] = 0; 15 | } 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | int index = floor(random(total)); 21 | randomCounts[index]++; 22 | 23 | // Draw a rectangle to graph results 24 | stroke(0); 25 | strokeWeight(2); 26 | fill(127); 27 | int w = width / randomCounts.length; 28 | 29 | for (int x = 0; x < randomCounts.length; x++) { 30 | rect(x * w, height - randomCounts[x], w - 1, randomCounts[x]); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter0/Example_0_3_Random_Walk_Tends_To_Right/Example_0_3_Random_Walk_Tends_To_Right.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Walker walker; 6 | 7 | void setup() { 8 | size(640, 360); 9 | // Creating the Walker object! 10 | walker = new Walker(); 11 | background(255); 12 | } 13 | 14 | void draw() { 15 | walker.step(); 16 | walker.show(); 17 | } 18 | 19 | class Walker { 20 | float x, y; 21 | 22 | Walker() { 23 | this.x = width / 2; 24 | this.y = height / 2; 25 | } 26 | 27 | void show() { 28 | stroke(0); 29 | point(this.x, this.y); 30 | } 31 | 32 | void step() { 33 | float r = random(1); 34 | // A 40% of moving to the right! 35 | if (r < 0.4) { 36 | this.x++; 37 | } else if (r < 0.6) { 38 | this.x--; 39 | } else if (r < 0.8) { 40 | this.y++; 41 | } else { 42 | this.y--; 43 | } 44 | this.x = constrain(this.x, 0, width - 1); 45 | this.y = constrain(this.y, 0, height - 1); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chapter0/Example_0_4_Gaussian_Distribution/Example_0_4_Gaussian_Distribution.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | void setup() { 6 | size(640, 360); 7 | background(255); 8 | } 9 | 10 | void draw() { 11 | // A normal distribution with mean 320 and standard deviation 60 12 | float x = randomGaussian() * 60 + 320; 13 | noStroke(); 14 | fill(0, 10); 15 | circle(x, 120, 16); 16 | } 17 | -------------------------------------------------------------------------------- /chapter0/Example_0_5_Accept_Reject_Distribution/Example_0_5_Accept_Reject_Distribution.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // An array to keep track of how often random numbers are picked 6 | int[] randomCounts; 7 | int total = 20; 8 | 9 | void setup() { 10 | size(640, 360); 11 | randomCounts = new int[total]; 12 | for (int i = 0; i < total; i++) { 13 | randomCounts[i] = 0; 14 | } 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | 20 | // Pick a random number and increase the count 21 | int index = int(acceptreject() * randomCounts.length); 22 | randomCounts[index]++; 23 | 24 | // Draw a rectangle to graph results 25 | stroke(0); 26 | strokeWeight(2); 27 | fill(127); 28 | 29 | int w = width / randomCounts.length; 30 | 31 | for (int x = 0; x < randomCounts.length; x++) { 32 | rect(x * w, height - randomCounts[x], w - 1, randomCounts[x]); 33 | } 34 | } 35 | 36 | // An algorithm for picking a random number based on monte carlo method 37 | // Here probability is determined by formula y = x 38 | float acceptreject() { 39 | // We do this “forever” until we find a qualifying random value. 40 | while (true) { 41 | // Pick a random value. 42 | float r1 = random(1); 43 | // Assign a probability. 44 | float probability = r1; 45 | // Pick a second random value. 46 | float r2 = random(1); 47 | 48 | //{!3} Does it qualify? If so, we’re done! 49 | if (r2 < probability) { 50 | return r1; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /chapter0/Example_0_6_Perlin_Noise_Walker/Example_0_6_Perlin_Noise_Walker.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Walker walker; 6 | 7 | void setup() { 8 | size(640, 360); // creating canvas of size 640 x 240 9 | walker = new Walker(); // creating an instance/object of class Walker 10 | background(255); 11 | } 12 | 13 | void draw() { 14 | walker.step(); 15 | walker.show(); 16 | } 17 | 18 | class Walker { 19 | float tx, ty; 20 | float x, y; 21 | 22 | Walker() { 23 | this.tx = 0; 24 | this.ty = 10000; 25 | } 26 | 27 | void step() { 28 | // x- and y-position mapped from noise 29 | this.x = map(noise(this.tx), 0, 1, 0, width); 30 | this.y = map(noise(this.ty), 0, 1, 0, height); 31 | 32 | // Move forward through time. 33 | this.tx += 0.01; 34 | this.ty += 0.01; 35 | } 36 | 37 | void show() { 38 | strokeWeight(2); 39 | fill(127); 40 | stroke(0); 41 | circle(this.x, this.y, 48); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter1/Example_1_10_Accelerating_Towards_Mouse/Example_1_10_Accelerating_Towards_Mouse.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Demonstration of the basics of motion with vector. 6 | // A "Mover" object stores position, velocity, and acceleration as vectors 7 | // The motion is controlled by affecting the acceleration (in this case towards the mouse) 8 | 9 | Mover mover; 10 | 11 | void setup() { 12 | size(640, 360); 13 | mover = new Mover(); 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | 19 | mover.update(); 20 | mover.show(); 21 | } 22 | -------------------------------------------------------------------------------- /chapter1/Example_1_10_Accelerating_Towards_Mouse/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | PVector position, velocity, acceleration; 7 | float topspeed; 8 | 9 | Mover() { 10 | this.position = new PVector(width / 2, height / 2); 11 | this.velocity = new PVector(); 12 | this.acceleration = new PVector(); 13 | this.topspeed = 5; 14 | } 15 | 16 | void update() { 17 | 18 | PVector mouse = new PVector(mouseX, mouseY); 19 | // Step 1: Compute direction 20 | PVector dir = PVector.sub(mouse, this.position); 21 | 22 | // Step 2: Normalize 23 | dir.normalize(); 24 | 25 | // Step 3: Scale 26 | dir.mult(0.2); 27 | 28 | // Steps 2 and 3 could be combined into: 29 | // dir.setMag(0.2); 30 | 31 | // Step 4: Accelerate 32 | this.acceleration = dir; 33 | 34 | this.velocity.add(this.acceleration); 35 | this.velocity.limit(this.topspeed); 36 | this.position.add(this.velocity); 37 | 38 | } 39 | 40 | void show() { 41 | stroke(0); 42 | strokeWeight(2); 43 | fill(127); 44 | circle(this.position.x, this.position.y, 48); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /chapter1/Example_1_1_Bouncing_Ball_No_Vectors/Example_1_1_Bouncing_Ball_No_Vectors.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 1-1: Bouncing Ball, no vectors 6 | // Variables for position and speed of ball. 7 | float x = 100; 8 | float y = 100; 9 | float xspeed = 2.5; 10 | float yspeed = 2; 11 | 12 | void setup() { 13 | size(640, 360); 14 | background(255); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | 20 | // Move the ball according to its speed. 21 | x = x + xspeed; 22 | y = y + yspeed; 23 | 24 | //Check for bouncing. 25 | if (x > width || x < 0) { 26 | xspeed = xspeed * -1; 27 | } 28 | if (y > height || y < 0) { 29 | yspeed = yspeed * -1; 30 | } 31 | 32 | stroke(0); 33 | fill(127); 34 | strokeWeight(2); 35 | //Draw the ball at the position (x,y). 36 | circle(x, y, 48); 37 | } 38 | -------------------------------------------------------------------------------- /chapter1/Example_1_2_Bouncing_Ball_Vectors/Example_1_2_Bouncing_Ball_Vectors.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 1-2: Bouncing Ball, with PVector! 6 | //Instead of a bunch of floats, we now just have two variables. 7 | PVector position; 8 | PVector velocity; 9 | 10 | void setup() { 11 | size(640, 360); 12 | //Note how PVector() has to be called inside of setup(). 13 | position = new PVector(100, 100); 14 | velocity = new PVector(2.5, 2); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | position.add(velocity); 20 | 21 | //We still sometimes need to refer to the individual components of a PVector and can do so using the dot syntax: position.x, velocity.y, etc. 22 | if (position.x > width || position.x < 0) { 23 | velocity.x = velocity.x * -1; 24 | } 25 | if (position.y > height || position.y < 0) { 26 | velocity.y = velocity.y * -1; 27 | } 28 | 29 | stroke(0); 30 | fill(127); 31 | strokeWeight(2); 32 | circle(position.x, position.y, 48); 33 | } 34 | -------------------------------------------------------------------------------- /chapter1/Example_1_3_Vector_Subtraction/Example_1_3_Vector_Subtraction.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 1-3: Vector subtraction 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | 14 | // Two vectors, one for the mouse position and one for the center of the window 15 | PVector mouse = new PVector(mouseX, mouseY); 16 | PVector center = new PVector(width / 2, height / 2); 17 | 18 | // Draw the original two vectors 19 | strokeWeight(4); 20 | stroke(200); 21 | line(0, 0, mouse.x, mouse.y); 22 | line(0, 0, center.x, center.y); 23 | 24 | // Vector subtraction! 25 | mouse.sub(center); 26 | 27 | // Draw a line to represent the result of subtraction. 28 | // Notice how I move the origin with translate() to place the vector 29 | stroke(0); 30 | translate(width / 2, height / 2); 31 | line(0, 0, mouse.x, mouse.y); 32 | } 33 | -------------------------------------------------------------------------------- /chapter1/Example_1_4_Vector_Multiplication/Example_1_4_Vector_Multiplication.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 1-4: Vector multiplication 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | 14 | PVector mouse = new PVector(mouseX, mouseY); 15 | PVector center = new PVector(width / 2, height / 2); 16 | mouse.sub(center); 17 | 18 | translate(width / 2, height / 2); 19 | strokeWeight(2); 20 | stroke(200); 21 | line(0, 0, mouse.x, mouse.y); 22 | 23 | //Multiplying a vector! The vector is now half its original size (multiplied by 0.5). 24 | mouse.mult(0.5); 25 | 26 | stroke(0); 27 | strokeWeight(4); 28 | line(0, 0, mouse.x, mouse.y); 29 | } 30 | -------------------------------------------------------------------------------- /chapter1/Example_1_5_Vector_Magnitude/Example_1_5_Vector_Magnitude.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 1-5: Vector magnitude 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | 14 | PVector mouse = new PVector(mouseX, mouseY); 15 | PVector center = new PVector(width / 2, height / 2); 16 | mouse.sub(center); 17 | 18 | //The magnitude (i.e. length) of a vector can be accessed via the mag() function. Here it is used as the width of a rectangle drawn at the top of the window. 19 | float m = mouse.mag(); 20 | fill(0); 21 | rect(10, 10, m, 10); 22 | 23 | translate(width / 2, height / 2); 24 | line(0, 0, mouse.x, mouse.y); 25 | } 26 | -------------------------------------------------------------------------------- /chapter1/Example_1_6_Vector_Normalize/Example_1_6_Vector_Normalize.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Demonstration of normalizing a vector. 6 | // Normalizing a vector sets its length to 1. 7 | 8 | void setup() { 9 | size(640, 360); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | // A vector that points to the mouse position 16 | PVector mouse = new PVector(mouseX, mouseY); 17 | // A vector that points to the center of the window 18 | PVector center = new PVector(width / 2, height / 2); 19 | // Subtract center from mouse which results in a vector that points from center to mouse 20 | mouse.sub(center); 21 | 22 | translate(width / 2, height / 2); 23 | stroke(200); 24 | strokeWeight(2); 25 | line(0, 0, mouse.x, mouse.y); 26 | 27 | // Normalize the vector 28 | mouse.normalize(); 29 | 30 | // Multiply its length by 50 31 | mouse.mult(50); 32 | 33 | // Draw the resulting vector 34 | stroke(0); 35 | strokeWeight(8); 36 | line(0, 0, mouse.x, mouse.y); 37 | } 38 | -------------------------------------------------------------------------------- /chapter1/Example_1_7_Motion_101_Velocity/Example_1_7_Motion_101_Velocity.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | mover.update(); 16 | mover.checkEdges(); 17 | mover.show(); 18 | } 19 | -------------------------------------------------------------------------------- /chapter1/Example_1_7_Motion_101_Velocity/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | PVector position, velocity; 7 | 8 | Mover() { 9 | this.position = new PVector(random(width), random(height)); 10 | this.velocity = new PVector(random(-2, 2), random(-2, 2)); 11 | } 12 | 13 | void update() { 14 | this.position.add(this.velocity); 15 | } 16 | 17 | void show() { 18 | stroke(0); 19 | strokeWeight(2); 20 | fill(127); 21 | circle(this.position.x, this.position.y, 48); 22 | } 23 | 24 | void checkEdges() { 25 | if (this.position.x > width) { 26 | this.position.x = 0; 27 | } else if (this.position.x < 0) { 28 | this.position.x = width; 29 | } 30 | 31 | if (this.position.y > height) { 32 | this.position.y = 0; 33 | } else if (this.position.y < 0) { 34 | this.position.y = height; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter1/Example_1_8_Motion_101_Velocity_And_Constant_Acceleration/Example_1_8_Motion_101_Velocity_And_Constant_Acceleration.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | mover.show(); 15 | mover.update(); 16 | mover.checkEdges(); 17 | } 18 | -------------------------------------------------------------------------------- /chapter1/Example_1_8_Motion_101_Velocity_And_Constant_Acceleration/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | PVector position, velocity, acceleration; 7 | float topSpeed; 8 | 9 | Mover() { 10 | this.position = new PVector(width / 2, height / 2); 11 | this.velocity = new PVector(); 12 | this.acceleration = new PVector(-0.001, 0.01); 13 | this.topSpeed = 10; 14 | } 15 | 16 | void update() { 17 | this.velocity.add(this.acceleration); 18 | this.velocity.limit(this.topSpeed); 19 | this.position.add(this.velocity); 20 | } 21 | 22 | void show() { 23 | stroke(0); 24 | strokeWeight(2); 25 | fill(127); 26 | circle(this.position.x, this.position.y, 48); 27 | } 28 | 29 | void checkEdges() { 30 | if (this.position.x > width) { 31 | this.position.x = 0; 32 | } else if (this.position.x < 0) { 33 | this.position.x = width; 34 | } 35 | 36 | if (this.position.y > height) { 37 | this.position.y = 0; 38 | } else if (this.position.y < 0) { 39 | this.position.y = height; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /chapter1/Example_1_9_Motion_101_Velocity_And_Random_Acceleration/Example_1_9_Motion_101_Velocity_And_Random_Acceleration.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | mover.update(); 16 | mover.checkEdges(); 17 | mover.show(); 18 | } 19 | -------------------------------------------------------------------------------- /chapter1/Example_1_9_Motion_101_Velocity_And_Random_Acceleration/Mover.pde: -------------------------------------------------------------------------------- 1 | 2 | 3 | // The Nature of Code 4 | // Daniel Shiffman 5 | // http://natureofcode.com 6 | 7 | class Mover{ 8 | PVector position, velocity, acceleration; 9 | float topSpeed; 10 | 11 | Mover(){ 12 | this.position = new PVector(width/2,height/2); 13 | this.velocity = new PVector(); 14 | this.acceleration = new PVector(); 15 | this.topSpeed = 5; 16 | } 17 | 18 | void update() { 19 | // The random2D() function returns a unit vector pointing in a random direction. 20 | this.acceleration = PVector.random2D(); 21 | this.acceleration.mult(random(2)); 22 | 23 | this.velocity.add(this.acceleration); 24 | this.velocity.limit(this.topSpeed); 25 | this.position.add(this.velocity); 26 | } 27 | 28 | void show() { 29 | stroke(0); 30 | strokeWeight(2); 31 | fill(127); 32 | circle(this.position.x, this.position.y, 48); 33 | } 34 | 35 | void checkEdges() { 36 | 37 | if (this.position.x > width) { 38 | this.position.x = 0; 39 | } 40 | else if (this.position.x < 0) { 41 | this.position.x = width; 42 | } 43 | 44 | if (this.position.y > height) { 45 | this.position.y = 0; 46 | } 47 | else if (this.position.y < 0) { 48 | this.position.y = height; 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /chapter11/Example_11_1_Flappy_Bird/Bird.pde: -------------------------------------------------------------------------------- 1 | class Bird { 2 | int x; 3 | int y; 4 | float velocity; 5 | float gravity; 6 | int flapForce; 7 | 8 | Bird() { 9 | // The bird's position (x will be constant) 10 | this.x = 50; 11 | this.y = 120; 12 | 13 | // Velocity and forces are scalar since the bird only moves along the y-axis 14 | this.velocity = 0; 15 | this.gravity = 0.5; 16 | this.flapForce = -10; 17 | } 18 | 19 | // The bird flaps its wings 20 | void flap() { 21 | this.velocity += this.flapForce; 22 | } 23 | 24 | void update() { 25 | // Add gravity 26 | this.velocity += this.gravity; 27 | this.y += this.velocity; 28 | // Dampen velocity 29 | this.velocity *= 0.95; 30 | 31 | // Handle the "floor" 32 | if (this.y > height) { 33 | this.y = height; 34 | this.velocity = 0; 35 | } 36 | } 37 | 38 | void show() { 39 | strokeWeight(2); 40 | stroke(0); 41 | fill(127); 42 | circle(this.x, this.y, 16); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter11/Example_11_1_Flappy_Bird/Example_11_1_Flappy_Bird.pde: -------------------------------------------------------------------------------- 1 | import java.util.List; 2 | 3 | Bird bird; 4 | List pipes = new ArrayList(); 5 | 6 | void setup() { 7 | size(640, 360); 8 | bird = new Bird(); 9 | pipes.add(new Pipe()); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | for (int i = pipes.size() - 1; i >= 0; i--) { 16 | pipes.get(i).show(); 17 | pipes.get(i).update(); 18 | 19 | if (pipes.get(i).collides(bird)) { 20 | text("OOPS!", pipes.get(i).x, pipes.get(i).top + 20); 21 | } 22 | 23 | if (pipes.get(i).offscreen()) { 24 | pipes.remove(i); 25 | } 26 | } 27 | 28 | bird.update(); 29 | bird.show(); 30 | 31 | if (frameCount % 100 == 0) { 32 | pipes.add(new Pipe()); 33 | } 34 | } 35 | 36 | void mousePressed() { 37 | bird.flap(); 38 | } 39 | -------------------------------------------------------------------------------- /chapter11/Example_11_1_Flappy_Bird/Pipe.pde: -------------------------------------------------------------------------------- 1 | class Pipe { 2 | int spacing; 3 | float top; 4 | float bottom; 5 | int x; 6 | int w; 7 | int velocity; 8 | 9 | Pipe() { 10 | this.spacing = 100; 11 | this.top = random(height - this.spacing); 12 | this.bottom = this.top + this.spacing; 13 | this.x = width; 14 | this.w = 20; 15 | this.velocity = 2; 16 | } 17 | 18 | boolean collides(Bird bird) { 19 | // Is the bird within the vertical range of the top or bottom pipe? 20 | boolean verticalCollision = bird.y < this.top || bird.y > this.bottom; 21 | // Is the bird within the horizontal range of the pipes? 22 | boolean horizontalCollision = bird.x > this.x && bird.x < this.x + this.w; 23 | // If it's both a vertical and horizontal hit, it's a hit! 24 | return verticalCollision && horizontalCollision; 25 | } 26 | 27 | void show() { 28 | fill(0); 29 | noStroke(); 30 | rect(this.x, 0, this.w, this.top); 31 | rect(this.x, this.bottom, this.w, height - this.bottom); 32 | } 33 | 34 | void update() { 35 | this.x -= this.velocity; 36 | } 37 | 38 | boolean offscreen() { 39 | return this.x < -this.w; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /chapter2/Example_2_1_Forces/Example_2_1_Forces.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(); 10 | println("Click mouse to apply wind force."); 11 | } 12 | 13 | void draw() { 14 | background(255); 15 | 16 | PVector gravity = new PVector(0, 0.1); 17 | mover.applyForce(gravity); 18 | 19 | if (mousePressed) { 20 | PVector wind = new PVector(0.1, 0); 21 | mover.applyForce(wind); 22 | } 23 | 24 | mover.update(); 25 | mover.display(); 26 | mover.checkEdges(); 27 | } 28 | -------------------------------------------------------------------------------- /chapter2/Example_2_1_Forces/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover() { 10 | this.mass = 1; 11 | this.position = new PVector(width / 2, 30); 12 | this.velocity = new PVector(0, 0); 13 | this.acceleration = new PVector(0, 0); 14 | } 15 | 16 | void applyForce(PVector force) { 17 | PVector f = PVector.div(force, this.mass); 18 | this.acceleration.add(f); 19 | } 20 | 21 | void update() { 22 | this.velocity.add(this.acceleration); 23 | this.position.add(this.velocity); 24 | this.acceleration.mult(0); 25 | } 26 | 27 | void display() { 28 | stroke(0); 29 | strokeWeight(2); 30 | fill(127, 127); 31 | ellipse(this.position.x, this.position.y, 48, 48); 32 | } 33 | 34 | void checkEdges() { 35 | if (this.position.x > width) { 36 | this.position.x = width; 37 | this.velocity.x *= -1; 38 | } else if (this.position.x < 0) { 39 | this.velocity.x *= -1; 40 | this.position.x = 0; 41 | } 42 | if (this.position.y > height) { 43 | this.velocity.y *= -1; 44 | this.position.y = height; 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /chapter2/Example_2_2_Forces_Acting_On_Two_Objects/Example_2_2_Forces_Acting_On_Two_Objects.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover moverA; 6 | Mover moverB; 7 | 8 | void setup() { 9 | size(640, 360); 10 | // A large Mover on the left side of the window 11 | moverA = new Mover(200, 30, 10); 12 | // A smaller Mover on the right side of the window 13 | moverB = new Mover(440, 30, 2); 14 | println("Click mouse to apply wind force."); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | 20 | PVector gravity = new PVector(0, 0.1); 21 | moverA.applyForce(gravity); 22 | moverB.applyForce(gravity); 23 | 24 | if (mousePressed) { 25 | PVector wind = new PVector(0.1, 0); 26 | moverA.applyForce(wind); 27 | moverB.applyForce(wind); 28 | } 29 | 30 | moverA.update(); 31 | moverA.show(); 32 | moverA.checkEdges(); 33 | 34 | moverB.update(); 35 | moverB.show(); 36 | moverB.checkEdges(); 37 | } 38 | -------------------------------------------------------------------------------- /chapter2/Example_2_2_Forces_Acting_On_Two_Objects/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.position = new PVector(x, y); 12 | this.velocity = new PVector(0, 0); 13 | this.acceleration = new PVector(0, 0); 14 | } 15 | 16 | void applyForce(PVector force) { 17 | PVector f = PVector.div(force, this.mass); 18 | this.acceleration.add(f); 19 | } 20 | 21 | void update() { 22 | this.velocity.add(this.acceleration); 23 | this.position.add(this.velocity); 24 | this.acceleration.mult(0); 25 | } 26 | 27 | void show() { 28 | stroke(0); 29 | strokeWeight(2); 30 | fill(127, 127); 31 | circle(this.position.x, this.position.y, this.mass * 16); 32 | } 33 | 34 | void checkEdges() { 35 | if (this.position.x > width) { 36 | this.position.x = width; 37 | this.velocity.x *= -1; 38 | } else if (this.position.x < 0) { 39 | this.velocity.x *= -1; 40 | this.position.x = 0; 41 | } 42 | if (this.position.y > height) { 43 | this.velocity.y *= -1; 44 | this.position.y = height; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chapter2/Example_2_3_Gravity_Scaled_By_Mass/Example_2_3_Gravity_Scaled_By_Mass.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover moverA; 6 | Mover moverB; 7 | 8 | void setup() { 9 | size(640, 360); 10 | // A large Mover on the left side of the window 11 | moverA = new Mover(200, 30, 10); 12 | // A smaller Mover on the right side of the window 13 | moverB = new Mover(440, 30, 2); 14 | println("Click mouse to apply wind force."); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | 20 | PVector gravity = new PVector(0, 0.1); 21 | 22 | PVector gravityA = PVector.mult(gravity, moverA.mass); 23 | moverA.applyForce(gravityA); 24 | 25 | PVector gravityB = PVector.mult(gravity, moverB.mass); 26 | moverB.applyForce(gravityB); 27 | 28 | if (mousePressed) { 29 | PVector wind = new PVector(0.1, 0); 30 | moverA.applyForce(wind); 31 | moverB.applyForce(wind); 32 | } 33 | 34 | moverA.update(); 35 | moverA.display(); 36 | moverA.checkEdges(); 37 | 38 | moverB.update(); 39 | moverB.display(); 40 | moverB.checkEdges(); 41 | } 42 | -------------------------------------------------------------------------------- /chapter2/Example_2_3_Gravity_Scaled_By_Mass/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass,radius; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.radius = m * 8; 12 | this.position = new PVector(x, y); 13 | this.velocity = new PVector(0, 0); 14 | this.acceleration = new PVector(0, 0); 15 | } 16 | 17 | void applyForce(PVector force) { 18 | PVector f = PVector.div(force, this.mass); 19 | this.acceleration.add(f); 20 | } 21 | 22 | void update() { 23 | this.velocity.add(this.acceleration); 24 | this.position.add(this.velocity); 25 | this.acceleration.mult(0); 26 | } 27 | 28 | void display() { 29 | stroke(0); 30 | strokeWeight(2); 31 | fill(127, 127); 32 | circle(this.position.x, this.position.y, this.radius * 2); 33 | } 34 | 35 | void checkEdges() { 36 | if (this.position.x > width - this.radius) { 37 | this.position.x = width - this.radius; 38 | this.velocity.x *= -1; 39 | } else if (this.position.x < this.radius) { 40 | this.position.x = this.radius; 41 | this.velocity.x *= -1; 42 | } 43 | if (this.position.y > height - this.radius) { 44 | this.position.y = height - this.radius; 45 | this.velocity.y *= -1; 46 | } 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /chapter2/Example_2_4_Including_Friction/Example_2_4_Including_Friction.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(width / 2, 30, 5); 10 | println("Click mouse to apply wind force."); 11 | } 12 | 13 | void draw() { 14 | background(255); 15 | 16 | PVector gravity = new PVector(0, 1); 17 | //I should scale by mass to be more accurate, but this example only has one circle 18 | mover.applyForce(gravity); 19 | 20 | if (mousePressed) { 21 | PVector wind = new PVector(0.5, 0); 22 | mover.applyForce(wind); 23 | } 24 | 25 | if (mover.contactEdge()) { 26 | float c = 0.1; 27 | PVector friction = mover.velocity.copy(); 28 | friction.mult(-1); 29 | friction.setMag(c); 30 | 31 | //Apply the friction force vector to the object. 32 | mover.applyForce(friction); 33 | } 34 | 35 | mover.bounceEdges(); 36 | mover.update(); 37 | mover.show(); 38 | } 39 | -------------------------------------------------------------------------------- /chapter2/Example_2_4_Including_Friction/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass, radius; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.radius = m * 8; 12 | this.position = new PVector(x, y); 13 | this.velocity = new PVector(0, 0); 14 | this.acceleration = new PVector(0, 0); 15 | } 16 | 17 | void applyForce(PVector force) { 18 | PVector f = PVector.div(force, this.mass); 19 | this.acceleration.add(f); 20 | } 21 | 22 | void update() { 23 | this.velocity.add(this.acceleration); 24 | this.position.add(this.velocity); 25 | this.acceleration.mult(0); 26 | } 27 | 28 | void show() { 29 | stroke(0); 30 | strokeWeight(2); 31 | fill(127, 127); 32 | circle(this.position.x, this.position.y, this.radius * 2); 33 | } 34 | 35 | boolean contactEdge() { 36 | // The mover is touching the edge when it's within one pixel 37 | return (this.position.y > height - this.radius - 1); 38 | } 39 | 40 | void bounceEdges() { 41 | // A new variable to simulate an inelastic collision 42 | // 10% of the velocity's x or y component is lost 43 | float bounce = -0.9; 44 | if (this.position.x > width - this.radius) { 45 | this.position.x = width - this.radius; 46 | this.velocity.x *= bounce; 47 | } else if (this.position.x < this.radius) { 48 | this.position.x = this.radius; 49 | this.velocity.x *= bounce; 50 | } 51 | if (this.position.y > height - this.radius) { 52 | this.position.y = height - this.radius; 53 | this.velocity.y *= bounce; 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /chapter2/Example_2_5_Fluid_Resistance/Example_2_5_Fluid_Resistance.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Forces (Gravity and Fluid Resistence) with Vectors 6 | 7 | // Demonstration of multiple force acting on bodies (Mover class) 8 | // Bodies experience gravity continuously 9 | // Bodies experience fluid resistance when in "water" 10 | 11 | // Five moving bodies 12 | Mover[] movers = new Mover[9]; 13 | 14 | // Liquid 15 | Liquid liquid; 16 | 17 | void setup() { 18 | size(640, 360); 19 | reset(); 20 | // Create liquid object 21 | liquid = new Liquid(0, height / 2, width, height / 2, 0.1); 22 | } 23 | 24 | void draw() { 25 | background(255); 26 | 27 | // Draw liquid 28 | liquid.show(); 29 | 30 | for (int i = 0; i < movers.length; i++) { 31 | // Is the Mover in the liquid? 32 | if (liquid.contains(movers[i])) { 33 | // Calculate drag force 34 | PVector dragForce = liquid.calculateDrag(movers[i]); 35 | // Apply drag force to Mover 36 | movers[i].applyForce(dragForce); 37 | } 38 | 39 | // Gravity is scaled by mass here! 40 | PVector gravity = new PVector(0, 0.1 * movers[i].mass); 41 | // Apply gravity 42 | movers[i].applyForce(gravity); 43 | 44 | // Update and display 45 | movers[i].update(); 46 | movers[i].show(); 47 | movers[i].checkEdges(); 48 | } 49 | } 50 | 51 | void mousePressed() { 52 | reset(); 53 | } 54 | 55 | // Restart all the Mover objects randomly 56 | void reset() { 57 | for (int i = 0; i < 9; i++) { 58 | movers[i] = new Mover(40 + i * 70, 0, random(0.5, 3)); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /chapter2/Example_2_5_Fluid_Resistance/Liquid.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Liquid { 6 | float x, y; 7 | float w, h; 8 | float c; 9 | 10 | Liquid(float x, float y, float w, float h, float c) { 11 | this.x = x; 12 | this.y = y; 13 | this.w = w; 14 | this.h = h; 15 | this.c = c; 16 | } 17 | 18 | // Is the Mover in the Liquid? 19 | boolean contains(Mover mover) { 20 | PVector pos = mover.position; 21 | return ( 22 | pos.x > this.x && 23 | pos.x < this.x + this.w && 24 | pos.y > this.y && 25 | pos.y < this.y + this.h 26 | ); 27 | } 28 | 29 | // Calculate drag force 30 | PVector calculateDrag(Mover mover) { 31 | // Magnitude is coefficient * speed squared 32 | float speed = mover.velocity.mag(); 33 | float dragMagnitude = this.c * speed * speed; 34 | 35 | // Direction is inverse of velocity 36 | PVector dragForce = mover.velocity.copy(); 37 | dragForce.mult(-1); 38 | 39 | // Scale according to magnitude 40 | dragForce.setMag(dragMagnitude); 41 | return dragForce; 42 | } 43 | 44 | void show() { 45 | noStroke(); 46 | fill(220); 47 | rect(this.x, this.y, this.w, this.h); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter2/Example_2_5_Fluid_Resistance/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass,radius; 7 | PVector position,velocity,acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.radius = m * 8; 12 | this.position = new PVector(x, y); 13 | this.velocity = new PVector(0, 0); 14 | this.acceleration = new PVector(0, 0); 15 | } 16 | 17 | // Newton's 2nd law: F = M * A 18 | // or A = F / M 19 | void applyForce(PVector force) { 20 | PVector f = PVector.div(force, this.mass); 21 | this.acceleration.add(f); 22 | } 23 | 24 | void update() { 25 | // Velocity changes according to acceleration 26 | this.velocity.add(this.acceleration); 27 | // position changes by velocity 28 | this.position.add(this.velocity); 29 | // We must clear acceleration each frame 30 | this.acceleration.mult(0); 31 | } 32 | 33 | void show() { 34 | stroke(0); 35 | strokeWeight(2); 36 | fill(127, 127); 37 | circle(this.position.x, this.position.y, this.radius * 2); 38 | } 39 | 40 | // Bounce off bottom of window 41 | void checkEdges() { 42 | if (this.position.y > height - this.radius) { 43 | this.velocity.y *= -0.9; // A little dampening when hitting the bottom 44 | this.position.y = height - this.radius; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chapter2/Example_2_6_Attraction/Attractor.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // An object for a draggable attractive body in our world 6 | 7 | class Attractor { 8 | PVector position, dragOffset; 9 | float mass; 10 | boolean dragging, rollover; 11 | 12 | Attractor() { 13 | this.position = new PVector(width / 2, height / 2); 14 | this.mass = 20; 15 | this.dragOffset = new PVector(0, 0); 16 | this.dragging = false; 17 | this.rollover = false; 18 | } 19 | 20 | PVector attract(Mover mover) { 21 | // Calculate direction of force 22 | PVector force = PVector.sub(this.position, mover.position); 23 | // Distance between objects 24 | float distance = force.mag(); 25 | // Limiting the distance to eliminate "extreme" results for very close or very far objects 26 | distance = constrain(distance, 5, 25); 27 | 28 | // Calculate gravitional force magnitude 29 | float strength = (G * this.mass * mover.mass) / (distance * distance); 30 | // Get force vector --> magnitude * direction 31 | force.setMag(strength); 32 | return force; 33 | } 34 | 35 | // Method to display 36 | void show() { 37 | strokeWeight(4); 38 | stroke(0); 39 | if (this.dragging) { 40 | fill(50); 41 | } else if (this.rollover) { 42 | fill(100); 43 | } else { 44 | fill(175, 200); 45 | } 46 | circle(this.position.x, this.position.y, this.mass * 2); 47 | } 48 | 49 | // The methods below are for mouse interaction 50 | void handlePress(float mx, float my) { 51 | float d = dist(mx, my, this.position.x, this.position.y); 52 | if (d < this.mass) { 53 | this.dragging = true; 54 | this.dragOffset.x = this.position.x - mx; 55 | this.dragOffset.y = this.position.y - my; 56 | } 57 | } 58 | 59 | void handleHover(float mx, float my) { 60 | float d = dist(mx, my, this.position.x, this.position.y); 61 | if (d < this.mass) { 62 | this.rollover = true; 63 | } else { 64 | this.rollover = false; 65 | } 66 | } 67 | 68 | void stopDragging() { 69 | this.dragging = false; 70 | } 71 | 72 | void handleDrag(float mx, float my) { 73 | if (this.dragging) { 74 | this.position.x = mx + this.dragOffset.x; 75 | this.position.y = my + this.dragOffset.y; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /chapter2/Example_2_6_Attraction/Example_2_6_Attraction.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // A Mover and an Attractor 6 | Mover mover; 7 | Attractor attractor; 8 | 9 | // Gravitational constant (for global scaling) 10 | float G = 1; 11 | 12 | void setup() { 13 | size(640, 360); 14 | mover = new Mover(300, 50, 2); 15 | attractor = new Attractor(); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | 21 | PVector force = attractor.attract(mover); 22 | mover.applyForce(force); 23 | mover.update(); 24 | 25 | attractor.show(); 26 | mover.show(); 27 | } 28 | 29 | void mouseMoved() { 30 | attractor.handleHover(mouseX, mouseY); 31 | } 32 | 33 | void mousePressed() { 34 | attractor.handlePress(mouseX, mouseY); 35 | } 36 | 37 | void mouseDragged() { 38 | attractor.handleHover(mouseX, mouseY); 39 | attractor.handleDrag(mouseX, mouseY); 40 | } 41 | 42 | void mouseReleased() { 43 | attractor.stopDragging(); 44 | } 45 | -------------------------------------------------------------------------------- /chapter2/Example_2_6_Attraction/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass, radius; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.radius = m * 8; 12 | this.position = new PVector(x, y); 13 | this.velocity = new PVector(0, 0); 14 | this.acceleration = new PVector(0, 0); 15 | } 16 | 17 | // Newton's 2nd law: F = M * A 18 | // or A = F / M 19 | void applyForce(PVector force) { 20 | PVector f = PVector.div(force, this.mass); 21 | this.acceleration.add(f); 22 | } 23 | 24 | void update() { 25 | // Velocity changes according to acceleration 26 | this.velocity.add(this.acceleration); 27 | // position changes by velocity 28 | this.position.add(this.velocity); 29 | // We must clear acceleration each frame 30 | this.acceleration.mult(0); 31 | } 32 | 33 | void show() { 34 | stroke(0); 35 | strokeWeight(2); 36 | fill(127, 127); 37 | circle(this.position.x, this.position.y, this.radius * 2); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /chapter2/Example_2_7_Attraction_With_Many_Movers/Attractor.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // An object for a draggable attractive body in our world 6 | 7 | class Attractor { 8 | PVector position, dragOffset; 9 | float mass, G; 10 | boolean dragging, rollover; 11 | 12 | Attractor() { 13 | this.position = new PVector(width / 2, height / 2); 14 | this.mass = 20; 15 | this.G = 1; 16 | this.dragOffset = new PVector(0, 0); 17 | this.dragging = false; 18 | this.rollover = false; 19 | } 20 | 21 | PVector attract(Mover mover) { 22 | // Calculate direction of force 23 | PVector force = PVector.sub(this.position, mover.position); 24 | // Distance between objects 25 | float distance = force.mag(); 26 | // Limiting the distance to eliminate "extreme" results for very close or very far objects 27 | distance = constrain(distance, 5, 25); 28 | 29 | // Calculate gravitional force magnitude 30 | float strength = (this.G * this.mass * mover.mass) / (distance * distance); 31 | // Get force vector --> magnitude * direction 32 | force.setMag(strength); 33 | return force; 34 | } 35 | 36 | // Method to display 37 | void show() { 38 | strokeWeight(4); 39 | stroke(0); 40 | if (this.dragging) { 41 | fill(50); 42 | } else if (this.rollover) { 43 | fill(100); 44 | } else { 45 | fill(175, 200); 46 | } 47 | circle(this.position.x, this.position.y, this.mass * 2); 48 | } 49 | 50 | // The methods below are for mouse interaction 51 | void handlePress(float mx, float my) { 52 | float d = dist(mx, my, this.position.x, this.position.y); 53 | if (d < this.mass) { 54 | this.dragging = true; 55 | this.dragOffset.x = this.position.x - mx; 56 | this.dragOffset.y = this.position.y - my; 57 | } 58 | } 59 | 60 | void handleHover(float mx, float my) { 61 | float d = dist(mx, my, this.position.x, this.position.y); 62 | if (d < this.mass) { 63 | this.rollover = true; 64 | } else { 65 | this.rollover = false; 66 | } 67 | } 68 | 69 | void stopDragging() { 70 | this.dragging = false; 71 | } 72 | 73 | void handleDrag(float mx, float my) { 74 | if (this.dragging) { 75 | this.position.x = mx + this.dragOffset.x; 76 | this.position.y = my + this.dragOffset.y; 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /chapter2/Example_2_7_Attraction_With_Many_Movers/Example_2_7_Attraction_With_Many_Movers.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | Mover[] movers = new Mover[10]; 5 | 6 | Attractor attractor; 7 | 8 | void setup() { 9 | size(640, 360); 10 | for (int i = 0; i < 10; i++) { 11 | movers[i] = new Mover(random(width), random(height), random(0.5, 3)); 12 | } 13 | attractor = new Attractor(); 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | 19 | attractor.show(); 20 | 21 | for (int i = 0; i < movers.length; i++) { 22 | PVector force = attractor.attract(movers[i]); 23 | movers[i].applyForce(force); 24 | 25 | movers[i].update(); 26 | movers[i].show(); 27 | } 28 | } 29 | 30 | void mouseMoved() { 31 | attractor.handleHover(mouseX, mouseY); 32 | } 33 | 34 | void mousePressed() { 35 | attractor.handlePress(mouseX, mouseY); 36 | } 37 | 38 | void mouseDragged() { 39 | attractor.handleHover(mouseX, mouseY); 40 | attractor.handleDrag(mouseX, mouseY); 41 | } 42 | 43 | void mouseReleased() { 44 | attractor.stopDragging(); 45 | } 46 | -------------------------------------------------------------------------------- /chapter2/Example_2_7_Attraction_With_Many_Movers/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass, radius; 7 | PVector position, velocity, acceleration; 8 | 9 | Mover(float x, float y, float m) { 10 | this.mass = m; 11 | this.radius = m * 8; 12 | this.position = new PVector(x, y); 13 | this.velocity = new PVector(1, 0); 14 | this.acceleration = new PVector(0, 0); 15 | } 16 | // Newton's 2nd law: F = M * A 17 | // or A = F / M 18 | void applyForce(PVector force) { 19 | PVector f = PVector.div(force, this.mass); 20 | this.acceleration.add(f); 21 | } 22 | 23 | void update() { 24 | // Velocity changes according to acceleration 25 | this.velocity.add(this.acceleration); 26 | // position changes by velocity 27 | this.position.add(this.velocity); 28 | // We must clear acceleration each frame 29 | this.acceleration.mult(0); 30 | } 31 | 32 | void show() { 33 | stroke(0); 34 | strokeWeight(2); 35 | fill(127, 127); 36 | circle(this.position.x, this.position.y, this.radius * 2); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /chapter2/Example_2_8_Two_Body_Attraction/Body.pde: -------------------------------------------------------------------------------- 1 | // Gravitational Attraction 2 | // The Nature of Code 3 | // The Coding Train / Daniel Shiffman 4 | // https://youtu.be/EpgB3cNhKPM 5 | // https://thecodingtrain.com/learning/nature-of-code/2.5-gravitational-attraction.html 6 | // https://editor.p5js.org/codingtrain/sketches/MkLraatd 7 | 8 | class Body { 9 | PVector position, velocity, acceleration; 10 | float mass, r; 11 | 12 | Body(float x, float y) { 13 | this.position = new PVector(x, y); 14 | this.velocity = new PVector(0, 0); 15 | this.acceleration = new PVector(0, 0); 16 | this.mass = 8; 17 | this.r = sqrt(this.mass) * 2; 18 | } 19 | 20 | void attract(Body body) { 21 | PVector force = PVector.sub(this.position, body.position); 22 | float d = constrain(force.mag(), 5, 25); 23 | float G = 1; 24 | float strength = (G * (this.mass * body.mass)) / (d * d); 25 | force.setMag(strength); 26 | body.applyForce(force); 27 | } 28 | 29 | void applyForce(PVector force) { 30 | PVector f = PVector.div(force, this.mass); 31 | this.acceleration.add(f); 32 | } 33 | 34 | 35 | 36 | void update() { 37 | this.velocity.add(this.acceleration); 38 | this.position.add(this.velocity); 39 | this.acceleration.set(0, 0); 40 | } 41 | 42 | void show() { 43 | stroke(0); 44 | strokeWeight(2); 45 | fill(127, 100); 46 | circle(this.position.x, this.position.y, this.r * 4); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /chapter2/Example_2_8_Two_Body_Attraction/Example_2_8_Two_Body_Attraction.pde: -------------------------------------------------------------------------------- 1 | // Mutual Attract// The Nature of Code 2 | 3 | Body bodyA; 4 | Body bodyB; 5 | 6 | float G = 1; 7 | 8 | void setup() { 9 | size(640, 360); 10 | bodyA = new Body(320, 60); 11 | bodyB = new Body(320, 300); 12 | bodyA.velocity = new PVector(1, 0); 13 | bodyB.velocity = new PVector(-1, 0); 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | 19 | bodyA.attract(bodyB); 20 | bodyB.attract(bodyA); 21 | 22 | bodyA.update(); 23 | bodyA.show(); 24 | bodyB.update(); 25 | bodyB.show(); 26 | } 27 | -------------------------------------------------------------------------------- /chapter2/Example_2_9_N_Bodies/Body.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Body { 6 | float mass; 7 | PVector position, velocity, acceleration; 8 | 9 | Body(float x, float y, float m) { 10 | this.mass = m; 11 | this.position = new PVector(x, y); 12 | this.velocity = new PVector(0, 0); 13 | this.acceleration = new PVector(0, 0); 14 | } 15 | 16 | void applyForce(PVector force) { 17 | PVector f = PVector.div(force, this.mass); 18 | this.acceleration.add(f); 19 | } 20 | 21 | void update() { 22 | this.velocity.add(this.acceleration); 23 | this.position.add(this.velocity); 24 | this.acceleration.mult(0); 25 | } 26 | 27 | void show() { 28 | stroke(0); 29 | strokeWeight(2); 30 | fill(127, 127); 31 | circle(this.position.x, this.position.y, this.mass * 16); 32 | } 33 | 34 | PVector attract(Body other) { 35 | // Calculate direction of force 36 | PVector force = PVector.sub(this.position, other.position); 37 | // Distance between objects 38 | float distance = force.mag(); 39 | // Limiting the distance to eliminate "extreme" results for very close or very far objects 40 | distance = constrain(distance, 5, 25); 41 | 42 | // Calculate gravitional force magnitude 43 | float strength = (G * this.mass * other.mass) / (distance * distance); 44 | // Get force vector --> magnitude * direction 45 | force.setMag(strength); 46 | return force; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /chapter2/Example_2_9_N_Bodies/Example_2_9_N_Bodies.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Body[] bodies = new Body[10]; 6 | 7 | float G = 1; 8 | 9 | void setup() { 10 | size(640, 360); 11 | for (int i = 0; i < 10; i++) { 12 | bodies[i] = new Body(random(width), random(height), random(0.1, 2)); 13 | } 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | 19 | for (int i = 0; i < bodies.length; i++) { 20 | for (int j = 0; j < bodies.length; j++) { 21 | if (i != j) { 22 | PVector force = bodies[j].attract(bodies[i]); 23 | bodies[i].applyForce(force); 24 | } 25 | } 26 | 27 | bodies[i].update(); 28 | bodies[i].show(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /chapter3/Example_3_10_A_Spring_Connection/Bob.pde: -------------------------------------------------------------------------------- 1 | // Bob object, just like our regular Mover (location, velocity, acceleration, mass) 2 | 3 | class Bob { 4 | PVector position, velocity, acceleration; 5 | float mass, damping; 6 | PVector dragOffset; 7 | boolean dragging; 8 | 9 | Bob(float x, float y) { 10 | this.position = new PVector(x, y); 11 | this.velocity = new PVector(); 12 | this.acceleration = new PVector(); 13 | this.mass = 24; 14 | // Arbitrary damping to simulate friction / drag 15 | this.damping = 0.98; 16 | // For user interaction 17 | this.dragOffset = new PVector(); 18 | this.dragging = false; 19 | } 20 | 21 | // Standard Euler integration 22 | void update() { 23 | this.velocity.add(this.acceleration); 24 | this.velocity.mult(this.damping); 25 | this.position.add(this.velocity); 26 | this.acceleration.mult(0); 27 | } 28 | 29 | // Newton's law: F = M * A 30 | void applyForce(PVector force) { 31 | PVector f = force.copy(); 32 | f.div(this.mass); 33 | this.acceleration.add(f); 34 | } 35 | 36 | // Draw the bob 37 | void show() { 38 | stroke(0); 39 | strokeWeight(2); 40 | fill(127); 41 | if (this.dragging) { 42 | fill(200); 43 | } 44 | circle(this.position.x, this.position.y, this.mass * 2); 45 | } 46 | 47 | void handleClick(float mx, float my) { 48 | float d = dist(mx, my, this.position.x, this.position.y); 49 | if (d < this.mass) { 50 | this.dragging = true; 51 | this.dragOffset.x = this.position.x - mx; 52 | this.dragOffset.y = this.position.y - my; 53 | } 54 | } 55 | 56 | void stopDragging() { 57 | this.dragging = false; 58 | } 59 | 60 | void handleDrag(float mx, float my) { 61 | if (this.dragging) { 62 | this.position.x = mx + this.dragOffset.x; 63 | this.position.y = my + this.dragOffset.y; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /chapter3/Example_3_10_A_Spring_Connection/Example_3_10_A_Spring_Connection.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Mover object 6 | Bob bob; 7 | 8 | // Spring object 9 | Spring spring; 10 | 11 | void setup() { 12 | size(640, 360); 13 | // Create objects at starting position 14 | // Note third argument in Spring constructor is "rest length" 15 | spring = new Spring(width / 2, 30, 100); 16 | bob = new Bob(width / 2, 100); 17 | } 18 | 19 | void draw() { 20 | background(255); 21 | 22 | // Apply a gravity force to the bob 23 | PVector gravity = new PVector(0, 2); 24 | bob.applyForce(gravity); 25 | 26 | 27 | // Update bob 28 | bob.update(); 29 | bob.handleDrag(mouseX, mouseY); 30 | 31 | // Connect the bob to the spring (this calculates the force) 32 | spring.connect(bob); 33 | 34 | // Constrain spring distance between min and max 35 | spring.constrainLength(bob, 30, 200); 36 | 37 | // Draw everything 38 | spring.showLine(bob); // Draw a line between spring and bob 39 | bob.show(); 40 | spring.show(); 41 | } 42 | 43 | void mousePressed() { 44 | bob.handleClick(mouseX, mouseY); 45 | } 46 | 47 | void mouseReleased() { 48 | bob.stopDragging(); 49 | } 50 | -------------------------------------------------------------------------------- /chapter3/Example_3_10_A_Spring_Connection/Spring.pde: -------------------------------------------------------------------------------- 1 | // Nature of Code 2 | // Daniel Shiffman 3 | // Chapter 3: Oscillation 4 | 5 | // Object to describe an anchor point that can connect to "Bob" objects via a spring 6 | // Thank you: http://www.myphysicslab.com/spring2d.html 7 | 8 | class Spring { 9 | PVector anchor; 10 | float restLength, k; 11 | 12 | Spring(float x, float y, float len) { 13 | this.anchor = new PVector(x, y); 14 | this.restLength = len; 15 | this.k = 0.2; 16 | } 17 | // Calculate and apply spring force 18 | void connect(Bob bob) { 19 | // Vector pointing from anchor to bob location 20 | PVector force = PVector.sub(bob.position, this.anchor); 21 | // What is distance 22 | float currentLength = force.mag(); 23 | // Stretch is difference between current distance and rest length 24 | float stretch = currentLength - this.restLength; 25 | 26 | // Direction and magnitude together! 27 | force.setMag(-1 * this.k * stretch); 28 | 29 | // Call applyForce() right here! 30 | bob.applyForce(force); 31 | } 32 | 33 | void constrainLength(Bob bob, float minlen, float maxlen) { 34 | // Vector pointing from Bob to Anchor 35 | PVector direction = PVector.sub(bob.position, this.anchor); 36 | float len = direction.mag(); 37 | 38 | // Is it too short? 39 | if (len < minlen) { 40 | direction.setMag(minlen); 41 | // Keep position within constraint. 42 | bob.position = PVector.add(this.anchor, direction); 43 | bob.velocity.mult(0); 44 | // Is it too long? 45 | } else if (len > maxlen) { 46 | direction.setMag(maxlen); 47 | // Keep position within constraint. 48 | bob.position = PVector.add(this.anchor, direction); 49 | bob.velocity.mult(0); 50 | } 51 | } 52 | 53 | // Draw the anchor. 54 | void show() { 55 | fill(127); 56 | circle(this.anchor.x, this.anchor.y, 10); 57 | } 58 | 59 | // Draw the spring connection between Bob position and anchor. 60 | void showLine(Bob bob) { 61 | stroke(0); 62 | line(bob.position.x, bob.position.y, this.anchor.x, this.anchor.y); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /chapter3/Example_3_11_Swinging_Pendulum/Example_3_11_Swinging_Pendulum.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Pendulum 6 | 7 | // A simple pendulum simulation 8 | // Given a pendulum with an angle theta (0 being the pendulum at rest) and a radius r 9 | // we can use sine to calculate the angular component of the gravitational force. 10 | 11 | // Gravity Force = Mass * Gravitational Constant; 12 | // Pendulum Force = Gravity Force * sine(theta) 13 | // Angular Acceleration = Pendulum Force / Mass = gravitational acceleration * sine(theta); 14 | 15 | // Note this is an ideal world scenario with no tension in the 16 | // pendulum arm, a more realistic formula might be: 17 | // Angular Acceleration = (g / R) * sine(theta) 18 | 19 | // For a more substantial explanation, visit: 20 | // http://www.myphysicslab.com/pendulum1.html 21 | Pendulum pendulum; 22 | 23 | void setup() { 24 | size(640, 360); 25 | // Make a new Pendulum with an origin position and armlength 26 | pendulum = new Pendulum(width / 2, 30, 175); 27 | } 28 | 29 | void draw() { 30 | background(255); 31 | pendulum.update(); 32 | pendulum.show(); 33 | 34 | pendulum.drag(); // for user interaction 35 | } 36 | 37 | void mousePressed() { 38 | pendulum.clicked(mouseX, mouseY); 39 | } 40 | 41 | void mouseReleased() { 42 | pendulum.stopDragging(); 43 | } 44 | -------------------------------------------------------------------------------- /chapter3/Example_3_11_Swinging_Pendulum/Pendulum.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Pendulum 6 | 7 | // A Simple Pendulum Class 8 | 9 | // This constructor could be improved to allow a greater variety of pendulums 10 | class Pendulum { 11 | PVector pivot, bob; 12 | float r; 13 | float angle, angleVelocity, angleAcceleration; 14 | float damping; 15 | float ballr; 16 | boolean dragging; 17 | 18 | Pendulum(float x, float y, float r) { 19 | // Fill all variables 20 | this.pivot = new PVector(x, y); 21 | this.bob = new PVector(); 22 | this.r = r; 23 | this.angle = PI / 4; 24 | this.angleVelocity = 0.0; 25 | this.angleAcceleration = 0.0; 26 | this.damping = 0.995; // Arbitrary damping 27 | this.ballr = 24.0; // Arbitrary ball radius 28 | this.dragging = false; 29 | } 30 | 31 | // Function to update position 32 | void update() { 33 | // As long as we aren't dragging the pendulum, let it swing! 34 | if (!this.dragging) { 35 | float gravity = 0.4; // Arbitrary constant 36 | this.angleAcceleration = ((-1 * gravity) / this.r) * sin(this.angle); // Calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html) 37 | 38 | this.angleVelocity += this.angleAcceleration; // Increment velocity 39 | this.angle += this.angleVelocity; // Increment angle 40 | 41 | this.angleVelocity *= this.damping; // Apply some damping 42 | } 43 | } 44 | 45 | void show() { 46 | this.bob.set(this.r * sin(this.angle), this.r * cos(this.angle), 0); // Polar to cartesian conversion 47 | this.bob.add(this.pivot); // Make sure the position is relative to the pendulum's origin 48 | 49 | stroke(0); 50 | strokeWeight(2); 51 | // Draw the arm 52 | line(this.pivot.x, this.pivot.y, this.bob.x, this.bob.y); 53 | fill(127); 54 | // Draw the ball 55 | circle(this.bob.x, this.bob.y, this.ballr * 2); 56 | } 57 | 58 | // The methods below are for mouse interaction 59 | 60 | // This checks to see if we clicked on the pendulum ball 61 | void clicked(float mx, float my) { 62 | float d = dist(mx, my, this.bob.x, this.bob.y); 63 | if (d < this.ballr) { 64 | this.dragging = true; 65 | } 66 | } 67 | 68 | // This tells us we are not longer clicking on the ball 69 | void stopDragging() { 70 | this.angleVelocity = 0; // No velocity once you let go 71 | this.dragging = false; 72 | } 73 | 74 | void drag() { 75 | // If we are draging the ball, we calculate the angle between the 76 | // pendulum origin and mouse position 77 | // we assign that angle to the pendulum 78 | if (this.dragging) { 79 | PVector diff = PVector.sub(this.pivot, new PVector(mouseX, mouseY)); // Difference between 2 points 80 | this.angle = atan2(-1 * diff.y, diff.x) - radians(90); // Angle relative to vertical axis 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /chapter3/Example_3_1_Angular_Motion_Using_Rotate/Example_3_1_Angular_Motion_Using_Rotate.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Position 6 | float angle = 0; 7 | // Velocity 8 | float angleVelocity = 0; 9 | //{!1} Acceleration 10 | float angleAcceleration = 0.0001; 11 | 12 | void setup() { 13 | size(640, 360); 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | 19 | translate(width / 2, height / 2); 20 | rotate(angle); 21 | 22 | stroke(0); 23 | strokeWeight(2); 24 | fill(127); 25 | 26 | line(-60, 0, 60, 0); 27 | circle(60, 0, 16); 28 | circle(-60, 0, 16); 29 | 30 | // Angular equivalent of velocity.add(acceleration); 31 | angleVelocity += angleAcceleration; 32 | // Angular equivalent of position.add(velocity); 33 | angle += angleVelocity; 34 | } 35 | -------------------------------------------------------------------------------- /chapter3/Example_3_2_Forces_With_Arbitrary_Angular_Motion/Attractor.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Attractor { 6 | PVector position; 7 | float mass, G; 8 | 9 | Attractor() { 10 | this.position = new PVector(width / 2, height / 2); 11 | this.mass = 20; 12 | this.G = 1; 13 | } 14 | 15 | PVector attract(Mover mover) { 16 | // Calculate direction of force 17 | PVector force = PVector.sub(this.position, mover.position); 18 | // Distance between objects 19 | float distance = force.mag(); 20 | // Limiting the distance to eliminate "extreme" results for very close or very far objects 21 | distance = constrain(distance, 5, 25); 22 | 23 | // Calculate gravitional force magnitude 24 | float strength = (this.G * this.mass * mover.mass) / (distance * distance); 25 | // Get force vector --> magnitude * direction 26 | force.setMag(strength); 27 | return force; 28 | } 29 | 30 | // Method to display 31 | void display() { 32 | ellipseMode(CENTER); 33 | stroke(0); 34 | fill(175, 200); 35 | circle(this.position.x, this.position.y, this.mass * 2); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter3/Example_3_2_Forces_With_Arbitrary_Angular_Motion/Example_3_2_Forces_With_Arbitrary_Angular_Motion.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover[] movers = new Mover[20]; 6 | Attractor attractor; 7 | 8 | void setup() { 9 | size(640, 360); 10 | 11 | for (int i = 0; i < 20; i++) { 12 | movers[i] = new Mover(random(width), random(height), random(0.1, 2)); 13 | } 14 | attractor = new Attractor(); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | 20 | attractor.display(); 21 | 22 | for (int i = 0; i < movers.length; i++) { 23 | PVector force = attractor.attract(movers[i]); 24 | movers[i].applyForce(force); 25 | 26 | movers[i].update(); 27 | movers[i].show(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter3/Example_3_2_Forces_With_Arbitrary_Angular_Motion/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | float mass, radius; 7 | PVector position, velocity, acceleration; 8 | float angle, angleVelocity, angleAcceleration; 9 | 10 | Mover(float x, float y, float mass) { 11 | this.mass = mass; 12 | this.radius = this.mass * 8; 13 | this.position = new PVector(x, y); 14 | this.angle = 0; 15 | this.angleVelocity = 0; 16 | this.angleAcceleration = 0; 17 | this.velocity = new PVector(random(-1, 1), random(-1, 1)); 18 | this.acceleration = new PVector(0, 0); 19 | } 20 | 21 | void applyForce(PVector force) { 22 | PVector f = PVector.div(force, this.mass); 23 | this.acceleration.add(f); 24 | } 25 | 26 | void update() { 27 | this.velocity.add(this.acceleration); 28 | this.position.add(this.velocity); 29 | this.angleAcceleration = this.acceleration.x / 10.0; 30 | this.angleVelocity += this.angleAcceleration; 31 | this.angleVelocity = constrain(this.angleVelocity, -0.1, 0.1); 32 | this.angle += this.angleVelocity; 33 | this.acceleration.mult(0); 34 | } 35 | 36 | void show() { 37 | strokeWeight(2); 38 | stroke(0); 39 | fill(127, 127); 40 | rectMode(CENTER); 41 | push(); 42 | translate(this.position.x, this.position.y); 43 | rotate(this.angle); 44 | circle(0, 0, this.radius * 2); 45 | line(0, 0, this.radius, 0); 46 | pop(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /chapter3/Example_3_3_Pointing_In_The_Direction_Of_Motion/Example_3_3_Pointing_In_The_Direction_Of_Motion.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Mover mover; 6 | 7 | void setup() { 8 | size(640, 360); 9 | mover = new Mover(); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | mover.update(); 15 | mover.checkEdges(); 16 | mover.display(); 17 | } 18 | -------------------------------------------------------------------------------- /chapter3/Example_3_3_Pointing_In_The_Direction_Of_Motion/Mover.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Mover { 6 | PVector position, velocity, acceleration; 7 | float topspeed; 8 | float xoff, yoff; 9 | float r; 10 | 11 | Mover() { 12 | this.position = new PVector(width / 2, height / 2); 13 | this.velocity = new PVector(0, 0); 14 | this.acceleration = new PVector(0, 0); 15 | this.topspeed = 4; 16 | this.xoff = 1000; 17 | this.yoff = 0; 18 | this.r = 16; 19 | } 20 | 21 | void update() { 22 | PVector mouse = new PVector(mouseX, mouseY); 23 | PVector dir = PVector.sub(mouse, this.position); 24 | dir.normalize(); 25 | dir.mult(0.5); 26 | this.acceleration = dir; 27 | 28 | this.velocity.add(this.acceleration); 29 | this.velocity.limit(this.topspeed); 30 | this.position.add(this.velocity); 31 | } 32 | 33 | void display() { 34 | float angle = this.velocity.heading(); 35 | 36 | stroke(0); 37 | strokeWeight(2); 38 | fill(127); 39 | push(); 40 | rectMode(CENTER); 41 | 42 | translate(this.position.x, this.position.y); 43 | rotate(angle); 44 | rect(0, 0, 30, 10); 45 | 46 | pop(); 47 | } 48 | 49 | void checkEdges() { 50 | if (this.position.x > width) { 51 | this.position.x = 0; 52 | } else if (this.position.x < 0) { 53 | this.position.x = width; 54 | } 55 | 56 | if (this.position.y > height) { 57 | this.position.y = 0; 58 | } else if (this.position.y < 0) { 59 | this.position.y = height; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /chapter3/Example_3_4_Polar_To_Cartesian/Example_3_4_Polar_To_Cartesian.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // PolarToCartesian 6 | // Convert a polar coordinate (r,theta) to cartesian (x,y): 7 | // x = r * cos(theta) 8 | // y = r * sin(theta) 9 | 10 | float r; 11 | float theta; 12 | 13 | void setup() { 14 | size(640, 360); 15 | // Initialize all values 16 | r = height * 0.35; 17 | theta = 0; 18 | } 19 | 20 | void draw() { 21 | background(255); 22 | 23 | // Translate the origin point to the center of the screen 24 | translate(width / 2, height / 2); 25 | 26 | // Convert polar to cartesian 27 | float x = r * cos(theta); 28 | float y = r * sin(theta); 29 | 30 | // Draw the ellipse at the cartesian coordinate 31 | fill(127); 32 | stroke(0); 33 | strokeWeight(2); 34 | line(0, 0, x, y); 35 | circle(x, y, 48); 36 | 37 | // Increase the angle over time 38 | theta += 0.02; 39 | } 40 | -------------------------------------------------------------------------------- /chapter3/Example_3_5_Simple_Harmonic_Motion/Example_3_5_Simple_Harmonic_Motion.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | void setup() { 6 | size(640, 360); 7 | } 8 | 9 | void draw() { 10 | background(255); 11 | 12 | float period = 120; 13 | float amplitude = 200; 14 | 15 | // Calculating horizontal position according to formula for simple harmonic motion 16 | float x = amplitude * sin((TWO_PI * frameCount) / period); 17 | 18 | stroke(0); 19 | strokeWeight(2); 20 | fill(127); 21 | translate(width / 2, height / 2); 22 | line(0, 0, x, 0); 23 | circle(x, 0, 48); 24 | } 25 | -------------------------------------------------------------------------------- /chapter3/Example_3_6_Simple_Harmonic_Motion_II/Example_3_6_Simple_Harmonic_Motion_II.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | float angle = 0; 6 | float angleVelocity = 0.05; 7 | 8 | void setup() { 9 | size(640, 360); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | float amplitude = 200; 16 | float x = amplitude * sin(angle); 17 | angle += angleVelocity; 18 | 19 | translate(width / 2, height / 2); 20 | 21 | stroke(0); 22 | strokeWeight(2); 23 | fill(127); 24 | line(0, 0, x, 0); 25 | circle(x, 0, 48); 26 | } 27 | -------------------------------------------------------------------------------- /chapter3/Example_3_7_Oscillator_Objects/Example_3_7_Oscillator_Objects.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // An array of objects 6 | Oscillator[] oscillators = new Oscillator[10]; 7 | 8 | void setup() { 9 | size(640, 360); 10 | // Initialize all objects 11 | for (int i = 0; i < 10; i++) { 12 | oscillators[i] = new Oscillator(); 13 | } 14 | } 15 | 16 | void draw() { 17 | background(255); 18 | // Run all objects 19 | for (int i = 0; i < oscillators.length; i++) { 20 | oscillators[i].update(); 21 | oscillators[i].show(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /chapter3/Example_3_7_Oscillator_Objects/Oscillator.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Oscillator { 6 | PVector angle, angleVelocity, amplitude; 7 | 8 | Oscillator() { 9 | this.angle = new PVector(); 10 | this.angleVelocity = new PVector(random(-0.05, 0.05), random(-0.05, 0.05)); 11 | this.amplitude = new PVector( 12 | random(20, width / 2), 13 | random(20, height / 2) 14 | ); 15 | } 16 | 17 | void update() { 18 | this.angle.add(this.angleVelocity); 19 | } 20 | 21 | void show() { 22 | float x = sin(this.angle.x) * this.amplitude.x; 23 | float y = sin(this.angle.y) * this.amplitude.y; 24 | 25 | push(); 26 | translate(width / 2, height / 2); 27 | stroke(0); 28 | strokeWeight(2); 29 | fill(127); 30 | line(0, 0, x, y); 31 | circle(x, y, 32); 32 | pop(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter3/Example_3_8_Static_Wave/Example_3_8_Static_Wave.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | float angle = 0; 6 | float angleVelocity = 0.2; 7 | float amplitude = 100; 8 | 9 | void setup() { 10 | size(640, 360); 11 | background(255); 12 | 13 | stroke(0); 14 | strokeWeight(2); 15 | fill(127, 127); 16 | 17 | for (int x = 0; x <= width; x += 24) { 18 | // 1) Calculate the y position according to amplitude and sine of the angle. 19 | float y = amplitude * sin(angle); 20 | // 2) Draw a circle at the (x,y) position. 21 | circle(x, y + height / 2, 48); 22 | // 3) Increment the angle according to angular velocity. 23 | angle += angleVelocity; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter3/Example_3_9_The_Wave/Example_3_9_The_Wave.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | float startAngle = 0; 6 | float angleVelocity = 0.2; 7 | 8 | void setup() { 9 | size(640, 360); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | 15 | float angle = startAngle; 16 | startAngle += 0.02; 17 | 18 | for (int x = 0; x <= width; x += 24) { 19 | float y = map(sin(angle), -1, 1, 0, height); 20 | stroke(0); 21 | strokeWeight(2); 22 | fill(127, 127); 23 | circle(x, y, 48); 24 | angle += angleVelocity; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter4/Example_4_1_Single_Particle/Example_4_1_Single_Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Particle particle; 6 | 7 | void setup() { 8 | size(640, 360); 9 | particle = new Particle(width / 2, 10); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | // Operating the single Particle 15 | particle.update(); 16 | particle.show(); 17 | 18 | // Applying a gravity force 19 | PVector gravity = new PVector(0, 0.1); 20 | particle.applyForce(gravity); 21 | 22 | // Checking the particle's state and making a new particle 23 | if (particle.isDead()) { 24 | particle = new Particle(width / 2, 20); 25 | println("Particle dead!"); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter4/Example_4_1_Single_Particle/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | // For demonstration purposes the Particle has a random velocity. 16 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 17 | this.acceleration = new PVector(0, 0); 18 | this.lifespan = 255.0; 19 | } 20 | 21 | void update() { 22 | this.velocity.add(this.acceleration); 23 | this.position.add(this.velocity); 24 | this.lifespan -= 2.0; 25 | this.acceleration.mult(0); 26 | } 27 | 28 | 29 | void show() { 30 | stroke(0, this.lifespan); 31 | fill(0, this.lifespan); 32 | circle(this.position.x, this.position.y, 8); 33 | } 34 | 35 | // Keeping the same physics model as with previous chapters 36 | void applyForce(PVector force) { 37 | this.acceleration.add(force); 38 | } 39 | 40 | // Is the Particle alive or dead? 41 | boolean isDead() { 42 | return (this.lifespan < 0); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /chapter4/Example_4_2_Array_Of_Particles/Example_4_2_Array_Of_Particles.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | ArrayList particles = new ArrayList(); 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | particles.add(new Particle(width / 2, 20)); 14 | 15 | // Looping through backwards to delete 16 | for (int i = particles.size() - 1; i >= 0; i--) { 17 | Particle particle = particles.get(i); 18 | particle.run(); 19 | if (particle.isDead()) { 20 | //remove the particle 21 | particles.remove(i); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter4/Example_4_2_Array_Of_Particles/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | } 19 | 20 | void run() { 21 | PVector gravity = new PVector(0, 0.05); 22 | this.applyForce(gravity); 23 | this.update(); 24 | this.show(); 25 | } 26 | 27 | void applyForce(PVector force) { 28 | this.acceleration.add(force); 29 | } 30 | 31 | // Method to update position 32 | void update() { 33 | this.velocity.add(this.acceleration); 34 | this.position.add(this.velocity); 35 | this.lifespan -= 2; 36 | this.acceleration.mult(0); 37 | } 38 | 39 | // Method to display 40 | void show() { 41 | stroke(0, this.lifespan); 42 | strokeWeight(2); 43 | fill(127, this.lifespan); 44 | circle(this.position.x, this.position.y, 8); 45 | } 46 | 47 | // Is the particle still useful? 48 | boolean isDead() { 49 | return (this.lifespan < 0.0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chapter4/Example_4_3_A_Particle_Emitter/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Emitter { 6 | PVector origin; 7 | ArrayList particles; 8 | 9 | Emitter(float x, float y) { 10 | this.origin = new PVector(x, y); 11 | this.particles = new ArrayList(); 12 | } 13 | 14 | void addParticle() { 15 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 16 | } 17 | 18 | void run() { 19 | // Looping through backwards to delete 20 | for (int i = this.particles.size() - 1; i >= 0; i--) { 21 | this.particles.get(i).run(); 22 | if (this.particles.get(i).isDead()) { 23 | // Remove the particle 24 | this.particles.remove(i); 25 | } 26 | } 27 | 28 | // Run every particle 29 | // ES6 for..of loop 30 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of 31 | // https://www.youtube.com/watch?v=Y8sMnRQYr3c 32 | // for (let particle of this.particles) { 33 | // particle.run(); 34 | // } 35 | 36 | // Filter removes any elements of the array that do not pass the test 37 | // I am also using ES6 arrow snytax 38 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions 39 | // https://www.youtube.com/watch?v=mrYMzpbFz18 40 | // this.particles = this.particles.filter(particle => !particle.isDead()); 41 | 42 | // Without ES6 arrow code would look like: 43 | // this.particles = this.particles.filter(function(particle) { 44 | // return !particle.isDead(); 45 | // }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chapter4/Example_4_3_A_Particle_Emitter/Example_4_3_A_Particle_Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Emitter emitter; 6 | 7 | void setup() { 8 | size(640,360); 9 | emitter = new Emitter(width / 2, 50); 10 | } 11 | 12 | void draw() { 13 | background(255); 14 | emitter.addParticle(); 15 | emitter.run(); 16 | } 17 | -------------------------------------------------------------------------------- /chapter4/Example_4_3_A_Particle_Emitter/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | } 19 | 20 | void run() { 21 | PVector gravity = new PVector(0, 0.05); 22 | this.applyForce(gravity); 23 | this.update(); 24 | this.show(); 25 | } 26 | 27 | void applyForce(PVector force) { 28 | this.acceleration.add(force); 29 | } 30 | 31 | // Method to update position 32 | void update() { 33 | this.velocity.add(this.acceleration); 34 | this.position.add(this.velocity); 35 | this.lifespan -= 2; 36 | this.acceleration.mult(0); 37 | } 38 | 39 | // Method to display 40 | void show() { 41 | stroke(0, this.lifespan); 42 | strokeWeight(2); 43 | fill(127, this.lifespan); 44 | circle(this.position.x, this.position.y, 8); 45 | } 46 | 47 | // Is the particle still useful? 48 | boolean isDead() { 49 | return (this.lifespan < 0.0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chapter4/Example_4_4_A_System_Of_Systems/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Emitter { 6 | PVector origin; 7 | ArrayList particles; 8 | 9 | Emitter(float x, float y) { 10 | this.origin = new PVector(x, y); 11 | this.particles = new ArrayList(); 12 | } 13 | 14 | void addParticle() { 15 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 16 | } 17 | 18 | void run() { 19 | // Looping through backwards to delete 20 | for (int i = this.particles.size() - 1; i >= 0; i--) { 21 | this.particles.get(i).run(); 22 | if (this.particles.get(i).isDead()) { 23 | // Remove the particle 24 | this.particles.remove(i); 25 | } 26 | } 27 | 28 | // Run every particle 29 | // ES6 for..of loop 30 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of 31 | // https://www.youtube.com/watch?v=Y8sMnRQYr3c 32 | // for (let particle of this.particles) { 33 | // particle.run(); 34 | // } 35 | 36 | // Filter removes any elements of the array that do not pass the test 37 | // I am also using ES6 arrow snytax 38 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions 39 | // https://www.youtube.com/watch?v=mrYMzpbFz18 40 | // this.particles = this.particles.filter(particle => !particle.isDead()); 41 | 42 | // Without ES6 arrow code would look like: 43 | // this.particles = this.particles.filter(function(particle) { 44 | // return !particle.isDead(); 45 | // }); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /chapter4/Example_4_4_A_System_Of_Systems/Example_4_4_A_System_Of_Systems.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Particles are generated each cycle through draw(), 6 | // fall with gravity and fade out over time 7 | // A ParticleSystem object manages a variable size 8 | // list of particles. 9 | 10 | // an array of ParticleSystems 11 | ArrayList emitters = new ArrayList(); 12 | 13 | void setup() { 14 | size(640, 360); 15 | println("click to add particle systems"); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | for (Emitter emitter : emitters) { 21 | emitter.run(); 22 | emitter.addParticle(); 23 | } 24 | } 25 | 26 | void mousePressed() { 27 | emitters.add(new Emitter(mouseX, mouseY)); 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/Example_4_4_A_System_Of_Systems/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | } 19 | 20 | void run() { 21 | PVector gravity = new PVector(0, 0.05); 22 | this.applyForce(gravity); 23 | this.update(); 24 | this.show(); 25 | } 26 | 27 | void applyForce(PVector force) { 28 | this.acceleration.add(force); 29 | } 30 | 31 | // Method to update position 32 | void update() { 33 | this.velocity.add(this.acceleration); 34 | this.position.add(this.velocity); 35 | this.lifespan -= 2; 36 | this.acceleration.mult(0); 37 | } 38 | 39 | // Method to display 40 | void show() { 41 | stroke(0, this.lifespan); 42 | strokeWeight(2); 43 | fill(127, this.lifespan); 44 | circle(this.position.x, this.position.y, 8); 45 | } 46 | 47 | // Is the particle still useful? 48 | boolean isDead() { 49 | return (this.lifespan < 0.0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chapter4/Example_4_5_Particle_System_With_Inheritance_And_Polymorphism/Confetti.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Child class constructor 6 | class Confetti extends Particle { 7 | 8 | Confetti (float x, float y) { 9 | super(x, y); 10 | } 11 | // Override the show method 12 | void show() { 13 | float angle = map(this.position.x, 0, width, 0, TWO_PI * 2); 14 | 15 | rectMode(CENTER); 16 | fill(127, this.lifespan); 17 | stroke(0, this.lifespan); 18 | strokeWeight(2); 19 | push(); 20 | translate(this.position.x, this.position.y); 21 | rotate(angle); 22 | square(0, 0, 12); 23 | pop(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter4/Example_4_5_Particle_System_With_Inheritance_And_Polymorphism/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Emitter { 6 | PVector origin; 7 | ArrayList particles; 8 | 9 | Emitter(float x, float y) { 10 | this.origin = new PVector(x, y); 11 | this.particles = new ArrayList(); 12 | } 13 | 14 | void addParticle() { 15 | float r = random(1); 16 | if (r < 0.5) { 17 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 18 | } else { 19 | this.particles.add(new Confetti(this.origin.x, this.origin.y)); 20 | } 21 | } 22 | 23 | void run() { 24 | for (int i = this.particles.size() - 1; i >= 0; i--) { 25 | Particle p = this.particles.get(i); 26 | p.run(); 27 | if (p.isDead()) { 28 | this.particles.remove(i); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /chapter4/Example_4_5_Particle_System_With_Inheritance_And_Polymorphism/Example_4_5_Particle_System_With_Inheritance_And_Polymorphism.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Particles are generated each cycle through draw(), 6 | // fall with gravity and fade out over time 7 | // A ParticleSystem object manages a variable size 8 | // list of particles. 9 | 10 | 11 | Emitter emitter; 12 | 13 | void setup() { 14 | size(640, 360); 15 | emitter = new Emitter(width / 2, 50); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | emitter.addParticle(); 21 | emitter.run(); 22 | } 23 | -------------------------------------------------------------------------------- /chapter4/Example_4_5_Particle_System_With_Inheritance_And_Polymorphism/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | } 19 | 20 | void run() { 21 | PVector gravity = new PVector(0, 0.05); 22 | this.applyForce(gravity); 23 | this.update(); 24 | this.show(); 25 | } 26 | 27 | void applyForce(PVector force) { 28 | this.acceleration.add(force); 29 | } 30 | 31 | // Method to update position 32 | void update() { 33 | this.velocity.add(this.acceleration); 34 | this.position.add(this.velocity); 35 | this.lifespan -= 2; 36 | this.acceleration.mult(0); 37 | } 38 | 39 | // Method to display 40 | void show() { 41 | stroke(0, this.lifespan); 42 | strokeWeight(2); 43 | fill(127, this.lifespan); 44 | circle(this.position.x, this.position.y, 8); 45 | } 46 | 47 | // Is the particle still useful? 48 | boolean isDead() { 49 | return (this.lifespan < 0.0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /chapter4/Example_4_6_Particle_System_With_Forces/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Emitter { 6 | PVector origin; 7 | ArrayList particles; 8 | 9 | Emitter(float x, float y) { 10 | this.origin = new PVector(x, y); 11 | this.particles = new ArrayList(); 12 | } 13 | 14 | void addParticle() { 15 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 16 | } 17 | 18 | void applyForce(PVector force) { 19 | // Using a for of loop to apply the force to all particles 20 | for (Particle particle : this.particles) { 21 | particle.applyForce(force); 22 | } 23 | } 24 | 25 | void run() { 26 | // Can't use the enhanced loop because checking for particles to delete. 27 | for (int i = this.particles.size() - 1; i >= 0; i--) { 28 | Particle particle = this.particles.get(i); 29 | particle.run(); 30 | if (particle.isDead()) { 31 | this.particles.remove(i); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /chapter4/Example_4_6_Particle_System_With_Forces/Example_4_6_Particle_System_With_Forces.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | Emitter emitter; 6 | 7 | void setup() { 8 | size(640, 360); 9 | background(255); 10 | emitter = new Emitter(width / 2, 50); 11 | } 12 | 13 | void draw() { 14 | // Semi-transparent background 15 | noStroke(); 16 | fill(255,30); 17 | rect(0,0,width,height); 18 | 19 | // Apply gravity force to all Particles 20 | PVector gravity = new PVector(0, 0.1); 21 | emitter.applyForce(gravity); 22 | 23 | emitter.addParticle(); 24 | emitter.run(); 25 | } 26 | -------------------------------------------------------------------------------- /chapter4/Example_4_6_Particle_System_With_Forces/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan, mass; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | this.mass = 1; // Let's do something better here! 19 | } 20 | 21 | void run() { 22 | this.update(); 23 | this.show(); 24 | } 25 | 26 | void applyForce(PVector force) { 27 | PVector f = force.copy(); 28 | f.div(this.mass); 29 | this.acceleration.add(f); 30 | } 31 | 32 | // Method to update position 33 | void update() { 34 | this.velocity.add(this.acceleration); 35 | this.position.add(this.velocity); 36 | this.acceleration.mult(0); 37 | this.lifespan -= 2.0; 38 | } 39 | 40 | // Method to display 41 | void show() { 42 | stroke(0, this.lifespan); 43 | strokeWeight(2); 44 | fill(127, this.lifespan); 45 | circle(this.position.x, this.position.y, 8); 46 | } 47 | 48 | // Is the particle still useful? 49 | boolean isDead() { 50 | return this.lifespan < 0.0; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /chapter4/Example_4_7_Particle_System_With_Repeller/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The Emitter manages all the particles. 6 | class Emitter { 7 | PVector origin; 8 | ArrayList particles; 9 | 10 | Emitter(float x, float y) { 11 | this.origin = new PVector(x, y); 12 | this.particles = new ArrayList(); 13 | } 14 | 15 | void addParticle() { 16 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 17 | } 18 | 19 | void applyForce(PVector force) { 20 | // Applying a force as a PVector 21 | for (Particle particle : this.particles) { 22 | particle.applyForce(force); 23 | } 24 | } 25 | 26 | void applyRepeller(Repeller repeller) { 27 | // Calculating a force for each Particle based on a Repeller 28 | for (Particle particle : this.particles) { 29 | PVector force = repeller.repel(particle); 30 | particle.applyForce(force); 31 | } 32 | } 33 | 34 | void run() { 35 | for (int i = this.particles.size() - 1; i >= 0; i--) { 36 | Particle particle = this.particles.get(i); 37 | particle.run(); 38 | if (particle.isDead()) { 39 | this.particles.remove(i); 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /chapter4/Example_4_7_Particle_System_With_Repeller/Example_4_7_Particle_System_With_Repeller.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // One ParticleSystem 6 | Emitter emitter; 7 | 8 | //{!1} One repeller 9 | Repeller repeller; 10 | 11 | void setup() { 12 | size(640 , 360); 13 | emitter = new Emitter(width / 2, 60); 14 | repeller = new Repeller(width / 2, 250); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | emitter.addParticle(); 20 | // We’re applying a universal gravity. 21 | PVector gravity = new PVector(0, 0.1); 22 | emitter.applyForce(gravity); 23 | // Applying the repeller 24 | emitter.applyRepeller(repeller); 25 | emitter.run(); 26 | 27 | repeller.show(); 28 | } 29 | -------------------------------------------------------------------------------- /chapter4/Example_4_7_Particle_System_With_Repeller/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Particle System 6 | 7 | // A simple Particle class 8 | 9 | class Particle { 10 | PVector position, velocity, acceleration; 11 | float lifespan; 12 | 13 | Particle(float x, float y) { 14 | this.position = new PVector(x, y); 15 | this.velocity = new PVector(random(-1, 1), random(-2, 0)); 16 | this.acceleration = new PVector(0, 0); 17 | this.lifespan = 255.0; 18 | } 19 | 20 | void run() { 21 | this.update(); 22 | this.show(); 23 | } 24 | 25 | void applyForce(PVector f) { 26 | this.acceleration.add(f); 27 | } 28 | 29 | // Method to update position 30 | void update() { 31 | this.velocity.add(this.acceleration); 32 | this.position.add(this.velocity); 33 | this.acceleration.mult(0); 34 | this.lifespan -= 2.0; 35 | } 36 | 37 | // Method to display 38 | void show() { 39 | stroke(0, this.lifespan); 40 | strokeWeight(2); 41 | fill(127, this.lifespan); 42 | circle(this.position.x, this.position.y, 8); 43 | } 44 | 45 | // Is the particle still useful? 46 | boolean isDead() { 47 | return this.lifespan < 0.0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter4/Example_4_7_Particle_System_With_Repeller/Repeller.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Repeller { 6 | PVector position; 7 | float power; 8 | 9 | Repeller(float x, float y) { 10 | this.position = new PVector(x, y); 11 | // How strong is the repeller? 12 | this.power = 150; 13 | } 14 | 15 | void show() { 16 | stroke(0); 17 | strokeWeight(2); 18 | fill(127); 19 | circle(this.position.x, this.position.y, 32); 20 | } 21 | 22 | PVector repel(Particle particle) { 23 | // This is the same repel algorithm we used in Chapter 2: forces based on gravitational attraction. 24 | PVector force = PVector.sub(this.position, particle.position); 25 | float distance = force.mag(); 26 | distance = constrain(distance, 5, 50); 27 | float strength = (-1 * this.power) / (distance * distance); 28 | force.setMag(strength); 29 | return force; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /chapter4/Example_4_8_Image_Texture_System_Smoke/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Smoke Particle System 6 | 7 | // A class to describe a group of Particles 8 | // An ArrayList is used to manage the list of Particles 9 | 10 | class Emitter { 11 | PVector origin; 12 | ArrayList particles; 13 | 14 | Emitter(float x, float y) { 15 | this.origin = new PVector(x, y); // Initialize the arraylist 16 | this.particles = new ArrayList(); // Store the origin point 17 | } 18 | 19 | void run() { 20 | for (int i = this.particles.size() - 1; i >= 0; i--) { 21 | Particle particle = this.particles.get(i); 22 | particle.run(); 23 | if (particle.isDead()) { 24 | this.particles.remove(i); 25 | } 26 | } 27 | } 28 | 29 | // Method to add a force vector to all particles currently in the system 30 | void applyForce(PVector force) { 31 | // Enhanced loop!!! 32 | for (Particle particle : this.particles) { 33 | particle.applyForce(force); 34 | } 35 | } 36 | 37 | void addParticle() { 38 | this.particles.add(new Particle(this.origin.x, this.origin.y)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /chapter4/Example_4_8_Image_Texture_System_Smoke/Example_4_8_Image_Texture_System_Smoke.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Smoke Particle System 6 | 7 | // A basic smoke effect using a particle system 8 | // Each particle is rendered as an alpha masked image 9 | 10 | Emitter emitter; 11 | PImage img; 12 | 13 | void setup() { 14 | size(640, 360); 15 | img = loadImage("texture.png"); 16 | emitter = new Emitter(width / 2, height - 75); 17 | } 18 | 19 | void draw() { 20 | // Try additive blending! 21 | // You also need clear or else the colors will accumulate between frames 22 | // blendMode(ADD); 23 | // clear(); 24 | 25 | background(0); 26 | 27 | // Wind force direction based on mouseX. 28 | float dx = map(mouseX, 0, width, -0.2, 0.2); 29 | PVector wind = new PVector(dx, 0); 30 | emitter.applyForce(wind); 31 | emitter.run(); 32 | emitter.addParticle(); 33 | 34 | // Draw an arrow representing the wind force 35 | drawVector(wind, new PVector(width / 2, 50, 0), 500); 36 | } 37 | 38 | // Renders a vector object 'v' as an arrow and a position 'loc' 39 | void drawVector(PVector v, PVector pos, float scayl) { 40 | push(); 41 | float arrowsize = 4; 42 | // Translate to position to render vector 43 | translate(pos.x, pos.y); 44 | stroke(255); 45 | // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate 46 | rotate(v.heading()); 47 | // Calculate length of vector & scale it to be bigger or smaller if necessary 48 | float len = v.mag() * scayl; 49 | // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) 50 | line(0, 0, len, 0); 51 | line(len, 0, len - arrowsize, +arrowsize / 2); 52 | line(len, 0, len - arrowsize, -arrowsize / 2); 53 | pop(); 54 | } 55 | -------------------------------------------------------------------------------- /chapter4/Example_4_8_Image_Texture_System_Smoke/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Particle { 6 | PVector position, velocity, acceleration; 7 | float lifespan; 8 | 9 | Particle(float x, float y) { 10 | this.position = new PVector(x, y); 11 | float vx = (randomGaussian() * 0.3); 12 | float vy = (randomGaussian() * 0.3) - 1; 13 | this.velocity = new PVector(vx, vy); 14 | this.acceleration = new PVector(0, 0); 15 | this.lifespan = 100.0; 16 | } 17 | 18 | void run() { 19 | this.update(); 20 | this.show(); 21 | } 22 | 23 | // Method to apply a force vector to the Particle object 24 | // Note we are ignoring "mass" here 25 | void applyForce(PVector force) { 26 | this.acceleration.add(force); 27 | } 28 | 29 | // Method to update position 30 | void update() { 31 | this.velocity.add(this.acceleration); 32 | this.position.add(this.velocity); 33 | this.lifespan -= 2; 34 | this.acceleration.mult(0); // clear Acceleration 35 | } 36 | 37 | // Method to draw 38 | void show() { 39 | tint(255, this.lifespan); 40 | imageMode(CENTER); 41 | image(img, this.position.x, this.position.y); 42 | // Drawing a circle instead 43 | // fill(255, lifespan); 44 | // noStroke(); 45 | // circle(pos.x, pos.y, img.width); 46 | } 47 | 48 | // Is the particle still useful? 49 | boolean isDead() { 50 | return (this.lifespan < 0.0); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /chapter4/Example_4_8_Image_Texture_System_Smoke/data/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nature-of-code/noc-2-processing-port/0fec54e9252cfd393926b5db5bfdeaae67bce733/chapter4/Example_4_8_Image_Texture_System_Smoke/data/texture.png -------------------------------------------------------------------------------- /chapter4/Example_4_9_Additive_Blending/Emitter.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Smoke Particle System 6 | 7 | // A class to describe a group of Particles 8 | // An ArrayList is used to manage the list of Particles 9 | 10 | class Emitter { 11 | PVector origin; 12 | ArrayList particles; 13 | PImage img; 14 | 15 | Emitter(float x, float y, PImage img) { 16 | this.origin = new PVector(x, y); // Initialize the arraylist 17 | this.particles = new ArrayList(); // Store the origin point 18 | this.img = img; 19 | } 20 | 21 | void run() { 22 | for (int i = this.particles.size() - 1; i >= 0; i--) { 23 | Particle particle = this.particles.get(i); 24 | particle.run(); 25 | if (particle.isDead()) { 26 | this.particles.remove(i); 27 | } 28 | } 29 | } 30 | 31 | // Method to add a force vector to all particles currently in the system 32 | void applyForce(PVector force) { 33 | // Enhanced loop!!! 34 | for (Particle particle : this.particles) { 35 | particle.applyForce(force); 36 | } 37 | } 38 | 39 | void addParticle() { 40 | this.particles.add(new Particle(this.origin.x, this.origin.y, this.img)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /chapter4/Example_4_9_Additive_Blending/Example_4_9_Additive_Blending.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Smoke Particle System 6 | 7 | // A basic smoke effect using a particle system 8 | // Each particle is rendered as an alpha masked image 9 | 10 | 11 | Emitter emitter; 12 | PImage img; 13 | 14 | void setup() { 15 | size(640, 360); 16 | img = loadImage("texture.png"); 17 | emitter = new Emitter(width / 2, height - 75, img); 18 | } 19 | 20 | void draw() { 21 | 22 | // Access WEBGL Directly for more blending options? 23 | // let gl = this._renderer.GL; 24 | // gl.enable(gl.BLEND); 25 | // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 26 | 27 | background(0); 28 | // Additive blending! 29 | blendMode(ADD); 30 | 31 | // Calculate a "wind" force based on mouse horizontal position 32 | float dx = map(mouseX, 0, width, -0.2, 0.2); 33 | PVector wind = new PVector(dx, 0); 34 | emitter.applyForce(wind); 35 | emitter.run(); 36 | for (int i = 0; i < 3; i++) { 37 | emitter.addParticle(); 38 | } 39 | 40 | // Draw an arrow representing the wind force 41 | drawVector(wind, new PVector(width / 2, 50, 0), 500); 42 | 43 | } 44 | 45 | // Renders a vector object 'v' as an arrow and a position 'loc' 46 | void drawVector(PVector v, PVector pos, float scayl) { 47 | push(); 48 | float arrowsize = 4; 49 | // Translate to position to render vector 50 | translate(pos.x, pos.y); 51 | stroke(255); 52 | // Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate 53 | rotate(v.heading()); 54 | // Calculate length of vector & scale it to be bigger or smaller if necessary 55 | float len = v.mag() * scayl; 56 | // Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) 57 | line(0, 0, len, 0); 58 | line(len, 0, len - arrowsize, +arrowsize / 2); 59 | line(len, 0, len - arrowsize, -arrowsize / 2); 60 | pop(); 61 | } 62 | -------------------------------------------------------------------------------- /chapter4/Example_4_9_Additive_Blending/Particle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Particle { 6 | PVector position, velocity, acceleration; 7 | float lifespan; 8 | PImage img; 9 | 10 | Particle(float x, float y, PImage img) { 11 | this.position = new PVector(x, y); 12 | float vx = (randomGaussian() * 0.3); 13 | float vy = (randomGaussian() * 0.3) - 1; 14 | this.velocity = new PVector(vx, vy); 15 | this.acceleration = new PVector(0, 0); 16 | this.lifespan = 100.0; 17 | this.img = img; 18 | } 19 | 20 | void run() { 21 | this.update(); 22 | this.show(); 23 | } 24 | 25 | // Method to apply a force vector to the Particle object 26 | // Note we are ignoring "mass" here 27 | void applyForce(PVector f) { 28 | this.acceleration.add(f); 29 | } 30 | 31 | // Method to update position 32 | void update() { 33 | this.velocity.add(this.acceleration); 34 | this.position.add(this.velocity); 35 | this.lifespan -= 2.5; 36 | this.acceleration.mult(0); // clear Acceleration 37 | } 38 | 39 | // Method to display 40 | void show() { 41 | tint(255, 100, 255, this.lifespan); 42 | imageMode(CENTER); 43 | image(img, this.position.x, this.position.y); 44 | } 45 | 46 | // Is the particle still useful? 47 | boolean isDead() { 48 | return (this.lifespan < 0.0); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter4/Example_4_9_Additive_Blending/data/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nature-of-code/noc-2-processing-port/0fec54e9252cfd393926b5db5bfdeaae67bce733/chapter4/Example_4_9_Additive_Blending/data/texture.png -------------------------------------------------------------------------------- /chapter5/Example_5_10_Combining_Seek_Separate/Example_5_10_Combining_Seek_Separate.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Separation 6 | // Via Reynolds: http://www.red3d.com/cwr/steer/ 7 | 8 | // A list of vehicles 9 | ArrayList vehicles; 10 | 11 | void setup() { 12 | size(640, 360); 13 | vehicles = new ArrayList(); 14 | 15 | // We are now making random vehicles and storing them in an array 16 | for (int i = 0; i < 50; i++) { 17 | vehicles.add(new Vehicle(random(width), random(height))); 18 | } 19 | 20 | 21 | } 22 | 23 | void draw() { 24 | background(255); 25 | 26 | for (Vehicle v : vehicles) { 27 | v.applyBehaviors(vehicles); 28 | v.update(); 29 | v.borders(); 30 | v.show(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /chapter5/Example_5_10_Combining_Seek_Separate/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Vehicle object 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y) { 16 | // All the usual stuff 17 | this.position = new PVector(x, y); 18 | this.r = 6; 19 | this.maxspeed = 3; // Maximum speed 20 | this.maxforce = 0.2; // Maximum steering force 21 | this.acceleration = new PVector(0, 0); 22 | this.velocity = new PVector(0, 0); 23 | } 24 | 25 | void applyBehaviors(ArrayList vehicles) { 26 | PVector separateForce = this.separate(vehicles); 27 | PVector seekForce = this.seek(new PVector(mouseX, mouseY)); 28 | 29 | separateForce.mult(1.5); 30 | seekForce.mult(0.5); 31 | 32 | this.applyForce(separateForce); 33 | this.applyForce(seekForce); 34 | } 35 | 36 | void applyForce(PVector force) { 37 | // We could add mass here if we want A = F / M 38 | this.acceleration.add(force); 39 | } 40 | 41 | // Separation 42 | // Method checks for nearby vehicles and steers away 43 | PVector separate(ArrayList vehicles) { 44 | float desiredSeparation = this.r * 2; 45 | PVector sum = new PVector(); 46 | int count = 0; 47 | // For every vehicle in the system, check if it's too close 48 | for (Vehicle other : vehicles) { 49 | float d = PVector.dist(this.position, other.position); 50 | // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) 51 | if (this != other && d < desiredSeparation) { 52 | // Calculate vector pointing away from neighbor 53 | PVector diff = PVector.sub(this.position, other.position); 54 | diff.setMag(1 / d); // Weight by distance 55 | sum.add(diff); 56 | count++; // Keep track of how many 57 | } 58 | } 59 | // Average -- divide by how many 60 | if (count > 0) { 61 | sum.div(count); 62 | // Our desired vector is the average scaled to maximum speed 63 | sum.setMag(this.maxspeed); 64 | // Implement Reynolds: Steering = Desired - Velocity 65 | sum.sub(this.velocity); 66 | sum.limit(this.maxforce); 67 | } 68 | return sum; 69 | } 70 | 71 | // A method that calculates a steering force towards a target 72 | // STEER = DESIRED MINUS VELOCITY 73 | PVector seek(PVector target) { 74 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the location to the target 75 | 76 | // Normalize desired and scale to maximum speed 77 | desired.normalize(); 78 | desired.mult(this.maxspeed); 79 | // Steering = Desired minus velocity 80 | PVector steer = PVector.sub(desired, this.velocity); 81 | steer.limit(this.maxforce); // Limit to maximum steering force 82 | return steer; 83 | } 84 | 85 | // Method to update location 86 | void update() { 87 | // Update velocity 88 | this.velocity.add(this.acceleration); 89 | // Limit speed 90 | this.velocity.limit(this.maxspeed); 91 | this.position.add(this.velocity); 92 | // Reset accelertion to 0 each cycle 93 | this.acceleration.mult(0); 94 | } 95 | 96 | void show() { 97 | fill(127); 98 | stroke(0); 99 | strokeWeight(2); 100 | push(); 101 | translate(this.position.x, this.position.y); 102 | circle(0, 0, this.r * 2); 103 | pop(); 104 | } 105 | 106 | // Wraparound 107 | void borders() { 108 | if (this.position.x < -this.r) this.position.x = width + this.r; 109 | if (this.position.y < -this.r) this.position.y = height + this.r; 110 | if (this.position.x > width + this.r) this.position.x = -this.r; 111 | if (this.position.y > height + this.r) this.position.y = -this.r; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /chapter5/Example_5_11_Flocking/Boid.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Boid class 6 | // Methods for Separation, Cohesion, Alignment added 7 | 8 | class Boid { 9 | PVector position; 10 | PVector velocity; 11 | PVector acceleration; 12 | float r; 13 | float maxspeed; 14 | float maxforce; 15 | 16 | Boid(float x, float y) { 17 | this.acceleration = new PVector(0, 0); 18 | this.velocity = new PVector(random(-1, 1), random(-1, 1)); 19 | this.position = new PVector(x, y); 20 | this.r = 3.0; 21 | this.maxspeed = 3; // Maximum speed 22 | this.maxforce = 0.05; // Maximum steering force 23 | } 24 | 25 | void run(ArrayList boids) { 26 | this.flock(boids); 27 | this.update(); 28 | this.borders(); 29 | this.show(); 30 | } 31 | 32 | void applyForce(PVector force) { 33 | // We could add mass here if we want A = F / M 34 | this.acceleration.add(force); 35 | } 36 | 37 | // We accumulate a new acceleration each time based on three rules 38 | void flock(ArrayList boids) { 39 | PVector sep = this.separate(boids); // Separation 40 | PVector ali = this.align(boids); // Alignment 41 | PVector coh = this.cohere(boids); // Cohesion 42 | // Arbitrarily weight these forces 43 | sep.mult(1.5); 44 | ali.mult(1.0); 45 | coh.mult(1.0); 46 | // Add the force vectors to acceleration 47 | this.applyForce(sep); 48 | this.applyForce(ali); 49 | this.applyForce(coh); 50 | } 51 | 52 | // Method to update location 53 | void update() { 54 | // Update velocity 55 | this.velocity.add(this.acceleration); 56 | // Limit speed 57 | this.velocity.limit(this.maxspeed); 58 | this.position.add(this.velocity); 59 | // Reset accelertion to 0 each cycle 60 | this.acceleration.mult(0); 61 | } 62 | 63 | // A method that calculates and applies a steering force towards a target 64 | // STEER = DESIRED MINUS VELOCITY 65 | PVector seek(PVector target) { 66 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the location to the target 67 | // Normalize desired and scale to maximum speed 68 | desired.normalize(); 69 | desired.mult(this.maxspeed); 70 | // Steering = Desired minus Velocity 71 | PVector steer = PVector.sub(desired, this.velocity); 72 | steer.limit(this.maxforce); // Limit to maximum steering force 73 | return steer; 74 | } 75 | 76 | void show() { 77 | // Draw a triangle rotated in the direction of velocity 78 | float angle = this.velocity.heading(); 79 | fill(127); 80 | stroke(0); 81 | push(); 82 | translate(this.position.x, this.position.y); 83 | rotate(angle); 84 | beginShape(); 85 | vertex(this.r * 2, 0); 86 | vertex(-this.r * 2, -this.r); 87 | vertex(-this.r * 2, this.r); 88 | endShape(CLOSE); 89 | pop(); 90 | } 91 | 92 | // Wraparound 93 | void borders() { 94 | if (this.position.x < -this.r) this.position.x = width + this.r; 95 | if (this.position.y < -this.r) this.position.y = height + this.r; 96 | if (this.position.x > width + this.r) this.position.x = -this.r; 97 | if (this.position.y > height + this.r) this.position.y = -this.r; 98 | } 99 | 100 | // Separation 101 | // Method checks for nearby boids and steers away 102 | PVector separate(ArrayList boids) { 103 | float desiredSeparation = 25; 104 | PVector steer = new PVector(0, 0); 105 | int count = 0; 106 | // For every boid in the system, check if it's too close 107 | for (int i = 0; i < boids.size(); i++) { 108 | float d = PVector.dist(this.position, boids.get(i).position); 109 | // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) 110 | if (d > 0 && d < desiredSeparation) { 111 | // Calculate vector pointing away from neighbor 112 | PVector diff = PVector.sub(this.position, boids.get(i).position); 113 | diff.normalize(); 114 | diff.div(d); // Weight by distance 115 | steer.add(diff); 116 | count++; // Keep track of how many 117 | } 118 | } 119 | // Average -- divide by how many 120 | if (count > 0) { 121 | steer.div(count); 122 | } 123 | 124 | // As long as the vector is greater than 0 125 | if (steer.mag() > 0) { 126 | // Implement Reynolds: Steering = Desired - Velocity 127 | steer.normalize(); 128 | steer.mult(this.maxspeed); 129 | steer.sub(this.velocity); 130 | steer.limit(this.maxforce); 131 | } 132 | return steer; 133 | } 134 | 135 | // Alignment 136 | // For every nearby boid in the system, calculate the average velocity 137 | PVector align(ArrayList boids) { 138 | float neighborDistance = 50; 139 | PVector sum = new PVector(0, 0); 140 | int count = 0; 141 | for (int i = 0; i < boids.size(); i++) { 142 | float d = PVector.dist(this.position, boids.get(i).position); 143 | if (d > 0 && d < neighborDistance) { 144 | sum.add(boids.get(i).velocity); 145 | count++; 146 | } 147 | } 148 | if (count > 0) { 149 | sum.div(count); 150 | sum.normalize(); 151 | sum.mult(this.maxspeed); 152 | PVector steer = PVector.sub(sum, this.velocity); 153 | steer.limit(this.maxforce); 154 | return steer; 155 | } else { 156 | return new PVector(0, 0); 157 | } 158 | } 159 | 160 | // Cohesion 161 | // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location 162 | PVector cohere(ArrayList boids) { 163 | float neighborDistance = 50; 164 | PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all locations 165 | int count = 0; 166 | for (int i = 0; i < boids.size(); i++) { 167 | float d = PVector.dist(this.position, boids.get(i).position); 168 | if (d > 0 && d < neighborDistance) { 169 | sum.add(boids.get(i).position); // Add location 170 | count++; 171 | } 172 | } 173 | if (count > 0) { 174 | sum.div(count); 175 | return this.seek(sum); // Steer towards the location 176 | } else { 177 | return new PVector(0, 0); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /chapter5/Example_5_11_Flocking/Example_5_11_Flocking.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Demonstration of Craig Reynolds' "Flocking" behavior 6 | // See: http://www.red3d.com/cwr/ 7 | // Rules: Cohesion, Separation, Alignment 8 | 9 | // Click mouse to add boids into the system 10 | 11 | Flock flock; 12 | 13 | void setup() { 14 | size(640, 360); 15 | flock = new Flock(); 16 | // Add an initial set of boids into the system 17 | for (int i = 0; i < 120; i++) { 18 | Boid boid = new Boid(width / 2, height / 2); 19 | flock.addBoid(boid); 20 | } 21 | } 22 | 23 | void draw() { 24 | background(255); 25 | flock.run(); 26 | } 27 | 28 | // Add a new boid into the System 29 | void mouseDragged() { 30 | flock.addBoid(new Boid(mouseX, mouseY)); 31 | } 32 | -------------------------------------------------------------------------------- /chapter5/Example_5_11_Flocking/Flock.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Flock object 6 | // Does very little, simply manages the array of all the boids 7 | 8 | class Flock { 9 | ArrayList boids; 10 | 11 | Flock() { 12 | // An array for all the boids 13 | this.boids = new ArrayList(); // Initialize the array 14 | } 15 | 16 | void run() { 17 | for (Boid boid : this.boids) { 18 | boid.run(this.boids); // Passing the entire list of boids to each boid individually 19 | } 20 | } 21 | 22 | void addBoid(Boid b) { 23 | this.boids.add(b); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /chapter5/Example_5_12_Bin_Lattice_Spatial_Separation/Boid.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Boid class 6 | // Methods for Separation, Cohesion, Alignment added 7 | 8 | class Boid { 9 | PVector position; 10 | PVector velocity; 11 | PVector acceleration; 12 | float r; 13 | float maxspeed; 14 | float maxforce; 15 | 16 | Boid(float x, float y) { 17 | this.acceleration = new PVector(0, 0); 18 | this.velocity = new PVector(random(-1, 1), random(-1, 1)); 19 | this.position = new PVector(x, y); 20 | this.r = 3.0; 21 | this.maxspeed = 3; // Maximum speed 22 | this.maxforce = 0.05; // Maximum steering force 23 | } 24 | 25 | // No argument to run() anymore, could bring in grid 26 | // but accessing it as global variable instead 27 | void run() { 28 | int col = (int)Math.floor(this.position.x / resolution); 29 | int row = (int)Math.floor(this.position.y / resolution); 30 | ArrayList neighbors = new ArrayList<>(); 31 | 32 | // Check cells in a 3x3 block around the current boid 33 | for (int i = -1; i <= 1; i++) { 34 | for (int j = -1; j <= 1; j++) { 35 | int newCol = col + i; 36 | int newRow = row + j; 37 | // Make sure this is a valid cell 38 | if (newCol >= 0 && newCol < cols && newRow >= 0 && newRow < rows) { 39 | // Add all boids in this cell to neighbors 40 | grid.get(newRow).get(newCol); 41 | 42 | ArrayList cell = grid.get(newRow).get(newCol); 43 | for(int b = 0; b < cell.size(); b++){ 44 | neighbors.add(cell.get(b)); 45 | } 46 | } 47 | } 48 | } 49 | 50 | this.flock(neighbors); 51 | this.update(); 52 | this.borders(); 53 | this.show(); 54 | } 55 | 56 | void applyForce(PVector force) { 57 | // We could add mass here if we want A = F / M 58 | this.acceleration.add(force); 59 | } 60 | 61 | // We accumulate a new acceleration each time based on three rules 62 | void flock(ArrayList boids) { 63 | PVector sep = this.separate(boids); // Separation 64 | PVector ali = this.align(boids); // Alignment 65 | PVector coh = this.cohesion(boids); // Cohesion 66 | // Arbitrarily weight these forces 67 | sep.mult(1.5); 68 | ali.mult(1.0); 69 | coh.mult(1.0); 70 | // Add the force vectors to acceleration 71 | this.applyForce(sep); 72 | this.applyForce(ali); 73 | this.applyForce(coh); 74 | } 75 | 76 | // Method to update location 77 | void update() { 78 | // Update velocity 79 | this.velocity.add(this.acceleration); 80 | // Limit speed 81 | this.velocity.limit(this.maxspeed); 82 | this.position.add(this.velocity); 83 | // Reset accelertion to 0 each cycle 84 | this.acceleration.mult(0); 85 | } 86 | 87 | // A method that calculates and applies a steering force towards a target 88 | // STEER = DESIRED MINUS VELOCITY 89 | PVector seek(PVector target) { 90 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the location to the target 91 | // Normalize desired and scale to maximum speed 92 | desired.normalize(); 93 | desired.mult(this.maxspeed); 94 | // Steering = Desired minus Velocity 95 | PVector steer = PVector.sub(desired, this.velocity); 96 | steer.limit(this.maxforce); // Limit to maximum steering force 97 | return steer; 98 | } 99 | 100 | void show() { 101 | // Draw a triangle rotated in the direction of velocity 102 | float angle = this.velocity.heading(); 103 | fill(127); 104 | stroke(0); 105 | push(); 106 | translate(this.position.x, this.position.y); 107 | rotate(angle); 108 | beginShape(); 109 | vertex(this.r * 2, 0); 110 | vertex(-this.r * 2, -this.r); 111 | vertex(-this.r * 2, this.r); 112 | endShape(CLOSE); 113 | pop(); 114 | } 115 | 116 | // Wraparound 117 | void borders() { 118 | if (this.position.x < -this.r) this.position.x = width + this.r; 119 | if (this.position.y < -this.r) this.position.y = height + this.r; 120 | if (this.position.x > width + this.r) this.position.x = -this.r; 121 | if (this.position.y > height + this.r) this.position.y = -this.r; 122 | } 123 | 124 | // Separation 125 | // Method checks for nearby boids and steers away 126 | PVector separate(ArrayList boids) { 127 | float desiredseparation = 25.0; 128 | PVector steer = new PVector(0, 0); 129 | int count = 0; 130 | // For every boid in the system, check if it's too close 131 | for (int i = 0; i < boids.size(); i++) { 132 | float d = PVector.dist(this.position, boids.get(i).position); 133 | // If the distance is greater than 0 and less than an arbitrary amount (0 when you are yourself) 134 | if (d > 0 && d < desiredseparation) { 135 | // Calculate vector pointing away from neighbor 136 | PVector diff = PVector.sub(this.position, boids.get(i).position); 137 | diff.normalize(); 138 | diff.div(d); // Weight by distance 139 | steer.add(diff); 140 | count++; // Keep track of how many 141 | } 142 | } 143 | // Average -- divide by how many 144 | if (count > 0) { 145 | steer.div(count); 146 | } 147 | 148 | // As long as the vector is greater than 0 149 | if (steer.mag() > 0) { 150 | // Implement Reynolds: Steering = Desired - Velocity 151 | steer.normalize(); 152 | steer.mult(this.maxspeed); 153 | steer.sub(this.velocity); 154 | steer.limit(this.maxforce); 155 | } 156 | return steer; 157 | } 158 | 159 | // Alignment 160 | // For every nearby boid in the system, calculate the average velocity 161 | PVector align(ArrayList boids) { 162 | float neighbordist = 50; 163 | PVector sum = new PVector(0, 0); 164 | int count = 0; 165 | for (int i = 0; i < boids.size(); i++) { 166 | float d = PVector.dist(this.position, boids.get(i).position); 167 | if (d > 0 && d < neighbordist) { 168 | sum.add(boids.get(i).velocity); 169 | count++; 170 | } 171 | } 172 | if (count > 0) { 173 | sum.div(count); 174 | sum.normalize(); 175 | sum.mult(this.maxspeed); 176 | PVector steer = PVector.sub(sum, this.velocity); 177 | steer.limit(this.maxforce); 178 | return steer; 179 | } else { 180 | return new PVector(0, 0); 181 | } 182 | } 183 | 184 | // Cohesion 185 | // For the average location (i.e. center) of all nearby boids, calculate steering vector towards that location 186 | PVector cohesion(ArrayList boids) { 187 | float neighbordist = 50; 188 | PVector sum = new PVector(0, 0); // Start with empty vector to accumulate all locations 189 | int count = 0; 190 | for (int i = 0; i < boids.size(); i++) { 191 | float d = PVector.dist(this.position, boids.get(i).position); 192 | if (d > 0 && d < neighbordist) { 193 | sum.add(boids.get(i).position); // Add location 194 | count++; 195 | } 196 | } 197 | if (count > 0) { 198 | sum.div(count); 199 | return this.seek(sum); // Steer towards the location 200 | } else { 201 | return new PVector(0, 0); 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /chapter5/Example_5_12_Bin_Lattice_Spatial_Separation/Example_5_12_Bin_Lattice_Spatial_Separation.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Demonstration of Craig Reynolds' "Flocking" behavior 6 | // See: http://www.red3d.com/cwr/ 7 | // Rules: Cohesion, Separation, Alignment 8 | 9 | // Click mouse to add boids into the system 10 | 11 | Flock flock; 12 | 13 | // bin-lattice spatial subdivision 14 | ArrayList>> grid; 15 | int cols; 16 | int rows; 17 | float resolution = 40; // adjust as necessary 18 | 19 | // Creates 3D Grid Array 20 | void make3DArray(int cols, int rows){ 21 | grid = new ArrayList<>(); 22 | while(grid.size() <= rows){ 23 | grid.add(new ArrayList<>()); 24 | } 25 | 26 | for(int i = 0; i < rows; i++){ 27 | ArrayList> rowList = grid.get(i); 28 | while(rowList.size() <= cols){ 29 | rowList.add(new ArrayList()); 30 | } 31 | } 32 | } 33 | 34 | void setup() { 35 | size(640, 360); 36 | cols = floor(width / resolution); 37 | rows = floor(height / resolution); 38 | make3DArray(cols, rows); 39 | 40 | flock = new Flock(); 41 | 42 | // Add an initial set of boids into the system 43 | for (int i = 0; i < 800; i++) { 44 | Boid boid = new Boid(random(width), random(height)); 45 | flock.addBoid(boid); 46 | } 47 | } 48 | 49 | void draw() { 50 | background(255); 51 | 52 | // Reset grid at the beginning of each frame 53 | for(int i = 0; i < rows; i++){ 54 | for(int j = 0; j < cols; j++){ 55 | grid.get(i).get(j).clear(); 56 | } 57 | } 58 | 59 | // Place each boid into the appropriate cell in the grid 60 | for (Boid boid : flock.boids) { 61 | int col = floor(boid.position.x / resolution); 62 | int row = floor(boid.position.y / resolution); 63 | col = constrain(col, 0, cols - 1); 64 | row = constrain(row, 0, rows - 1); 65 | grid.get(row).get(col).add(boid); 66 | } 67 | 68 | // Draw the grid 69 | stroke(200); 70 | strokeWeight(1); 71 | 72 | // Draw vertical lines 73 | for (int i = 0; i <= cols; i++) { 74 | float x = i * resolution; 75 | line(x, 0, x, height); 76 | } 77 | 78 | // Draw horizontal lines 79 | for (int j = 0; j <= rows; j++) { 80 | float y = j * resolution; 81 | line(0, y, width, y); 82 | } 83 | 84 | // Highlight the 3x3 neighborhood the mouse is over 85 | int mouseCol = floor(mouseX / resolution); 86 | int mouseRow = floor(mouseY / resolution); 87 | noStroke(); 88 | fill(255, 50, 50, 100); // Semi-transparent red 89 | for (int i = -1; i <= 1; i++) { 90 | for (int j = -1; j <= 1; j++) { 91 | int col = mouseCol + i; 92 | int row = mouseRow + j; 93 | // Check if the cell is within the grid 94 | if (col >= 0 && col < cols && row >= 0 && row < rows) { 95 | rect(col * resolution, row * resolution, resolution, resolution); 96 | } 97 | } 98 | } 99 | 100 | flock.run(); 101 | } 102 | 103 | // Add a new boid into the System 104 | void mouseDragged() { 105 | flock.addBoid(new Boid(mouseX, mouseY)); 106 | } 107 | -------------------------------------------------------------------------------- /chapter5/Example_5_12_Bin_Lattice_Spatial_Separation/Flock.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Flock object 6 | // Does very little, simply manages the array of all the boids 7 | 8 | class Flock { 9 | 10 | ArrayList boids; 11 | 12 | Flock() { 13 | // An array for all the boids 14 | this.boids = new ArrayList(); // Initialize the array 15 | } 16 | 17 | void run() { 18 | for (Boid boid : this.boids) { 19 | boid.run(); 20 | } 21 | } 22 | 23 | void addBoid(Boid boid) { 24 | this.boids.add(boid); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /chapter5/Example_5_13_QuadTree/Example_5_13_QuadTree.pde: -------------------------------------------------------------------------------- 1 | // Daniel Shiffman 2 | // http://codingtra.in 3 | // http://patreon.com/codingtrain 4 | 5 | // QuadTree 6 | // 1: https://www.youtube.com/watch?v=OJxEcs0w_kE 7 | // 2: https://www.youtube.com/watch?v=QQx_NmCIuCY 8 | 9 | // For more: 10 | // https://github.com/CodingTrain/QuadTree 11 | 12 | QuadTree qtree; 13 | 14 | void setup() { 15 | size(640, 360); 16 | Rectangle boundary = new Rectangle(width / 2, height / 2, width, height); 17 | qtree = new QuadTree(boundary, 8); 18 | for (int i = 0; i < 2000; i++) { 19 | float mean = width/2.0f; 20 | float stdDev = width / 8.0f; 21 | float x = randomGaussian() * stdDev + mean; 22 | float y = randomGaussian() * stdDev + mean; 23 | Point p = new Point(x, y); 24 | qtree.insert(p); 25 | } 26 | } 27 | 28 | void draw() { 29 | background(255); 30 | qtree.show(); 31 | 32 | rectMode(CENTER); 33 | Rectangle range = new Rectangle(mouseX, mouseY, 50, 50); 34 | 35 | // This check has been introduced due to a bug discussed in https://github.com/CodingTrain/website/pull/556 36 | if (mouseX < width && mouseY < height) { 37 | strokeWeight(2); 38 | stroke(255, 50, 50); 39 | fill(255, 50, 50, 50); 40 | rect(range.x, range.y, range.w * 2, range.h * 2); 41 | ArrayList points = new ArrayList<>(); 42 | points = qtree.query(range, points); 43 | println(points); 44 | for (Point p : points) { 45 | strokeWeight(3); 46 | stroke(50, 50, 50); 47 | point(p.x, p.y); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter5/Example_5_13_QuadTree/QuadTree.pde: -------------------------------------------------------------------------------- 1 | // Daniel Shiffman 2 | // http://codingtra.in 3 | // http://patreon.com/codingtrain 4 | 5 | // QuadTree 6 | // 1: https://www.youtube.com/watch?v=OJxEcs0w_kE 7 | // 2: https://www.youtube.com/watch?v=QQx_NmCIuCY 8 | 9 | // For more: 10 | // https://github.com/CodingTrain/QuadTree 11 | 12 | class Point { 13 | float x, y; 14 | 15 | Point(float x, float y) { 16 | this.x = x; 17 | this.y = y; 18 | } 19 | } 20 | 21 | class Rectangle { 22 | float x, y, w, h; 23 | 24 | Rectangle(float x, float y, float w, float h) { 25 | this.x = x; 26 | this.y = y; 27 | this.w = w; 28 | this.h = h; 29 | } 30 | 31 | boolean contains(Point point) { 32 | return (point.x >= this.x - this.w && 33 | point.x < this.x + this.w && 34 | point.y >= this.y - this.h && 35 | point.y < this.y + this.h); 36 | } 37 | 38 | boolean intersects(Rectangle range) { 39 | return !(range.x - range.w > this.x + this.w || 40 | range.x + range.w < this.x - this.w || 41 | range.y - range.h > this.y + this.h || 42 | range.y + range.h < this.y - this.h); 43 | } 44 | } 45 | 46 | class QuadTree { 47 | Rectangle boundary; 48 | int capacity; 49 | ArrayList points; 50 | boolean divided; 51 | QuadTree northeast; 52 | QuadTree northwest; 53 | QuadTree southeast; 54 | QuadTree southwest; 55 | 56 | QuadTree(Rectangle boundary, int n) { 57 | this.boundary = boundary; 58 | this.capacity = n; 59 | this.points = new ArrayList<>(); 60 | this.divided = false; 61 | this.northeast = null; 62 | this.northwest = null; 63 | this.southeast = null; 64 | this.southwest = null; 65 | } 66 | 67 | void subdivide() { 68 | float x = this.boundary.x; 69 | float y = this.boundary.y; 70 | float w = this.boundary.w; 71 | float h = this.boundary.h; 72 | Rectangle ne = new Rectangle(x + w / 2, y - h / 2, w / 2, h / 2); 73 | this.northeast = new QuadTree(ne, this.capacity); 74 | Rectangle nw = new Rectangle(x - w / 2, y - h / 2, w / 2, h / 2); 75 | this.northwest = new QuadTree(nw, this.capacity); 76 | Rectangle se = new Rectangle(x + w / 2, y + h / 2, w / 2, h / 2); 77 | this.southeast = new QuadTree(se, this.capacity); 78 | Rectangle sw = new Rectangle(x - w / 2, y + h / 2, w / 2, h / 2); 79 | this.southwest = new QuadTree(sw, this.capacity); 80 | this.divided = true; 81 | } 82 | 83 | boolean insert(Point point) { 84 | 85 | if (!this.boundary.contains(point)) { 86 | return false; 87 | } 88 | 89 | if (this.points.size() < this.capacity) { 90 | this.points.add(point); 91 | return true; 92 | } else { 93 | if (!this.divided) { 94 | this.subdivide(); 95 | } 96 | if (this.northeast.insert(point)) { 97 | return true; 98 | } else if (this.northwest.insert(point)) { 99 | return true; 100 | } else if (this.southeast.insert(point)) { 101 | return true; 102 | } else if (this.southwest.insert(point)) { 103 | return true; 104 | } 105 | } 106 | return false; 107 | } 108 | 109 | ArrayList query(Rectangle range, ArrayList found) { 110 | if (!this.boundary.intersects(range)) { 111 | return found; 112 | } else { 113 | for (Point p : this.points) { 114 | if (range.contains(p)) { 115 | found.add(p); 116 | } 117 | } 118 | if (this.divided) { 119 | this.northwest.query(range, found); 120 | this.northeast.query(range, found); 121 | this.southwest.query(range, found); 122 | this.southeast.query(range, found); 123 | } 124 | } 125 | return found; 126 | } 127 | 128 | 129 | void show() { 130 | stroke(0); 131 | noFill(); 132 | strokeWeight(1); 133 | rectMode(CENTER); 134 | rect(this.boundary.x, this.boundary.y, this.boundary.w * 2, this.boundary.h * 2); 135 | for (Point p : this.points) { 136 | strokeWeight(1); 137 | stroke(0); 138 | point(p.x, p.y); 139 | } 140 | 141 | if (this.divided) { 142 | this.northeast.show(); 143 | this.northwest.show(); 144 | this.southeast.show(); 145 | this.southwest.show(); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /chapter5/Example_5_14_COS_SIN_LUT/Example_5_14_COS_SIN_LUT.pde: -------------------------------------------------------------------------------- 1 | /* 2 | sincoslookup taken from http://wiki.processing.org/index.php/Sin/Cos_look-up_table 3 | archived version http://web.archive.org/web/20130510100827/http://wiki.processing.org/w/Sin/Cos_look-up_table 4 | ported to p5.js by Miká Kruschel 5 | https://editor.p5js.org/mikakruschel/sketches/Ag6QMqDE 6 | */ 7 | 8 | // declare arrays and params for storing sin/cos values 9 | float[] sinLUT; 10 | float[] cosLUT; 11 | // set table precision to 0.5 degrees 12 | final float SC_PRECISION = 0.5; 13 | // caculate reciprocal for conversions 14 | final float SC_INV_PREC = 1 / SC_PRECISION; 15 | // compute required table length 16 | final int SC_PERIOD = (int)Math.floor(360 * SC_INV_PREC); 17 | 18 | // init sin/cos tables with values 19 | // should be called from setup() 20 | void initSinCos() { 21 | sinLUT = new float[SC_PERIOD]; 22 | cosLUT = new float[SC_PERIOD]; 23 | for (int i = 0; i < SC_PERIOD; i++) { 24 | sinLUT[i] = sin(i * DEG_TO_RAD * SC_PRECISION); 25 | cosLUT[i] = cos(i * DEG_TO_RAD * SC_PRECISION); 26 | } 27 | } 28 | 29 | // circle radius used for example 30 | float radius; 31 | 32 | void setup() { 33 | size(640, 360); 34 | initSinCos(); // important call to initialize lookup tables 35 | } 36 | 37 | void draw() { 38 | background(255); 39 | // modulate the current radius 40 | radius = 50 + 50 * sinLUT[frameCount % SC_PERIOD]; 41 | 42 | // draw a circle made of points (every 5 degrees) 43 | for (int i = 0; i < 360; i += 5) { 44 | // convert degrees into array index: 45 | // the modulo operator (%) ensures periodicity 46 | int theta = int((i * SC_INV_PREC) % SC_PERIOD); 47 | strokeWeight(4); 48 | // draw the circle around mouse pos 49 | point( 50 | width / 2 + radius * cosLUT[theta], 51 | height / 2 + radius * sinLUT[theta] 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /chapter5/Example_5_1_Seek/Example_5_1_Seek.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Seeking "vehicle" follows the mouse position 6 | 7 | // Implements Craig Reynold's autonomous steering behaviors 8 | // One vehicle "seeks" 9 | // See: http://www.red3d.com/cwr/ 10 | 11 | Vehicle vehicle; 12 | 13 | void setup() { 14 | size(640, 360); 15 | vehicle = new Vehicle(width / 2, height / 2); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | 21 | PVector mouse = new PVector(mouseX, mouseY); 22 | 23 | // Draw an ellipse at the mouse position 24 | fill(127); 25 | stroke(0); 26 | strokeWeight(2); 27 | circle(mouse.x, mouse.y, 48); 28 | 29 | // Call the appropriate steering behaviors for our agents 30 | vehicle.seek(mouse); 31 | vehicle.update(); 32 | vehicle.show(); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /chapter5/Example_5_1_Seek/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y) { 16 | this.position = new PVector(x, y); 17 | this.velocity = new PVector(0, 0); 18 | this.acceleration = new PVector(0, 0); 19 | this.r = 6; 20 | this.maxspeed = 8; 21 | this.maxforce = 0.2; 22 | } 23 | 24 | // Method to update location 25 | void update() { 26 | // Update velocity 27 | this.velocity.add(this.acceleration); 28 | // Limit speed 29 | this.velocity.limit(this.maxspeed); 30 | this.position.add(this.velocity); 31 | // Reset acceleration to 0 each cycle 32 | this.acceleration.mult(0); 33 | } 34 | 35 | void applyForce(PVector force) { 36 | // We could add mass here if we want A = F / M 37 | this.acceleration.add(force); 38 | } 39 | 40 | // A method that calculates a steering force towards a target 41 | // STEER = DESIRED MINUS VELOCITY 42 | void seek(PVector target) { 43 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the location to the target 44 | 45 | // Scale to maximum speed 46 | desired.setMag(this.maxspeed); 47 | 48 | // Steering = Desired minus velocity 49 | PVector steer = PVector.sub(desired, this.velocity); 50 | steer.limit(this.maxforce); // Limit to maximum steering force 51 | 52 | this.applyForce(steer); 53 | } 54 | void show() { 55 | //{!1} Vehicle is a triangle pointing in the direction of velocity 56 | float angle = this.velocity.heading(); 57 | fill(127); 58 | stroke(0); 59 | push(); 60 | translate(this.position.x, this.position.y); 61 | rotate(angle); 62 | beginShape(); 63 | vertex(this.r * 2, 0); 64 | vertex(-this.r * 2, -this.r); 65 | vertex(-this.r * 2, this.r); 66 | endShape(CLOSE); 67 | pop(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /chapter5/Example_5_2_Arrive/Example_5_2_Arrive.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Arriving "vehicle" follows the mouse position 6 | 7 | // Implements Craig Reynold's autonomous steering behaviors 8 | // One vehicle "arrive" 9 | // See: http://www.red3d.com/cwr/ 10 | 11 | Vehicle vehicle; 12 | 13 | void setup() { 14 | size(640, 360); 15 | vehicle = new Vehicle(width / 2, height / 2); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | PVector mouse = new PVector(mouseX, mouseY); 21 | 22 | // Draw an ellipse at the mouse position 23 | fill(127); 24 | stroke(0); 25 | strokeWeight(2); 26 | circle(mouse.x, mouse.y, 48); 27 | 28 | // Call the appropriate steering behaviors for our agents 29 | vehicle.arrive(mouse); 30 | vehicle.update(); 31 | vehicle.show(); 32 | } 33 | 34 | void mousePressed(){ 35 | save("screenshot.png"); 36 | } 37 | -------------------------------------------------------------------------------- /chapter5/Example_5_2_Arrive/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y) { 16 | this.acceleration = new PVector(0, 0); 17 | this.velocity = new PVector(0, -2); 18 | this.position = new PVector(x, y); 19 | this.r = 6; 20 | this.maxspeed = 4; 21 | this.maxforce = 0.1; 22 | } 23 | 24 | // Method to update location 25 | void update() { 26 | // Update velocity 27 | this.velocity.add(this.acceleration); 28 | // Limit speed 29 | this.velocity.limit(this.maxspeed); 30 | this.position.add(this.velocity); 31 | // Reset accelerationelertion to 0 each cycle 32 | this.acceleration.mult(0); 33 | } 34 | 35 | void applyForce(PVector force) { 36 | // We could add mass here if we want A = F / M 37 | this.acceleration.add(force); 38 | } 39 | 40 | // A method that calculates a steering force towards a target 41 | // STEER = DESIRED MINUS VELOCITY 42 | void arrive(PVector target) { 43 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the location to the target 44 | float d = desired.mag(); 45 | // Scale with arbitrary damping within 100 pixels 46 | if (d < 100) { 47 | float m = map(d, 0, 100, 0, this.maxspeed); 48 | desired.setMag(m); 49 | } else { 50 | desired.setMag(this.maxspeed); 51 | } 52 | 53 | // Steering = Desired minus Velocity 54 | PVector steer = PVector.sub(desired, this.velocity); 55 | steer.limit(this.maxforce); // Limit to maximum steering force 56 | this.applyForce(steer); 57 | } 58 | 59 | void show() { 60 | // Draw a triangle rotated in the direction of velocity 61 | float angle = this.velocity.heading(); 62 | fill(127); 63 | stroke(0); 64 | strokeWeight(2); 65 | push(); 66 | translate(this.position.x, this.position.y); 67 | rotate(angle); 68 | beginShape(); 69 | vertex(this.r * 2, 0); 70 | vertex(-this.r * 2, -this.r); 71 | vertex(-this.r * 2, this.r); 72 | endShape(CLOSE); 73 | pop(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /chapter5/Example_5_3_Stay_Within_Walls/Example_5_3_Stay_Within_Walls.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Stay Within Walls 6 | // "Made-up" Steering behavior to stay within walls 7 | 8 | Vehicle vehicle; 9 | 10 | boolean debug = true; 11 | int offset = 25; 12 | 13 | void setup() { 14 | size(640, 360); 15 | vehicle = new Vehicle(width / 2, height / 2); 16 | } 17 | 18 | void draw() { 19 | background(255); 20 | 21 | if (debug) { 22 | stroke(0); 23 | noFill(); 24 | rectMode(CENTER); 25 | rect(width / 2, height / 2, width - offset * 2, height - offset * 2); 26 | } 27 | 28 | // Call the appropriate steering behaviors for our agents 29 | vehicle.boundaries(offset); 30 | 31 | vehicle.update(); 32 | vehicle.show(); 33 | 34 | } 35 | 36 | void mousePressed() { 37 | debug = !debug; 38 | } 39 | -------------------------------------------------------------------------------- /chapter5/Example_5_3_Stay_Within_Walls/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y) { 16 | this.acceleration = new PVector(0, 0); 17 | this.velocity = new PVector(3, 4); 18 | this.position = new PVector(x, y); 19 | this.r = 6; 20 | this.maxspeed = 3; 21 | this.maxforce = 0.15; 22 | } 23 | 24 | // Method to update location 25 | void update() { 26 | // Update velocity 27 | this.velocity.add(this.acceleration); 28 | // Limit speed 29 | this.velocity.limit(this.maxspeed); 30 | this.position.add(this.velocity); 31 | // Reset accelerationelertion to 0 each cycle 32 | this.acceleration.mult(0); 33 | } 34 | 35 | void applyForce(PVector force) { 36 | // We could add mass here if we want A = F / M 37 | this.acceleration.add(force); 38 | } 39 | 40 | void boundaries(int offset) { 41 | PVector desired = null; 42 | 43 | if (this.position.x < offset) { 44 | desired = new PVector(this.maxspeed, this.velocity.y); 45 | } else if (this.position.x > width - offset) { 46 | desired = new PVector(-this.maxspeed, this.velocity.y); 47 | } 48 | 49 | if (this.position.y < offset) { 50 | desired = new PVector(this.velocity.x, this.maxspeed); 51 | } else if (this.position.y > height - offset) { 52 | desired = new PVector(this.velocity.x, -this.maxspeed); 53 | } 54 | 55 | if (desired != null) { 56 | desired.normalize(); 57 | desired.mult(this.maxspeed); 58 | PVector steer = PVector.sub(desired, this.velocity); 59 | steer.limit(this.maxforce); 60 | this.applyForce(steer); 61 | } 62 | } 63 | 64 | void show() { 65 | // Draw a triangle rotated in the direction of velocity 66 | float angle = this.velocity.heading(); 67 | fill(127); 68 | stroke(0); 69 | strokeWeight(2); 70 | push(); 71 | translate(this.position.x, this.position.y); 72 | rotate(angle); 73 | beginShape(); 74 | vertex(this.r * 2, 0); 75 | vertex(-this.r * 2, -this.r); 76 | vertex(-this.r * 2, this.r); 77 | endShape(CLOSE); 78 | pop(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /chapter5/Example_5_4_Flow_Field/Example_5_4_Flow_Field.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Flow Field Following 6 | // Via Reynolds: http://www.red3d.com/cwr/steer/FlowFollow.html 7 | 8 | // Using this variable to decide whether to draw all the stuff 9 | boolean debug = true; 10 | 11 | // Flowfield object 12 | FlowField flowfield; 13 | // An ArrayList of vehicles 14 | Vehicle []vehicles; 15 | 16 | void setup() { 17 | println( 18 | "Hit space bar to toggle debugging lines.
Click the mouse to generate a new flow field." 19 | ); 20 | 21 | size(640, 360); 22 | // Make a new flow field with "resolution" of 16 23 | flowfield = new FlowField(20); 24 | vehicles = new Vehicle[120]; 25 | // Make a whole bunch of vehicles with random maxspeed and maxforce values 26 | for (int i = 0; i < 120; i++) { 27 | vehicles[i] = 28 | new Vehicle(random(width), random(height), random(2, 5), random(0.1, 0.5)); 29 | } 30 | } 31 | 32 | void draw() { 33 | background(255); 34 | // Display the flowfield in "debug" mode 35 | if (debug) flowfield.show(); 36 | // Tell all the vehicles to follow the flow field 37 | for (int i = 0; i < vehicles.length; i++) { 38 | vehicles[i].follow(flowfield); 39 | vehicles[i].run(); 40 | } 41 | } 42 | 43 | void keyPressed() { 44 | if (key == ' ') { 45 | debug = !debug; 46 | } 47 | } 48 | 49 | // Make a new flowfield 50 | void mousePressed() { 51 | flowfield.init(); 52 | } 53 | -------------------------------------------------------------------------------- /chapter5/Example_5_4_Flow_Field/FlowField.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Flow Field Following 6 | 7 | class FlowField { 8 | int resolution; 9 | int rows, cols; 10 | PVector [][]field; 11 | 12 | FlowField(int r) { 13 | this.resolution = r; 14 | //{!2} Determine the number of columns and rows. 15 | this.cols = width / this.resolution; 16 | this.rows = height / this.resolution; 17 | //{!4} A flow field is a two-dimensional array of vectors. The example includes as separate function to create that array 18 | 19 | this.field = new PVector[cols][rows]; 20 | /* 21 | this.field = new Array(this.cols); 22 | for (let i = 0; i < this.cols; i++) { 23 | this.field[i] = new Array(this.rows); 24 | } 25 | */ 26 | this.init(); 27 | } 28 | 29 | // The init() function fills the 2D array with vectors 30 | void init() { 31 | // Reseed noise for a new flow field each time 32 | noiseSeed((long)(random(10000))); 33 | float xoff = 0; 34 | for (int i = 0; i < this.cols; i++) { 35 | float yoff = 0; 36 | for (int j = 0; j < this.rows; j++) { 37 | //{.code-wide} In this example, use Perlin noise to create the vectors. 38 | float angle = map(noise(xoff, yoff), 0, 1, 0, TWO_PI); 39 | this.field[i][j] = PVector.fromAngle(angle); 40 | yoff += 0.1; 41 | } 42 | xoff += 0.1; 43 | } 44 | } 45 | 46 | // Draw every vector 47 | void show() { 48 | for (int i = 0; i < this.cols; i++) { 49 | for (int j = 0; j < this.rows; j++) { 50 | float w = width / this.cols; 51 | float h = height / this.rows; 52 | PVector v = this.field[i][j].copy(); 53 | v.setMag(w * 0.5); 54 | float x = i * w + w / 2; 55 | float y = j * h + h / 2; 56 | strokeWeight(1); 57 | line(x, y, x + v.x, y + v.y); 58 | } 59 | } 60 | } 61 | 62 | //{.code-wide} A function to return a p5.Vector based on a position 63 | PVector lookup(PVector position) { 64 | int column = constrain(floor(position.x / this.resolution), 0, this.cols - 1); 65 | int row = constrain(floor(position.y / this.resolution), 0, this.rows - 1); 66 | return this.field[column][row].copy(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /chapter5/Example_5_4_Flow_Field/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y, float ms, float mf) { 16 | this.position = new PVector(x, y); 17 | this.acceleration = new PVector(0, 0); 18 | this.velocity = new PVector(0, 0); 19 | this.r = 4; 20 | this.maxspeed = ms; 21 | this.maxforce = mf; 22 | } 23 | 24 | void run() { 25 | this.update(); 26 | this.borders(); 27 | this.show(); 28 | } 29 | 30 | // Implementing Reynolds' flow field following algorithm 31 | // http://www.red3d.com/cwr/steer/FlowFollow.html 32 | void follow(FlowField flow) { 33 | // What is the vector at that spot in the flow field? 34 | PVector desired = flow.lookup(this.position); 35 | // Scale it up by maxspeed 36 | desired.mult(this.maxspeed); 37 | // Steering is desired minus velocity 38 | PVector steer = PVector.sub(desired, this.velocity); 39 | steer.limit(this.maxforce); // Limit to maximum steering force 40 | this.applyForce(steer); 41 | } 42 | 43 | void applyForce(PVector force) { 44 | // We could add mass here if we want A = F / M 45 | this.acceleration.add(force); 46 | } 47 | 48 | // Method to update location 49 | void update() { 50 | // Update velocity 51 | this.velocity.add(this.acceleration); 52 | // Limit speed 53 | this.velocity.limit(this.maxspeed); 54 | this.position.add(this.velocity); 55 | // Reset accelerationelertion to 0 each cycle 56 | this.acceleration.mult(0); 57 | } 58 | 59 | // Wraparound 60 | void borders() { 61 | if (this.position.x < -this.r) this.position.x = width + this.r; 62 | if (this.position.y < -this.r) this.position.y = height + this.r; 63 | if (this.position.x > width + this.r) this.position.x = -this.r; 64 | if (this.position.y > height + this.r) this.position.y = -this.r; 65 | } 66 | 67 | void show() { 68 | // Draw a triangle rotated in the direction of velocity 69 | float theta = this.velocity.heading(); 70 | fill(127); 71 | stroke(0); 72 | strokeWeight(2); 73 | push(); 74 | translate(this.position.x, this.position.y); 75 | rotate(theta); 76 | beginShape(); 77 | vertex(this.r * 2, 0); 78 | vertex(-this.r * 2, -this.r); 79 | vertex(-this.r * 2, this.r); 80 | endShape(CLOSE); 81 | pop(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /chapter5/Example_5_5_Create_Path_Object/Example_5_5_Create_Path_Object.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | // Path is a just a straight line in this example 7 | // Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html 8 | 9 | // A path object (series of connected points) 10 | Path path; 11 | 12 | void setup() { 13 | size(640, 360); 14 | path = new Path(); 15 | } 16 | 17 | void draw() { 18 | background(255); 19 | path.show(); 20 | } 21 | -------------------------------------------------------------------------------- /chapter5/Example_5_5_Create_Path_Object/Path.pde: -------------------------------------------------------------------------------- 1 | class Path { 2 | float radius; 3 | PVector start; 4 | PVector end; 5 | 6 | Path() { 7 | // A path has a radius, how wide is it. 8 | //{!3} Picking some arbitrary values to initialize the path 9 | this.radius = 20; 10 | this.start = new PVector(0, height / 3); 11 | //{!2} A path is only two points, start and end. 12 | this.end = new PVector(width, (2 * height) / 3); 13 | } 14 | 15 | //{!7} Display the path. 16 | void show() { 17 | strokeWeight(this.radius * 2); 18 | stroke(0, 100); 19 | line(this.start.x, this.start.y, this.end.x, this.end.y); 20 | strokeWeight(1); 21 | stroke(0); 22 | line(this.start.x, this.start.y, this.end.x, this.end.y); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /chapter5/Example_5_6_Simple_Path_Following/Example_5_6_Simple_Path_Following.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | // Path is a just a straight line in this example 7 | // Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html 8 | 9 | // Using this variable to decide whether to draw all the stuff 10 | boolean debug = true; 11 | 12 | // A path object (series of connected points) 13 | Path path; 14 | 15 | // Two vehicles 16 | Vehicle vehicle1, vehicle2; 17 | 18 | void setup() { 19 | println("Hit space bar to toggle debugging lines."); 20 | 21 | size(640, 360); 22 | path = new Path(); 23 | 24 | // Each vehicle has different maxspeed and maxforce for demo purposes 25 | vehicle1 = new Vehicle(0, height / 2, 2, 0.02); 26 | vehicle2 = new Vehicle(0, height / 2, 3, 0.05); 27 | } 28 | 29 | void draw() { 30 | background(255); 31 | // Display the path 32 | path.show(); 33 | // The boids follow the path 34 | vehicle1.follow(path); 35 | vehicle2.follow(path); 36 | // Call the generic run method (update, borders, display, etc.) 37 | vehicle1.run(); 38 | vehicle2.run(); 39 | 40 | // Check if it gets to the end of the path since it's not a loop 41 | vehicle1.borders(path); 42 | vehicle2.borders(path); 43 | } 44 | 45 | void keyPressed() { 46 | if (key == ' ') { 47 | debug = !debug; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /chapter5/Example_5_6_Simple_Path_Following/Path.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | 7 | class Path { 8 | float radius; 9 | PVector start; 10 | PVector end; 11 | 12 | Path() { 13 | // A path has a radius, i.e how far is it ok for the boid to wander off 14 | this.radius = 20; 15 | // A Path is line between two points (p5.Vector objects) 16 | this.start = new PVector(0, height / 3); 17 | this.end = new PVector(width, 2 * height / 3); 18 | } 19 | 20 | // Draw the path 21 | void show() { 22 | 23 | strokeWeight(this.radius * 2); 24 | stroke(0, 50); 25 | line(this.start.x, this.start.y, this.end.x, this.end.y); 26 | 27 | strokeWeight(1); 28 | stroke(0); 29 | line(this.start.x, this.start.y, this.end.x, this.end.y); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /chapter5/Example_5_6_Simple_Path_Following/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y, float maxspeed, float maxforce) { 16 | this.position = new PVector(x, y); 17 | this.acceleration = new PVector(0, 0); 18 | this.velocity = new PVector(2, 0); 19 | this.r = 4; 20 | this.maxspeed = maxspeed; 21 | this.maxforce = maxforce; 22 | } 23 | 24 | void run() { 25 | this.update(); 26 | this.show(); 27 | } 28 | 29 | // This function implements Craig Reynolds' path following algorithm 30 | // http://www.red3d.com/cwr/steer/PathFollow.html 31 | void follow(Path path) { 32 | //{!3} Step 1: Predict the vehicles future position. 33 | PVector future = this.velocity.copy(); 34 | future.setMag(25); 35 | future.add(this.position); 36 | 37 | //{!1} Step 2: Find the normal point along the path. 38 | PVector normalPoint = getNormalPoint(future, path.start, path.end); 39 | 40 | //{!3} Step 3: Move a little further along the path and set a target. 41 | PVector b = PVector.sub(path.end, path.start); 42 | b.setMag(25); 43 | PVector target = PVector.add(normalPoint, b); 44 | 45 | //{!5} Step 4: If we are off the path, 46 | // seek that target in order to stay on the path. 47 | float distance = PVector.dist(normalPoint, future); 48 | if (distance > path.radius) { 49 | this.seek(target); 50 | } 51 | 52 | // Draw the debugging stuff 53 | if (debug) { 54 | fill(127); 55 | stroke(0); 56 | line(this.position.x, this.position.y, future.x, future.y); 57 | ellipse(future.x, future.y, 4, 4); 58 | 59 | // Draw normal location 60 | fill(127); 61 | stroke(0); 62 | line(future.x, future.y, normalPoint.x, normalPoint.y); 63 | ellipse(normalPoint.x, normalPoint.y, 4, 4); 64 | stroke(0); 65 | if (distance > path.radius) fill(255, 0, 0); 66 | noStroke(); 67 | ellipse(target.x + b.x, target.y + b.y, 8, 8); 68 | } 69 | } 70 | 71 | void applyForce(PVector force) { 72 | // We could add mass here if we want A = F / M 73 | this.acceleration.add(force); 74 | } 75 | 76 | // A method that calculates and applies a steering force towards a target 77 | // STEER = DESIRED MINUS VELOCITY 78 | void seek(PVector target) { 79 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the position to the target 80 | 81 | // If the magnitude of desired equals 0, skip out of here 82 | // (We could optimize this to check if x and y are 0 to avoid mag() square root 83 | if (desired.mag() == 0) return; 84 | 85 | // Normalize desired and scale to maximum speed 86 | desired.normalize(); 87 | desired.mult(this.maxspeed); 88 | // Steering = Desired minus Velocity 89 | PVector steer = PVector.sub(desired, this.velocity); 90 | steer.limit(this.maxforce); // Limit to maximum steering force 91 | 92 | this.applyForce(steer); 93 | } 94 | 95 | // Method to update position 96 | void update() { 97 | // Update velocity 98 | this.velocity.add(this.acceleration); 99 | // Limit speed 100 | this.velocity.limit(this.maxspeed); 101 | this.position.add(this.velocity); 102 | // Reset accelerationelertion to 0 each cycle 103 | this.acceleration.mult(0); 104 | } 105 | 106 | // Wraparound 107 | void borders(Path p) { 108 | if (this.position.x > p.end.x + this.r) { 109 | this.position.x = p.start.x - this.r; 110 | this.position.y = p.start.y + (this.position.y - p.end.y); 111 | } 112 | } 113 | 114 | void show() { 115 | // Draw a triangle rotated in the direction of velocity 116 | float theta = this.velocity.heading(); 117 | fill(127); 118 | stroke(0); 119 | strokeWeight(2); 120 | push(); 121 | translate(this.position.x, this.position.y); 122 | rotate(theta); 123 | beginShape(); 124 | vertex(this.r * 2, 0); 125 | vertex(-this.r * 2, -this.r); 126 | vertex(-this.r * 2, this.r); 127 | endShape(CLOSE); 128 | pop(); 129 | } 130 | } 131 | 132 | // A function to get the normal point from position to a line segment (a-b) 133 | // This function could be optimized to make fewer new Vector objects 134 | PVector getNormalPoint(PVector position, PVector a, PVector b) { 135 | // Vector that points from a to position 136 | PVector vectorA = PVector.sub(position, a); 137 | // Vector that points from a to b 138 | PVector vectorB = PVector.sub(b, a); 139 | 140 | // Using the dot product for scalar projection 141 | vectorB.normalize(); 142 | vectorB.mult(vectorA.dot(vectorB)); 143 | //{!1} Finding the normal point along the line segment 144 | PVector normalPoint = PVector.add(a, vectorB); 145 | 146 | return normalPoint; 147 | } 148 | -------------------------------------------------------------------------------- /chapter5/Example_5_7_Multiple_Segments/Example_5_7_Multiple_Segments.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | // Path is a just a straight line in this example 7 | // Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html 8 | 9 | // A path object (series of connected points) 10 | Path path; 11 | 12 | void setup() { 13 | size(640, 360); 14 | path = new Path(); 15 | path.addPoint(-20, height / 2); 16 | path.addPoint(100, 50); 17 | path.addPoint(400, 200); 18 | path.addPoint(width + 20, height / 2); 19 | } 20 | 21 | void draw() { 22 | background(255); 23 | // Display the path 24 | path.show(); 25 | } 26 | -------------------------------------------------------------------------------- /chapter5/Example_5_7_Multiple_Segments/Path.pde: -------------------------------------------------------------------------------- 1 | class Path { 2 | float radius; 3 | ArrayList points; 4 | 5 | Path() { 6 | this.radius = 20; 7 | // create empty ArrayList that will store PVector objects 8 | this.points = new ArrayList(); 9 | } 10 | 11 | //{!4} This method allows us to add points to the path. 12 | void addPoint(float x, float y) { 13 | PVector pathPoint = new PVector(x, y); 14 | this.points.add(pathPoint); 15 | } 16 | 17 | void show() { 18 | //{!8} Draw a thicker gray line for the path radius. 19 | stroke(200); 20 | strokeWeight(this.radius * 2); 21 | noFill(); 22 | beginShape(); 23 | for (PVector pathPoint : this.points) { 24 | vertex(pathPoint.x, pathPoint.y); 25 | } 26 | endShape(); 27 | 28 | //{!7} Draw a thin line for the path center. 29 | stroke(0); 30 | strokeWeight(1); 31 | beginShape(); 32 | for (PVector pathPoint : this.points) { 33 | vertex(pathPoint.x, pathPoint.y); 34 | } 35 | endShape(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter5/Example_5_8_Path_Following/Example_5_8_Path_Following.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | // Path is a just a straight line in this example 7 | // Via Reynolds: // http://www.red3d.com/cwr/steer/PathFollow.html 8 | 9 | // Using this variable to decide whether to draw all the stuff 10 | boolean debug = true; 11 | 12 | // A path object (series of connected points) 13 | Path path; 14 | 15 | // Two vehicles 16 | Vehicle car1; 17 | Vehicle car2; 18 | 19 | void setup() { 20 | println("Hit space bar to toggle debugging lines.
Click the mouse to generate a new path."); 21 | 22 | size(640, 360); 23 | newPath(); 24 | 25 | // Each vehicle has different maxspeed and maxforce for demo purposes 26 | car1 = new Vehicle(0, height / 2, 2, 0.04); 27 | car2 = new Vehicle(0, height / 2, 3, 0.1); 28 | } 29 | 30 | void draw() { 31 | background(255); 32 | // Display the path 33 | path.show(); 34 | // The boids follow the path 35 | car1.follow(path); 36 | car2.follow(path); 37 | // Call the generic run method (update, borders, display, etc.) 38 | car1.run(); 39 | car2.run(); 40 | 41 | // Check if it gets to the end of the path since it's not a loop 42 | car1.borders(path); 43 | car2.borders(path); 44 | 45 | } 46 | 47 | void newPath() { 48 | // A path is a series of connected points 49 | // A more sophisticated path might be a curve 50 | path = new Path(); 51 | path.addPoint(-20, height / 2); 52 | path.addPoint(random(0, width / 2), random(0, height)); 53 | path.addPoint(random(width / 2, width), random(0, height)); 54 | path.addPoint(width + 20, height / 2); 55 | } 56 | 57 | void keyPressed() { 58 | if (key == ' ') { 59 | debug = !debug; 60 | } 61 | } 62 | 63 | void mousePressed() { 64 | newPath(); 65 | } 66 | -------------------------------------------------------------------------------- /chapter5/Example_5_8_Path_Following/Path.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Path Following 6 | 7 | 8 | class Path { 9 | float radius; 10 | ArrayList points; 11 | 12 | Path() { 13 | // A path has a radius, i.e how far is it ok for the vehicle to wander off 14 | this.radius = 20; 15 | // A Path is an array of points (PVector objects) 16 | this.points = new ArrayList(); 17 | } 18 | 19 | // Add a point to the path 20 | void addPoint(float x, float y) { 21 | PVector point = new PVector(x, y); 22 | this.points.add(point); 23 | } 24 | 25 | PVector getStart() { 26 | return this.points.get(0); 27 | } 28 | 29 | PVector getEnd() { 30 | return this.points.get(this.points.size() - 1); 31 | } 32 | 33 | 34 | // Draw the path 35 | void show() { 36 | // Draw thick line for radius 37 | stroke(200); 38 | strokeWeight(this.radius * 2); 39 | noFill(); 40 | beginShape(); 41 | for (PVector pathPoint : this.points) { 42 | vertex(pathPoint.x, pathPoint.y); 43 | } 44 | endShape(); 45 | // Draw thin line for center of path 46 | stroke(0); 47 | strokeWeight(1); 48 | noFill(); 49 | beginShape(); 50 | for (PVector pathPoint : this.points) { 51 | vertex(pathPoint.x, pathPoint.y); 52 | } 53 | endShape(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /chapter5/Example_5_8_Path_Following/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // The "Vehicle" class 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x, float y, float ms, float mf) { 16 | this.position = new PVector(x, y); 17 | this.acceleration = new PVector(0, 0); 18 | this.velocity = new PVector(2, 0); 19 | this.r = 4; 20 | this.maxspeed = ms; // || 4; 21 | this.maxforce = mf; // || 0.1; 22 | } 23 | 24 | void run() { 25 | this.update(); 26 | this.show(); 27 | } 28 | 29 | // This function implements Craig Reynolds' path following algorithm 30 | // http://www.red3d.com/cwr/steer/PathFollow.html 31 | void follow(Path path) { 32 | // Predict location 50 (arbitrary choice) frames ahead 33 | // This could be based on speed 34 | PVector future = this.velocity.copy(); 35 | future.setMag(50); 36 | future.add(this.position); 37 | 38 | // Now we must find the normal to the path from the predicted location 39 | // We look at the normal for each line segment and pick out the closest one 40 | PVector target = null; 41 | PVector normal = null; 42 | float worldRecord = Float.MAX_VALUE; // Start with a very high record distance that can easily be beaten 43 | 44 | // Loop through all points of the path 45 | for (int i = 0; i < path.points.size() - 1; i++) { 46 | // Look at a line segment 47 | PVector a = path.points.get(i); 48 | PVector b = path.points.get(i + 1); 49 | 50 | // Get the normal point to that line 51 | PVector normalPoint = getNormalPoint(future, a, b); 52 | // This only works because we know our path goes from left to right 53 | // We could have a more sophisticated test to tell if the point is in the line segment or not 54 | if (normalPoint.x < a.x || normalPoint.x > b.x) { 55 | // This is something of a hacky solution, but if it's not within the line segment 56 | // consider the normal to just be the end of the line segment (point b) 57 | normalPoint = b.copy(); 58 | } 59 | 60 | // How far away are we from the path? 61 | float distance = PVector.dist(future, normalPoint); 62 | // Did we beat the record and find the closest line segment? 63 | if (distance < worldRecord) { 64 | worldRecord = distance; 65 | // If so the target we want to steer towards is the normal 66 | normal = normalPoint; 67 | target = normalPoint.copy(); 68 | 69 | // Look at the direction of the line segment so we can seek a little bit ahead of the normal 70 | PVector dir = PVector.sub(b, a); 71 | // This is an oversimplification 72 | // Should be based on distance to path & velocity 73 | dir.setMag(10); 74 | target.add(dir); 75 | } 76 | } 77 | 78 | // Only if the distance is greater than the path's radius do we bother to steer 79 | if (worldRecord > path.radius && target != null) { 80 | this.seek(target); 81 | } 82 | 83 | // Draw the debugging stuff 84 | if (debug) { 85 | // Draw predicted future location 86 | stroke(0); 87 | fill(127); 88 | line(this.position.x, this.position.y, future.x, future.y); 89 | ellipse(future.x, future.y, 4, 4); 90 | 91 | // Draw normal location 92 | if(normal!= null){ 93 | stroke(0); 94 | fill(127); 95 | circle(normal.x, normal.y, 4); 96 | // Draw actual target (red if steering towards it) 97 | line(future.x, future.y, normal.x, normal.y); 98 | if (worldRecord > path.radius) fill(255, 0, 0); 99 | noStroke(); 100 | if(target != null){ 101 | circle(target.x, target.y, 8); 102 | } 103 | } 104 | } 105 | } 106 | 107 | void applyForce(PVector force) { 108 | // We could add mass here if we want A = F / M 109 | this.acceleration.add(force); 110 | } 111 | 112 | // A method that calculates and applies a steering force towards a target 113 | // STEER = DESIRED MINUS VELOCITY 114 | void seek(PVector target) { 115 | PVector desired = PVector.sub(target, this.position); // A vector pointing from the position to the target 116 | 117 | // If the magnitude of desired equals 0, skip out of here 118 | // (We could optimize this to check if x and y are 0 to avoid mag() square root 119 | if (desired.mag() == 0) return; 120 | 121 | // Normalize desired and scale to maximum speed 122 | desired.normalize(); 123 | desired.mult(this.maxspeed); 124 | // Steering = Desired minus Velocity 125 | PVector steer = PVector.sub(desired, this.velocity); 126 | steer.limit(this.maxforce); // Limit to maximum steering force 127 | 128 | this.applyForce(steer); 129 | } 130 | 131 | // Method to update position 132 | void update() { 133 | // Update velocity 134 | this.velocity.add(this.acceleration); 135 | // Limit speed 136 | this.velocity.limit(this.maxspeed); 137 | this.position.add(this.velocity); 138 | // Reset accelerationelertion to 0 each cycle 139 | this.acceleration.mult(0); 140 | } 141 | 142 | // Wraparound 143 | void borders(Path path) { 144 | if (this.position.x > path.getEnd().x + this.r) { 145 | this.position.x = path.getStart().x - this.r; 146 | this.position.y = path.getStart().y + (this.position.y - path.getEnd().y); 147 | } 148 | } 149 | 150 | void show() { 151 | // Draw a triangle rotated in the direction of velocity 152 | float theta = this.velocity.heading(); 153 | fill(127); 154 | stroke(0); 155 | strokeWeight(2); 156 | push(); 157 | translate(this.position.x, this.position.y); 158 | rotate(theta); 159 | beginShape(); 160 | vertex(this.r * 2, 0); 161 | vertex(-this.r * 2, -this.r); 162 | vertex(-this.r * 2, this.r); 163 | endShape(CLOSE); 164 | pop(); 165 | } 166 | } 167 | 168 | // A function to get the normal point from a point (p) to a line segment (a-b) 169 | // This function could be optimized to make fewer new Vector objects 170 | PVector getNormalPoint(PVector p, PVector a, PVector b) { 171 | // Vector from a to p 172 | PVector ap = PVector.sub(p, a); 173 | // Vector from a to b 174 | PVector ab = PVector.sub(b, a); 175 | ab.normalize(); // Normalize the line 176 | // Project vector "diff" onto line by using the dot product 177 | ab.mult(ap.dot(ab)); 178 | PVector normalPoint = PVector.add(a, ab); 179 | return normalPoint; 180 | } 181 | -------------------------------------------------------------------------------- /chapter5/Example_5_9_Separation/Example_5_9_Separation.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Separation 6 | // Via Reynolds: http://www.red3d.com/cwr/steer/ 7 | 8 | // A list of vehicles 9 | ArrayList vehicles; 10 | 11 | void setup() { 12 | size(640, 360); 13 | 14 | vehicles = new ArrayList(); 15 | 16 | // We are now making random vehicles and storing them in an array 17 | for (int i = 0; i < 25; i++) { 18 | vehicles.add(new Vehicle(random(width), random(height))); 19 | } 20 | } 21 | 22 | void draw() { 23 | background(255); 24 | 25 | 26 | for (Vehicle v : vehicles) { 27 | v.separate(vehicles); 28 | v.update(); 29 | v.borders(); 30 | v.show(); 31 | } 32 | 33 | } 34 | 35 | 36 | void mouseDragged() { 37 | vehicles.add(new Vehicle(mouseX, mouseY)); 38 | } 39 | -------------------------------------------------------------------------------- /chapter5/Example_5_9_Separation/Vehicle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Vehicle object 6 | 7 | class Vehicle { 8 | PVector position; 9 | PVector velocity; 10 | PVector acceleration; 11 | float r; 12 | float maxspeed; 13 | float maxforce; 14 | 15 | Vehicle(float x,float y) { 16 | // All the usual stuff 17 | this.position = new PVector(x, y); 18 | this.r = 12; 19 | this.maxspeed = 3; // Maximum speed 20 | this.maxforce = 0.2; // Maximum steering force 21 | this.acceleration = new PVector(0, 0); 22 | this.velocity = new PVector(0, 0); 23 | } 24 | 25 | void applyForce(PVector force) { 26 | // We could add mass here if we want A = F / M 27 | this.acceleration.add(force); 28 | } 29 | 30 | // Separation 31 | // Method checks for nearby vehicles and steers away 32 | void separate(ArrayList vehicles) { 33 | //{!1 .bold} Note how the desired separation is based 34 | // on the Vehicles size. 35 | float desiredSeparation = this.r * 2; 36 | PVector sum = new PVector(); 37 | int count = 0; 38 | for (Vehicle other : vehicles) { 39 | float d = PVector.dist(this.position, other.position); 40 | if (this != other && d < desiredSeparation) { 41 | PVector diff = PVector.sub(this.position, other.position); 42 | //{!1 .bold} What is the magnitude of the p5.Vector 43 | // pointing away from the other vehicle? 44 | // The closer it is, the more the vehicle should flee. 45 | // The farther, the less. So the magnitude is set 46 | // to be inversely proportional to the distance. 47 | diff.setMag(1 / d); 48 | sum.add(diff); 49 | count++; 50 | } 51 | } 52 | if (count > 0) { 53 | sum.setMag(this.maxspeed); 54 | PVector steer = PVector.sub(sum, this.velocity); 55 | steer.limit(this.maxforce); 56 | this.applyForce(steer); 57 | } 58 | } 59 | 60 | // Method to update location 61 | void update() { 62 | // Update velocity 63 | this.velocity.add(this.acceleration); 64 | // Limit speed 65 | this.velocity.limit(this.maxspeed); 66 | this.position.add(this.velocity); 67 | // Reset accelertion to 0 each cycle 68 | this.acceleration.mult(0); 69 | } 70 | 71 | void show() { 72 | fill(127); 73 | stroke(0); 74 | strokeWeight(2); 75 | push(); 76 | translate(this.position.x, this.position.y); 77 | circle(0, 0, this.r); 78 | pop(); 79 | } 80 | 81 | // Wraparound 82 | void borders() { 83 | if (this.position.x < -this.r) this.position.x = width + this.r; 84 | if (this.position.y < -this.r) this.position.y = height + this.r; 85 | if (this.position.x > width + this.r) this.position.x = -this.r; 86 | if (this.position.y > height + this.r) this.position.y = -this.r; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /chapter7/Example_7_1_Wolfram_Elementary_Cellular_Automata/Example_7_1_Wolfram_Elementary_Cellular_Automata.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 7-1: Wolfram Elementary Cellular Automata 6 | 7 | // Array of cells 8 | int[] cells; 9 | // Starting at generation 0 10 | int generation = 0; 11 | // Cell size 12 | int w = 10; 13 | 14 | // Rule 90 15 | int[] ruleset = {0, 1, 0, 1, 1, 0, 1, 0}; 16 | 17 | void setup() { 18 | size(640, 320); 19 | background(255); 20 | // An array of 0s and 1s 21 | cells = new int[(int) Math.floor(width / w)]; 22 | for (int i = 0; i < cells.length; i++) { 23 | cells[i] = 0; 24 | } 25 | cells[floor(cells.length / 2)] = 1; 26 | } 27 | 28 | void draw() { 29 | for (int i = 1; i < cells.length - 1; i++) { 30 | // Only drawing the cell's with a state of 1 31 | if (cells[i] == 1) { 32 | fill(0); 33 | // Set the y-position according to the generation. 34 | square(i * w, generation * w, w); 35 | } 36 | } 37 | 38 | // Compute the next generation. 39 | int[] nextgen = cells.clone(); 40 | for (int i = 1; i < cells.length - 1; i++) { 41 | int left = cells[i - 1]; 42 | int me = cells[i]; 43 | int right = cells[i + 1]; 44 | nextgen[i] = rules(left, me, right); 45 | } 46 | cells = nextgen; 47 | 48 | // The next generation 49 | generation++; 50 | 51 | // Stopping when it gets to the bottom of the canvas 52 | if (generation * w > height) { 53 | noLoop(); 54 | } 55 | } 56 | 57 | // Look up a new state from the ruleset. 58 | int rules(int a, int b, int c) { 59 | String s = "" + a + b + c; 60 | int index = Integer.parseInt(s, 2); 61 | return ruleset[7 - index]; 62 | } 63 | -------------------------------------------------------------------------------- /chapter7/Example_7_2_Game_of_Life/Example_7_2_Game_of_Life.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 7-2: Game of Life 6 | 7 | int w = 8; 8 | int columns, rows; 9 | int[][] board; 10 | 11 | void setup() { 12 | size(640, 360); 13 | columns = width / w; 14 | rows = height / w; 15 | board = create2DArray(columns, rows); 16 | for (int i = 1; i < columns - 1; i++) { 17 | for (int j = 1; j < rows - 1; j++) { 18 | board[i][j] = (int) Math.floor(random(2)); 19 | } 20 | } 21 | } 22 | 23 | void draw() { 24 | // The next board 25 | int[][] next = create2DArray(columns, rows); 26 | 27 | // Looping but skipping the edge cells 28 | for (int i = 1; i < columns - 1; i++) { 29 | for (int j = 1; j < rows - 1; j++) { 30 | // Add up all the neighbor states to 31 | // calculate the number of live neighbors. 32 | int neighborSum = 0; 33 | for (int k = -1; k <= 1; k++) { 34 | for (int l = -1; l <= 1; l++) { 35 | neighborSum += board[i + k][j + l]; 36 | } 37 | } 38 | // Correct by subtracting the cell state itself. 39 | neighborSum -= board[i][j]; 40 | 41 | // The rules of life! 42 | if (board[i][j] == 1 && neighborSum < 2) next[i][j] = 0; 43 | else if (board[i][j] == 1 && neighborSum > 3) next[i][j] = 0; 44 | else if (board[i][j] == 0 && neighborSum == 3) next[i][j] = 1; 45 | else next[i][j] = board[i][j]; 46 | } 47 | } 48 | 49 | for (int i = 0; i < columns; i++) { 50 | for (int j = 0; j < rows; j++) { 51 | // evaluates to 255 when state is 0 and 0 when state is 1 52 | fill(255 - board[i][j] * 255); 53 | stroke(0); 54 | square(i * w, j * w, w); 55 | } 56 | } 57 | 58 | board = next; 59 | } 60 | 61 | int[][] create2DArray(int columns, int rows) { 62 | int[][] arr = new int[columns][rows]; 63 | for (int i = 0; i < columns; i++) { 64 | arr[i] = new int[rows]; 65 | for (int j = 0; j < rows; j++) { 66 | arr[i][j] = 0; 67 | } 68 | } 69 | return arr; 70 | } 71 | -------------------------------------------------------------------------------- /chapter7/Example_7_3_Object_Oriented_Game_of_Life/Cell.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Cell { 6 | int state, previous, x, y, w; 7 | 8 | Cell(int state, int x, int y, int w) { 9 | // Cell State -> 1 = Alive, 0 = Not Alive 10 | this.state = state; 11 | this.previous = this.state; 12 | 13 | // position and size 14 | this.x = x; 15 | this.y = y; 16 | this.w = w; 17 | } 18 | 19 | void show() { 20 | stroke(0); 21 | // If the cell is born, color it blue! 22 | if (this.previous == 0 && this.state == 1) { 23 | fill(0, 0, 255); 24 | } else if (this.state == 1) { 25 | fill(0); 26 | // If the cell dies, color it red! 27 | } else if (this.previous == 1 && this.state == 0) { 28 | fill(255, 0, 0); 29 | } else { 30 | fill(255); 31 | } 32 | square(this.x, this.y, this.w); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /chapter7/Example_7_3_Object_Oriented_Game_of_Life/Example_7_3_Object_Oriented_Game_of_Life.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Example 7-3: Object-Oriented Game of Life 6 | 7 | int w = 8; 8 | int columns, rows; 9 | Cell[][] board; 10 | 11 | void setup() { 12 | size(640, 360); 13 | columns = width / w; 14 | rows = height / w; 15 | board = create2DArray(columns, rows); 16 | for (int i = 1; i < columns - 1; i++) { 17 | for (int j = 1; j < rows - 1; j++) { 18 | board[i][j] = new Cell((int) Math.floor(random(2)), i * w, j * w, w); 19 | } 20 | } 21 | } 22 | 23 | void draw() { 24 | // Looping but skipping the edge cells 25 | for (int x = 1; x < columns - 1; x++) { 26 | for (int y = 1; y < rows - 1; y++) { 27 | int neighborSum = 0; 28 | for (int i = -1; i <= 1; i++) { 29 | for (int j = -1; j <= 1; j++) { 30 | // Use the previous state when counting neighbors 31 | neighborSum += board[x + i][y + j].previous; 32 | } 33 | } 34 | neighborSum -= board[x][y].previous; 35 | 36 | // Set the cell's new state based on the neighbor count 37 | if (board[x][y].state == 1 && neighborSum < 2) { 38 | board[x][y].state = 0; 39 | } else if (board[x][y].state == 1 && neighborSum > 3) { 40 | board[x][y].state = 0; 41 | } else if (board[x][y].state == 0 && neighborSum == 3) { 42 | board[x][y].state = 1; 43 | } 44 | // else do nothing! 45 | } 46 | } 47 | 48 | for (int i = 0; i < columns; i++) { 49 | for (int j = 0; j < rows; j++) { 50 | // evaluates to 255 when state is 0 and 0 when state is 1 51 | board[i][j].show(); 52 | 53 | // save the previous state before the next generation! 54 | board[i][j].previous = board[i][j].state; 55 | } 56 | } 57 | } 58 | 59 | Cell[][] create2DArray(int columns, int rows) { 60 | Cell[][] arr = new Cell[columns][rows]; 61 | for (int i = 0; i < columns; i++) { 62 | arr[i] = new Cell[rows]; 63 | for (int j = 0; j < rows; j++) { 64 | arr[i][j] = new Cell(0, i * w, j * w, w); 65 | } 66 | } 67 | return arr; 68 | } 69 | -------------------------------------------------------------------------------- /chapter8/Example_8_1_Recursive_Circles_Once/Example_8_1_Recursive_Circles_Once.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Recursion 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | drawCircles(width / 2, height / 2, width / 2); 14 | noLoop(); 15 | } 16 | 17 | // Very simple function that draws one circle 18 | // and recursively calls itself 19 | void drawCircles(int x, int y, float r) { 20 | stroke(0); 21 | strokeWeight(2); 22 | circle(x, y, r * 2); 23 | // Exit condition, stop when radius is too small 24 | if (r > 4) { 25 | r *= 0.75; 26 | // Call the function inside the function! (recursion!) 27 | drawCircles(x, y, r); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter8/Example_8_2_Recursive_Circles_Twice/Example_8_2_Recursive_Circles_Twice.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Recursion 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | drawCircles(width / 2, height / 2, 320); 14 | noLoop(); 15 | } 16 | 17 | void drawCircles(float x, int y, float radius) { 18 | stroke(0); 19 | strokeWeight(2); 20 | noFill(); 21 | circle(x, y, radius * 2); 22 | if (radius > 4) { 23 | // drawCircles() calls itself twice. For every circle, a smaller circle is drawn to the left and the right. 24 | drawCircles(x + radius / 2, y, radius / 2); 25 | drawCircles(x - radius / 2, y, radius / 2); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter8/Example_8_3_Recursive_Circles_Four_Times/Example_8_3_Recursive_Circles_Four_Times.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple Recursion 6 | 7 | void setup() { 8 | size(640, 360); 9 | } 10 | 11 | void draw() { 12 | background(255); 13 | drawCircles(width / 2, height / 2, 320); 14 | noLoop(); 15 | } 16 | 17 | void drawCircles(float x, float y, float radius) { 18 | stroke(0); 19 | noFill(); 20 | circle(x, y, radius * 2); 21 | if (radius > 16) { 22 | //{!4} drawCircle() calls itself four times. 23 | drawCircles(x + radius / 2, y, radius / 2); 24 | drawCircles(x - radius / 2, y, radius / 2); 25 | drawCircles(x, y + radius / 2, radius / 2); 26 | drawCircles(x, y - radius / 2, radius / 2); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /chapter8/Example_8_4_Cantor_Set/Example_8_4_Cantor_Set.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Cantor Set 6 | // Renders a simple fractal, the Cantor Set 7 | 8 | void setup() { 9 | size(640, 120); 10 | background(255); 11 | 12 | // Call the recursive function 13 | strokeWeight(2); 14 | cantor(10, 10, 620); 15 | } 16 | 17 | void draw() { 18 | // No need to loop 19 | noLoop(); 20 | } 21 | 22 | void cantor(float x, int y, float length) { 23 | //{!1} Stop at 1 pixel! 24 | if (length > 1) { 25 | line(x, y, x + length, y); 26 | cantor(x, y + 20, length / 3); 27 | cantor(x + (2 * length) / 3, y + 20, length / 3); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /chapter8/Example_8_5_Koch_Curve/Example_8_5_Koch_Curve.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Koch Curve 6 | // Renders a simple fractal, the Koch snowflake 7 | // Each recursive level drawn in sequence 8 | 9 | import java.util.List; 10 | 11 | // An array for all the line segments 12 | List segments = new ArrayList(); 13 | 14 | void setup() { 15 | size(640, 360); 16 | // Left side of canvas 17 | PVector start = new PVector(0, 300); 18 | // Right side of canvas 19 | PVector end = new PVector(width, 300); 20 | 21 | //{!1} The first KochLine object 22 | segments.add(new KochLine(start, end)); 23 | 24 | //{!3} Apply the Koch rules five times. 25 | for (int i = 0; i < 5; i++) { 26 | generate(); 27 | } 28 | } 29 | 30 | void draw() { 31 | background(255); 32 | for (KochLine segment : segments) { 33 | segment.show(); 34 | } 35 | noLoop(); 36 | } 37 | 38 | void generate() { 39 | // Create the next array 40 | List next = new ArrayList(); 41 | // For every segment 42 | for (KochLine segment : segments) { 43 | // Calculate 5 koch PVectors (done for us by the line object) 44 | PVector[] kochPoints = segment.kochPoints(); 45 | PVector a = kochPoints[0]; 46 | PVector b = kochPoints[1]; 47 | PVector c = kochPoints[2]; 48 | PVector d = kochPoints[3]; 49 | PVector e = kochPoints[4]; 50 | // Make line segments between all the vectors and add them 51 | next.add(new KochLine(a, b)); 52 | next.add(new KochLine(b, c)); 53 | next.add(new KochLine(c, d)); 54 | next.add(new KochLine(d, e)); 55 | } 56 | // The next segments! 57 | segments = next; 58 | } 59 | -------------------------------------------------------------------------------- /chapter8/Example_8_5_Koch_Curve/KochLine.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Koch Curve 6 | // A class to describe one line segment in the fractal 7 | // Includes methods to calculate midPVectors along the line according to the Koch algorithm 8 | 9 | class KochLine { 10 | // Two PVectors, 11 | // start is the "left" PVector and 12 | // end is the "right PVector 13 | PVector start, end; 14 | 15 | KochLine(PVector a, PVector b) { 16 | this.start = a.copy(); 17 | this.end = b.copy(); 18 | } 19 | 20 | void show() { 21 | stroke(0); 22 | strokeWeight(2); 23 | line(this.start.x, this.start.y, this.end.x, this.end.y); 24 | } 25 | 26 | PVector[] kochPoints() { 27 | // Just the first point! 28 | PVector a = this.start.copy(); 29 | // Just the last point! 30 | PVector e = this.end.copy(); 31 | 32 | // A vector pointing in the direction, 1/3rd the length 33 | PVector v = PVector.sub(this.end, this.start); 34 | v.mult(1 / 3f); 35 | 36 | // b is just 1/3 of the way 37 | PVector b = PVector.add(a, v); 38 | // d is just another 1/3 of the way 39 | PVector d = PVector.add(b, v); 40 | 41 | //{!1} Rotate by -PI/3 radians (negative angle so it rotates "up"). 42 | v.rotate(-PI / 3); 43 | // Move along 44 | PVector c = PVector.add(b, v); 45 | 46 | // Return all five points in an array 47 | PVector[] points = {a, b, c, d, e}; 48 | return points; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter8/Example_8_6_Recursive_Tree/Example_8_6_Recursive_Tree.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Recursive Tree 6 | // Renders a simple tree-like structure via recursion 7 | // Branching angle calculated as a function of horizontal mouse position 8 | 9 | float angle; 10 | 11 | void setup() { 12 | size(640, 360); 13 | } 14 | 15 | void draw() { 16 | background(255); 17 | // Mapping the angle between 0 to 90° (HALF_PI) according to mouseX 18 | angle = map(mouseX, 0, width, 0, HALF_PI); 19 | 20 | // Start the tree from the bottom of the canvas 21 | translate(width / 2, height); 22 | stroke(0); 23 | strokeWeight(2); 24 | branch(100); 25 | } 26 | 27 | //{!1} Each branch now receives its length as an argument. 28 | void branch(float len) { 29 | line(0, 0, 0, -len); 30 | translate(0, -len); 31 | 32 | //{!1} Each branch's length shrinks by two-thirds. 33 | len *= 0.67; 34 | 35 | if (len > 2) { 36 | push(); 37 | rotate(angle); 38 | //{!1} Subsequent calls to branch() include the length argument. 39 | branch(len); 40 | pop(); 41 | 42 | push(); 43 | rotate(-angle); 44 | branch(len); 45 | pop(); 46 | } 47 | } -------------------------------------------------------------------------------- /chapter8/Example_8_7_Stochastic_Tree/Example_8_7_Stochastic_Tree.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Stochastic Tree 6 | // Renders a simple tree-like structure via recursion 7 | // Angles and number of branches are random 8 | 9 | void setup() { 10 | size(640, 360); 11 | frameRate(1); 12 | } 13 | 14 | void draw() { 15 | background(255); 16 | 17 | stroke(0); 18 | push(); 19 | // Start the tree from the bottom of the screen 20 | translate(width / 2, height); 21 | strokeWeight(2); 22 | // Start the recursive branching! 23 | branch(100); 24 | pop(); 25 | } 26 | 27 | void branch(float length) { 28 | // Draw the actual branch 29 | line(0, 0, 0, -length); 30 | // Move along to end 31 | translate(0, -length); 32 | 33 | // Each branch will be 2/3rds the size of the previous one 34 | length *= 0.67; 35 | 36 | // All recursive functions must have an exit condition!!!! 37 | // Here, ours is when the length of the branch is 2 pixels or less 38 | if (length > 2) { 39 | // A random number of branches 40 | int n = (int) Math.floor(random(1, 4)); 41 | for (int i = 0; i < n; i++) { 42 | // Picking a random angle 43 | float angle = random(-PI / 2, PI / 2); 44 | push(); // Save the current state of transformation (i.e. where are we now) 45 | rotate(angle); // Rotate by theta 46 | branch(length); // Ok, now call myself to branch again 47 | pop(); // Whenever we get back here, we "pop" in order to restore the previous matrix state 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /chapter8/Example_8_8_LSystem_String_Only/Example_8_8_LSystem_String_Only.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | // Simple L-system Sentence Generation 6 | 7 | //{!1} Start with an axiom. 8 | String current = "A"; 9 | PFont courier; 10 | 11 | 12 | void setup() { 13 | size(640, 160); 14 | background(255); 15 | noLoop(); 16 | courier = createFont("courier", 16); 17 | fill(0); 18 | // 9 generations 19 | for (int i = 0; i < 9; i++) { 20 | generate(); 21 | // Render text to canvas 22 | textFont(courier); 23 | text(i + ": " + current, 4, 20 + i * 16); 24 | } 25 | } 26 | 27 | void generate() { 28 | String next = ""; 29 | for (int i = 0; i < current.length(); i++) { 30 | // For every character of the current sentence 31 | char c = current.charAt(i); 32 | //{!5} Apply the production rules A->AB, B->A 33 | if (c == 'A') { 34 | next += "AB"; 35 | } else if (c == 'B') { 36 | next += "A"; 37 | } 38 | } 39 | // Save the next generation 40 | current = next; 41 | } 42 | -------------------------------------------------------------------------------- /chapter8/Example_8_9_LSystem/Example_8_9_LSystem.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | LSystem lsystem; 6 | Turtle turtle; 7 | 8 | void setup() { 9 | size(640, 360); 10 | 11 | HashMap rules = new HashMap(); 12 | rules.put('F', "FF+[+F-F-F]-[-F+F+F]"); 13 | lsystem = new LSystem("F", rules); 14 | turtle = new Turtle(6, radians(25)); 15 | 16 | for (int i = 0; i < 4; i++) { 17 | lsystem.generate(); 18 | } 19 | 20 | // Some other rules 21 | // HashMap ruleset = new HashMap(); 22 | // ruleset.put('F', "F[F]-F+F[--F]+F-F"); 23 | // lsystem = new LSystem("F-F-F-F", ruleset); 24 | // turtle = new Turtle(4, PI / 2); 25 | 26 | // HashMap ruleset = new HashMap(); 27 | // ruleset.put('F', "F--F--F--G"); 28 | // ruleset.put('G', "GG"); 29 | // lsystem = new LSystem("F--F--F", ruleset); 30 | // turtle = new Turtle(16, PI / 3); 31 | } 32 | 33 | void draw() { 34 | background(255); 35 | translate(width / 2, height); 36 | turtle.render(lsystem.sentence); 37 | noLoop(); 38 | } 39 | -------------------------------------------------------------------------------- /chapter8/Example_8_9_LSystem/LSystem.pde: -------------------------------------------------------------------------------- 1 | // Daniel Shiffman 2 | // http://natureofcode.com 3 | 4 | // An LSystem has a starting sentence 5 | // An a ruleset 6 | // Each generation recursively replaces characters in the sentence 7 | // Based on the ruleset 8 | 9 | // Construct an LSystem with a starting sentence and a ruleset 10 | class LSystem { 11 | String sentence; 12 | HashMap ruleset; 13 | 14 | LSystem(String axiom, HashMap rules) { 15 | this.sentence = axiom; // The sentence (a String) 16 | this.ruleset = rules; // The ruleset (a HashMap of Rule) 17 | } 18 | 19 | // Generate the next generation 20 | void generate() { 21 | // An empty string that we will fill 22 | String nextgen = ""; 23 | // For every character in the sentence 24 | for (int i = 0; i < this.sentence.length(); i++) { 25 | // What is the character 26 | char c = this.sentence.charAt(i); 27 | // Replace it with itself unless it matches one of our rules 28 | if (this.ruleset.get(c) != null) { 29 | nextgen += this.ruleset.get(c); 30 | } else { 31 | nextgen += c; 32 | } 33 | } 34 | // Replace sentence 35 | this.sentence = nextgen; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /chapter8/Example_8_9_LSystem/Turtle.pde: -------------------------------------------------------------------------------- 1 | // The Nature of Code 2 | // Daniel Shiffman 3 | // http://natureofcode.com 4 | 5 | class Turtle { 6 | int length; 7 | float angle; 8 | 9 | Turtle(int length, float angle) { 10 | this.length = length; 11 | this.angle = angle; 12 | } 13 | 14 | void render(String sentence) { 15 | stroke(0); 16 | for (int i = 0; i < sentence.length(); i++) { 17 | char c = sentence.charAt(i); 18 | if (c == 'F' || c == 'G') { 19 | line(0, 0, 0, -this.length); 20 | translate(0, -this.length); 21 | } else if (c == '+') { 22 | rotate(this.angle); 23 | } else if (c == '-') { 24 | rotate(-this.angle); 25 | } else if (c == '[') { 26 | push(); 27 | } else if (c == ']') { 28 | pop(); 29 | } 30 | } 31 | } 32 | } 33 | --------------------------------------------------------------------------------