├── .gitignore ├── chp05_physicslibraries ├── box2d │ ├── data │ │ └── java_args.txt │ ├── distance_joint │ │ ├── particle_system.rb │ │ ├── distance_joint.rb │ │ ├── boundary.rb │ │ ├── pair.rb │ │ └── particle.rb │ ├── mouse_joint │ │ ├── dummy_spring.rb │ │ ├── boundary.rb │ │ ├── mouse_joint.rb │ │ ├── spring.rb │ │ └── box.rb │ ├── collision_listening.rb │ ├── lib │ │ ├── custom_listener.rb │ │ ├── boundary.rb │ │ ├── box.rb │ │ └── particle.rb │ ├── revolute_joint │ │ ├── revolute_joint.rb │ │ ├── windmill.rb │ │ └── box.rb │ ├── liquidy.rb │ ├── liquid_fun_test.rb │ ├── polygons.rb │ └── bumpy_surface_noise.rb ├── toxiclibs │ ├── README.md │ ├── soft_body │ │ ├── connection.rb │ │ ├── particle.rb │ │ ├── blanket.rb │ │ └── soft_body_square_adapted.rb │ ├── attract_repel │ │ ├── attractor.rb │ │ ├── particle.rb │ │ └── attract_repel.rb │ ├── simple_spring │ │ ├── particle.rb │ │ └── simple_spring.rb │ ├── soft_string │ │ ├── particle.rb │ │ └── soft_string_pendulum.rb │ ├── force_directed_graph │ │ └── node.rb │ └── simple_cluster │ │ ├── node.rb │ │ ├── cluster.rb │ │ └── simple_cluster.rb └── CollisionsEqualMass │ ├── world.rb │ └── collisions_equal_mass.rb ├── chp10_nn ├── SimpleNetwork │ ├── library │ │ └── neural_network │ │ │ ├── neural_network.rb │ │ │ └── lib │ │ │ ├── network.rb │ │ │ ├── neuron.rb │ │ │ └── connection.rb │ ├── NOC_10_03_NetworkViz.rb │ └── NOC_10_04_NetworkAnimation.rb ├── xor │ ├── ext │ │ └── nn │ │ │ ├── OutputNeuron.java │ │ │ ├── HiddenNeuron.java │ │ │ ├── InputNeuron.java │ │ │ └── Connection.java │ ├── README.md │ ├── Rakefile │ ├── landscape.rb │ └── xor.rb └── LayeredNetwork │ ├── library │ └── neural_network │ │ ├── neural_network.rb │ │ └── lib │ │ ├── static_network.rb │ │ ├── network.rb │ │ ├── neuron.rb │ │ └── connection.rb │ ├── LayeredNetworkViz.rb │ └── Exercise_10_05_LayeredNetworkAnimation.rb ├── chp04_systems ├── NOC_4_09_AdditiveBlending │ ├── data │ │ └── texture.png │ ├── NOC_4_09_AdditiveBlending.rb │ ├── particle_system.rb │ └── particle.rb ├── NOC_4_08_ParticleSystemSmoke_b │ ├── data │ │ └── texture.png │ ├── particle.rb │ ├── particle_system.rb │ └── NOC_4_08_ParticleSystemSmoke_b.rb ├── NOC_4_03_ParticleSystemClass │ ├── NOC_4_03_ParticleSystemClass.rb │ ├── particle_system.rb │ └── particle.rb ├── NOC_4_06_ParticleSystemForces │ ├── NOC_4_06_ParticleSystemForces.rb │ ├── particle_system.rb │ └── particle.rb ├── NOC_4_05_ParticleSystemInheritancePolymorphism │ ├── NOC_4_05_ParticleSystemInheritancePolymorphism.rb │ ├── particle_system.rb │ └── particle.rb ├── NOC_4_02_ArrayListParticles │ ├── NOC_4_02_ArrayListParticles.rb │ └── particle.rb ├── NOC_4_01_SingleParticle_trail │ ├── NOC_4_01_SingleParticle_trail.rb │ └── particle.rb ├── NOC_4_07_ParticleSystemForcesRepeller │ ├── NOC_4_07_ParticleSystemForcesRepeller.rb │ ├── particle_system.rb │ ├── particle.rb │ └── repeller.rb └── NOC_4_01_SingleParticle │ └── NOC_4_01_SingleParticle.rb ├── chp02_forces ├── NOC_2_5_fluidresistance_sequence │ ├── ch2_05_0020.png │ ├── ch2_05_0040.png │ ├── ch2_05_0060.png │ ├── ch2_05_0080.png │ ├── ch2_05_0100.png │ ├── ch2_05_0120.png │ ├── ch2_05_0140.png │ ├── ch2_05_0160.png │ ├── ch2_05_0180.png │ ├── ch2_05_0200.png │ ├── ch2_05_0220.png │ ├── ch2_05_0240.png │ ├── ch2_05_0260.png │ ├── ch2_05_0280.png │ ├── ch2_05_0300.png │ ├── ch2_05_0320.png │ ├── ch2_05_0340.png │ ├── ch2_05_0360.png │ ├── ch2_05_0380.png │ ├── ch2_05_0400.png │ ├── ch2_05_0420.png │ ├── ch2_05_0440.png │ ├── ch2_05_0460.png │ ├── ch2_05_0480.png │ ├── ch2_05_0500.png │ ├── ch2_05_0520.png │ ├── ch2_05_0540.png │ ├── ch2_05_0560.png │ ├── ch2_05_0580.png │ ├── ch2_05_0600.png │ ├── ch2_05_0620.png │ ├── ch2_05_0640.png │ ├── ch2_05_0660.png │ ├── ch2_05_0680.png │ ├── ch2_05_0700.png │ ├── ch2_05_0720.png │ ├── ch2_05_0740.png │ ├── ch2_05_0760.png │ ├── ch2_05_0780.png │ ├── ch2_05_0800.png │ ├── ch2_05_0820.png │ ├── ch2_05_0840.png │ ├── ch2_05_0860.png │ ├── ch2_05_0880.png │ ├── ch2_05_0900.png │ ├── ch2_05_0920.png │ ├── ch2_05_0940.png │ ├── ch2_05_0960.png │ ├── ch2_05_0980.png │ ├── ch2_05_1000.png │ ├── ch2_05_1020.png │ ├── ch2_05_1040.png │ ├── ch2_05_1060.png │ ├── ch2_05_1080.png │ ├── ch2_05_1100.png │ └── ch2_05_1120.png ├── NOC_2_1_forces │ ├── NOC_2_1_forces.rb │ └── mover.rb ├── NOC_2_2_forces_many │ ├── NOC_2_2_forces_many.rb │ └── mover.rb ├── NOC_2_8_mutual_attraction │ ├── NOC_2_8_mutual_attraction.rb │ └── mover.rb ├── NOC_2_4_forces_nofriction │ ├── NOC_2_4_forces_nofriction.rb │ └── mover.rb ├── NOC_2_3_forces_many_realgravity │ ├── NOC_2_3_forces_many_realgravity.rb │ └── mover.rb ├── NOC_2_4_forces_friction │ ├── NOC_2_4_forces_friction.rb │ └── mover.rb ├── NOC_02forces_many_mutual_boundaries │ ├── NOC_02forces_many_mutual_boundaries.rb │ └── mover.rb ├── NOC_2_6_attraction │ ├── NOC_2_6_attraction.rb │ ├── mover.rb │ └── attractor.rb ├── NOC_2_7_attraction_many │ ├── mover.rb │ └── NOC_2_7_attraction_many.rb └── Exercise_2_10_attractrepel │ ├── Exercise_2_10_attractrepel.rb │ ├── mover.rb │ └── attractor.rb ├── chp03_oscillation ├── ExtraOscillatingUpAndDown │ └── ExtraOscillatingUpAndDown.rb ├── NOC_3_03_pointing_velocity │ ├── NOC_3_03_pointing_velocity.rb │ └── mover.rb ├── NOC_3_08_static_wave_lines │ └── NOC_3_08_static_wave_lines.rb ├── NOC_3_09_wave │ └── NOC_3_09_wave.rb ├── NOC_3_07_oscillating_objects │ ├── NOC_3_07_oscillating_objects.rb │ └── oscillator.rb ├── NOC_3_06_simple_harmonic_motion │ └── NOC_3_06_simple_harmonic_motion.rb ├── Exercise_3_01_exercise_baton │ └── Exercise_3_01_exercise_baton.rb ├── NOC_03spring_exercise_sine │ └── NOC_03spring_exercise_sine.rb ├── NOC_3_05_simple_harmonic_motion │ └── NOC_3_05_simple_harmonic_motion.rb ├── NOC_3_01_angular_motion │ └── NOC_3_01_angular_motion.rb ├── NOC_3_02_forces_angular_motion │ ├── NOC_3_02_forces_angular_motion.rb │ ├── attractor.rb │ └── mover.rb ├── Exercise_3_04_spiral │ └── Exercise_3_04_spiral.rb ├── MultipleOscillations │ └── MultipleOscillations.rb ├── NOC_3_04_PolarToCartesian_trail │ └── NOC_3_04_PolarToCartesian_trail.rb ├── AdditiveWave │ └── AdditiveWave.rb ├── NOC_3_10_PendulumExampleSimplified │ └── NOC_3_10_PendulumExampleSimplified.rb ├── OOPWaveParticles │ └── OOPWaveParticles.rb ├── Exercise_3_11_AdditiveWave │ └── Exercise_3_11_AdditiveWave.rb ├── Exercise_3_03_cannon │ └── Exercise_3_03_cannon.rb ├── NOC_3_09_exercise_additive_wave │ └── NOC_3_09_exercise_additive_wave.rb └── Exercise_3_10_OOPWave │ └── Exercise_3_10_OOPWave.rb ├── chp01_vectors ├── NOC_1_3_vector_subtraction │ └── NOC_1_3_vector_subtraction.rb ├── NOC_1_5_vector_magnitude │ └── NOC_1_5_vector_magnitude.rb ├── NOC_1_4_vector_multiplication │ └── NOC_1_4_vector_multiplication.rb ├── NOC_1_1_bouncingball_novectors │ └── NOC_1_1_bouncingball_novectors.rb ├── NOC_1_2_bouncingball_vectors │ └── NOC_1_2_bouncingball_vectors.rb ├── NOC_1_6_vector_normalize │ └── NOC_1_6_vector_normalize.rb ├── NOC_1_10_motion101_acceleration │ └── NOC_1_10_motion101_acceleration.rb ├── NOC_1_7_motion101 │ └── NOC_1_7_motion101.rb ├── NOC_1_11_motion101_acceleration_array │ └── NOC_1_11_motion101_acceleration_array.rb ├── NOC_1_8_motion101_acceleration │ └── NOC_1_8_motion101_acceleration.rb └── NOC_1_9_motion101_acceleration │ └── NOC_1_9_motion101_acceleration.rb ├── chp09_ga ├── NOC_9_02_SmartRockets_superbasic │ ├── README.md │ ├── dna.rb │ ├── smart_rocket_basic.rb │ └── rocket.rb ├── NOC_9_03_SmartRockets │ ├── obstacle.rb │ └── dna.rb └── NOC_9_05_EvolutionEcosystem │ └── evolution_ecosystem.rb ├── chp08_fractals ├── NOC_8_01_Recursion │ └── NOC_8_01_Recursion.rb ├── NOC_8_02_Recursion │ └── NOC_8_02_Recursion.rb ├── NOC_8_04_CantorSet │ └── NOC_8_04_CantorSet.rb ├── NOC_8_03_Recursion │ └── NOC_8_03_Recursion.rb ├── NOC_8_06_Tree_static │ └── NOC_8_06_Tree_static.rb ├── NOC_8_04_Tree │ └── NOC_8_04_Tree.rb ├── NOC_8_06_Tree │ └── NOC_8_06_Tree.rb └── NOC_8_07_TreeStochastic │ └── NOC_8_07_TreeStochastic.rb ├── chp06_agents ├── NOC_6_08_SeparationAndSeek │ ├── NOC_6_08_SeparationAndSeek.rb │ └── vehicle.rb ├── NOC_6_01_Seek │ └── NOC_6_01_Seek.rb ├── NOC_6_02_Arrive │ └── NOC_6_02_Arrive.rb ├── NOC_6_01_Seek_trail │ └── NOC_6_01_Seek_trail.rb ├── NOC_6_07_Separation │ └── NOC_6_07_Separation.rb └── NOC_6_03_StayWithinWalls │ └── NOC_6_03_StayWithinWalls.rb ├── chp07_CA ├── NOC_7_01_WolframCA_simple │ └── NOC_7_01_WolframCA_simple.rb ├── NOC_7_01_WolframCA_figures │ └── NOC_7_01_WolframCA_figures.rb └── NOC_7_02_GameOfLifeSimple │ └── NOC_7_02_GameOfLifeSimple.rb └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.jar 4 | chp10_nn/xor/tmp 5 | rule222.png 6 | 7 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/data/java_args.txt: -------------------------------------------------------------------------------- 1 | -XX:CompileCommand=dontinline,org.jruby.runtime.invokedynamic.InvokeDynamicSupport::invocationFallback 2 | 3 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/library/neural_network/neural_network.rb: -------------------------------------------------------------------------------- 1 | require_relative 'lib/connection' 2 | require_relative 'lib/neuron' 3 | require_relative 'lib/network' 4 | 5 | -------------------------------------------------------------------------------- /chp10_nn/xor/ext/nn/OutputNeuron.java: -------------------------------------------------------------------------------- 1 | package nn; 2 | 3 | public class OutputNeuron extends Neuron { 4 | public OutputNeuron() { 5 | super(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_09_AdditiveBlending/data/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp04_systems/NOC_4_09_AdditiveBlending/data/texture.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0020.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0040.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0060.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0080.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0100.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0120.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0140.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0140.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0160.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0160.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0180.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0200.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0220.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0220.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0240.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0260.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0260.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0280.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0280.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0300.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0300.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0320.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0320.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0340.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0340.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0360.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0360.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0380.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0380.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0400.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0420.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0420.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0440.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0460.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0460.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0480.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0480.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0500.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0520.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0520.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0540.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0540.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0560.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0560.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0580.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0580.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0600.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0600.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0620.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0620.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0640.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0640.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0660.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0660.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0680.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0700.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0700.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0720.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0720.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0740.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0740.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0760.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0760.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0780.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0780.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0800.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0800.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0820.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0820.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0840.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0840.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0860.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0860.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0880.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0880.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0900.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0900.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0920.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0920.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0940.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0940.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0960.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0960.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0980.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_0980.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1000.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1020.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1020.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1040.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1040.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1060.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1060.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1080.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1080.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1100.png -------------------------------------------------------------------------------- /chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp02_forces/NOC_2_5_fluidresistance_sequence/ch2_05_1120.png -------------------------------------------------------------------------------- /chp04_systems/NOC_4_08_ParticleSystemSmoke_b/data/texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/HEAD/chp04_systems/NOC_4_08_ParticleSystemSmoke_b/data/texture.png -------------------------------------------------------------------------------- /chp10_nn/xor/README.md: -------------------------------------------------------------------------------- 1 | Building the nn Library 2 | =================== 3 | 4 | Use jruby to run the included Rakefile, you also need the rake-compiler gem. 5 | 6 | This is the way jruby-extensions get built for eg ruby-processing!! 7 | 8 | `jruby -S rake compile` 9 | 10 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/library/neural_network/neural_network.rb: -------------------------------------------------------------------------------- 1 | # This file provides access to the below listed files via ruby-processing load_library 2 | 3 | require_relative 'lib/connection' 4 | require_relative 'lib/neuron' 5 | require_relative 'lib/network' 6 | require_relative 'lib/static_network' 7 | -------------------------------------------------------------------------------- /chp10_nn/xor/Rakefile: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | require 'java' 3 | require 'rake/javaextensiontask' 4 | 5 | Rake::JavaExtensionTask.new('nn') do |ext| 6 | ext.name = 'nn' 7 | ext.debug = true 8 | ext.lib_dir = 'library/nn' 9 | ext.source_version = '1.7' 10 | ext.target_version = '1.7' 11 | end 12 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/README.md: -------------------------------------------------------------------------------- 1 | ### Toxiclibs 2 | These examples require installation of the 'toxiclibs' gem. Whilst they work they are mainly a translation exercise and could do with a bit re-factoring for ruby-processing. But are already a bit more elegant than java/vanilla processing. 3 | ```bash 4 | gem install toxiclibs 5 | ``` 6 | -------------------------------------------------------------------------------- /chp03_oscillation/ExtraOscillatingUpAndDown/ExtraOscillatingUpAndDown.rb: -------------------------------------------------------------------------------- 1 | # ExtraOscillatingUpAndDown 2 | def setup 3 | size(400,400) 4 | @angle = 0 5 | end 6 | 7 | def draw 8 | background(255) 9 | y = 100 * sin(@angle) 10 | @angle += 0.02 11 | fill(127) 12 | translate(width / 2, height / 2) 13 | line(0, 0, 0, y) 14 | ellipse(0, y, 16, 16) 15 | end 16 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/LayeredNetworkViz.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | load_library :neural_network, :vecmath 5 | 6 | attr_reader :network 7 | 8 | def setup 9 | size 640, 360 10 | @network = StaticNetwork.new 4, 3, 1 11 | smooth 4 12 | end 13 | 14 | def draw 15 | background 255 16 | network.display 17 | end 18 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_03_ParticleSystemClass/NOC_4_03_ParticleSystemClass.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_03_ParticleSystemClass 2 | load_library :vecmath 3 | require_relative 'particle_system' 4 | 5 | def setup 6 | size(640, 360) 7 | @particle_system = ParticleSystem.new(Vec2D.new(width / 2, 50)) 8 | end 9 | 10 | def draw 11 | background(255) 12 | @particle_system.add_particle 13 | @particle_system.run 14 | end 15 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_03_pointing_velocity/NOC_3_03_pointing_velocity.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_03_pointing_velocity 2 | # http://natureofcode.com 3 | load_library :vecmath 4 | require_relative 'mover' 5 | 6 | attr_reader :mover 7 | 8 | def setup 9 | size(640, 360) 10 | @mover = Mover.new(width / 2, height / 2) 11 | end 12 | 13 | def draw 14 | background(255) 15 | mover.update 16 | mover.check_edges 17 | mover.display 18 | end 19 | -------------------------------------------------------------------------------- /chp10_nn/xor/ext/nn/HiddenNeuron.java: -------------------------------------------------------------------------------- 1 | //Daniel Shiffman 2 | //The Nature of Code, Fall 2006 3 | //Neural Network 4 | 5 | // Hidden Neuron Class 6 | // So far not necessary to differentiate these 7 | 8 | package nn; 9 | 10 | public class HiddenNeuron extends Neuron { 11 | 12 | public HiddenNeuron() { 13 | super(); 14 | } 15 | 16 | public HiddenNeuron(int i) { 17 | super(i); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_body/connection.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | class Connection < Physics::VerletSpring2D 5 | extend Forwardable 6 | def_delegators(:@app, :stroke, :line) 7 | 8 | def initialize(p1, p2, len, strength) 9 | super(p1, p2, len, strength) 10 | @app = $app 11 | end 12 | 13 | def display 14 | stroke(0) 15 | line(a.x, a.y, b.x, b.y) 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_08_static_wave_lines/NOC_3_08_static_wave_lines.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_08_static_wave_lines 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | angle = 0 6 | angle_vel = 0.1 7 | 8 | size(800, 200) 9 | background(255) 10 | stroke(0) 11 | stroke_weight(2) 12 | no_fill 13 | 14 | begin_shape 15 | (0 .. width).step(5) do |x| 16 | y = map1d(sin(angle), (-1 .. 1.0), (0 .. height)) 17 | vertex(x, y) 18 | angle += angle_vel 19 | end 20 | end_shape 21 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_1_forces/NOC_2_1_forces.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | require_relative 'mover' 7 | 8 | def setup 9 | size(640, 360) 10 | @m = Mover.new 11 | end 12 | 13 | def draw 14 | background(255) 15 | wind = Vec2D.new(0.01, 0) 16 | gravity = Vec2D.new(0, 0.1) 17 | @m.apply_force(wind) 18 | @m.apply_force(gravity) 19 | @m.update 20 | @m.display 21 | @m.check_edges(width, height) 22 | end 23 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_09_AdditiveBlending/NOC_4_09_AdditiveBlending.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_09_AdditiveBlending 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | load_library :vecmath 5 | require_relative 'particle_system' 6 | 7 | attr_reader :ps 8 | 9 | def setup 10 | size(640, 340, P2D) 11 | @ps = ParticleSystem.new(0, Vec2D.new(width / 2, 50)) 12 | end 13 | 14 | def draw 15 | blend_mode(ADD) 16 | background(0) 17 | ps.run 18 | 10.times{ ps.add_particle } 19 | end 20 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_06_ParticleSystemForces/NOC_4_06_ParticleSystemForces.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_06_ParticleSystemForces 2 | 3 | load_library :vecmath 4 | require_relative 'particle_system' 5 | attr_reader :ps 6 | 7 | def setup 8 | size(640,360) 9 | @ps = ParticleSystem.new(Vec2D.new(width / 2, 50)) 10 | end 11 | 12 | def draw 13 | background(255) 14 | # Apply gravity force to all Particles 15 | gravity = Vec2D.new(0, 0.1) 16 | ps.apply_force(gravity) 17 | ps.add_particle 18 | ps.run 19 | end 20 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_09_wave/NOC_3_09_wave.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_09_wave 2 | def setup 3 | size(800, 200) 4 | smooth 5 | @start_angle = 0 6 | @angle_vel = 0.23 7 | end 8 | 9 | def draw 10 | background(255) 11 | 12 | @start_angle += 0.015 13 | angle = @start_angle 14 | 15 | (0..width).step(24) do |x| 16 | y = map1d(sin(angle), (-1 .. 1), (0 .. height)) 17 | stroke(0) 18 | fill(0, 50) 19 | stroke_weight(2) 20 | ellipse(x, y, 48, 48) 21 | angle += @angle_vel 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/NOC_4_05_ParticleSystemInheritancePolymorphism.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_05_ParticleSystemInheritancePolymorphism 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | load_library :vecmath 5 | require_relative 'particle_system' 6 | 7 | def setup 8 | size(640, 360) 9 | @particle_system = ParticleSystem.new(Vec2D.new(width / 2, 50)) 10 | end 11 | 12 | def draw 13 | background(255) 14 | @particle_system.add_particle 15 | @particle_system.run 16 | end 17 | -------------------------------------------------------------------------------- /chp10_nn/xor/ext/nn/InputNeuron.java: -------------------------------------------------------------------------------- 1 | //Daniel Shiffman 2 | //The Nature of Code, Fall 2006 3 | //Neural Network 4 | 5 | // Input Neuron Class 6 | // Has additional functionality to receive beginning input 7 | 8 | package nn; 9 | 10 | public class InputNeuron extends Neuron { 11 | public InputNeuron() { 12 | super(); 13 | } 14 | 15 | public InputNeuron(int i) { 16 | super(i); 17 | } 18 | 19 | public void input(double d) { 20 | output = d; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_07_oscillating_objects/NOC_3_07_oscillating_objects.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_07_oscillating_objects 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | load_library :vecmath 6 | require_relative 'oscillator' 7 | 8 | attr_reader :oscillators 9 | 10 | def setup 11 | size 800, 200 12 | smooth 4 13 | @oscillators = Array.new(10) { Oscillator.new(width, height) } 14 | end 15 | 16 | def draw 17 | background 255 18 | oscillators.each do |o| 19 | o.oscillate 20 | o.display 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_06_simple_harmonic_motion/NOC_3_06_simple_harmonic_motion.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_06_simple_harmonic_motion 2 | 3 | attr_reader :angle, :velocity 4 | def setup 5 | size 640, 360 6 | smooth 4 7 | @angle = 0 8 | @velocity = 0.03 9 | end 10 | 11 | def draw 12 | background 255 13 | amplitude = 300 14 | x = amplitude * cos(angle) 15 | @angle += velocity 16 | ellipse_mode(CENTER) 17 | stroke 0 18 | fill 175 19 | translate(width / 2, height / 2) 20 | line(0, 0, x, 0) 21 | ellipse(x, 0, 20, 20) 22 | end 23 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_02_ArrayListParticles/NOC_4_02_ArrayListParticles.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | # Simple Particle System 5 | # A simple Particle class 6 | load_library :vecmath 7 | require_relative 'particle' 8 | 9 | attr_reader :particles 10 | 11 | def setup 12 | size(640, 360) 13 | @particles = [] 14 | end 15 | 16 | def draw 17 | background(255) 18 | particles << Particle.new(Vec2D.new(width / 2, 50)) 19 | particles.each { |p| p.run } 20 | particles.reject! { |p| p.dead? } 21 | end 22 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/distance_joint/particle_system.rb: -------------------------------------------------------------------------------- 1 | # run system with a single command 2 | module Runnable 3 | def run 4 | reject!(&:done?) 5 | each(&:display) 6 | end 7 | end 8 | 9 | # A custom enumerable class, it is so easy in ruby 10 | class ParticleSystem 11 | include Enumerable, Runnable 12 | extend Forwardable 13 | def_delegators(:@pairs, :each, :reject!, :<<) 14 | 15 | def initialize 16 | @pairs = [] 17 | end 18 | 19 | def add_pair(x, y) 20 | self << Pair.new(x, y) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /chp03_oscillation/Exercise_3_01_exercise_baton/Exercise_3_01_exercise_baton.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | def setup 5 | size(750, 150) 6 | smooth 7 | 8 | @angle = 0 9 | end 10 | 11 | def draw 12 | background(255) 13 | 14 | fill(127) 15 | stroke(0) 16 | rect_mode(CENTER) 17 | translate(width/2, height/2) 18 | rotate(@angle) 19 | line(-50, 0, 50, 0) 20 | stroke(0) 21 | stroke_weight(2) 22 | fill(127) 23 | ellipse(50, 0, 16, 16) 24 | ellipse(-50, 0, 16, 16) 25 | @angle += 0.05 26 | end 27 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_03spring_exercise_sine/NOC_03spring_exercise_sine.rb: -------------------------------------------------------------------------------- 1 | # NOC_03spring_exercise_sine 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | attr_reader :angle, :velocity 5 | 6 | def setup 7 | size(640, 360) 8 | smooth 9 | @angle = 0 10 | @velocity = 0.05 11 | end 12 | 13 | def draw 14 | background(255) 15 | x = width / 2 16 | y = map1d(sin(angle), (-1 .. 1), (50 .. 250)) 17 | @angle += velocity 18 | ellipse_mode(CENTER) 19 | stroke(0) 20 | fill(175) 21 | line(x, 0, x, y) 22 | ellipse(x, y, 20, 20) 23 | end 24 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_3_vector_subtraction/NOC_1_3_vector_subtraction.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_3_vector_subtraction.pde 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # Example 1-3: Vector subtraction 5 | load_library :vecmath 6 | 7 | def setup 8 | size(800, 200) 9 | smooth 4 10 | end 11 | 12 | def draw 13 | background(255) 14 | mouse = Vec2D.new(mouse_x, mouse_y) 15 | center = Vec2D.new(width / 2, height / 2) 16 | mouse -= center 17 | translate(width / 2, height / 2) 18 | stroke_weight(2) 19 | stroke(0) 20 | line(0, 0, mouse.x, mouse.y) 21 | end 22 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_2_forces_many/NOC_2_2_forces_many.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | require_relative 'mover' 7 | 8 | def setup 9 | size(800, 200) 10 | @movers = Array.new(20) { Mover.new(rand(0.1 .. 4), 0, 0) } 11 | end 12 | 13 | def draw 14 | background(255) 15 | @movers.each do |m| 16 | wind = Vec2D.new(0.01, 0) 17 | gravity = Vec2D.new(0, 0.1) 18 | m.apply_force(wind) 19 | m.apply_force(gravity) 20 | m.update 21 | m.display 22 | m.check_edges(width, height) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_8_mutual_attraction/NOC_2_8_mutual_attraction.rb: -------------------------------------------------------------------------------- 1 | # NOC_2_8_mutual_attraction 2 | # http://natureofcode.com 3 | load_library :vecmath 4 | require_relative 'mover' 5 | 6 | def setup 7 | size(800, 200) 8 | @movers = Array.new(20) { Mover.new(rand(width), rand(height), rand(0.1 .. 2)) } 9 | end 10 | 11 | def draw 12 | background(255) 13 | @movers.each do |m| 14 | @movers.each do |mm| 15 | next if m.equal? mm 16 | force = mm.attract(m) 17 | m.apply_force(force) 18 | end 19 | m.update 20 | m.display 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_02_SmartRockets_superbasic/README.md: -------------------------------------------------------------------------------- 1 | ## Example of using refined includes in ruby-processing 2 | In dna.rb, we only require access to ruby math methods so we just `include Math` in the DNA class 3 | 4 | In population.rb we want to use the helper method `map1d` so we just `include Processing::HelperMethods` in the Population class 5 | 6 | In rocket.rb, we require similar access to processing methods as available to java inner classes, so here we `include Processing::Proxy` this allows us to access `stroke`, `push_matrix`, `pop_matrix`, `rotate` etc. in the Rocket class 7 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_4_forces_nofriction/NOC_2_4_forces_nofriction.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | load_library :vecmath 4 | require_relative 'mover' 5 | 6 | def setup 7 | size(383, 200) 8 | srand(1) 9 | @movers = Array.new(15) { Mover.new(rand(1.0 .. 4), rand(width), 0) } 10 | end 11 | 12 | def draw 13 | background(255) 14 | @movers.each do |m| 15 | wind = Vec2D.new(0.01, 0) 16 | gravity = Vec2D.new(0, 0.1 * m.mass) 17 | m.apply_forces(wind, gravity) 18 | m.update 19 | m.display 20 | m.check_edges(width, height) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_05_simple_harmonic_motion/NOC_3_05_simple_harmonic_motion.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_05_simple_harmonic_motion 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | def setup 6 | size 800, 200 7 | end 8 | 9 | def draw 10 | background 255 11 | period = 120 12 | amplitude = 300 13 | # Calculating horizontal location according to formula for simple harmonic motion 14 | x = amplitude * cos(TAU * frame_count / period) 15 | stroke(0) 16 | stroke_weight(2) 17 | fill(127) 18 | translate(width / 2, height / 2) 19 | line(0, 0, x, 0) 20 | ellipse(x, 0, 48, 48) 21 | end 22 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/attract_repel/attractor.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | class Attractor < Physics::VerletParticle2D 5 | extend Forwardable 6 | def_delegators(:@app, :fill, :ellipse, :physics, :width) 7 | attr_accessor :r 8 | 9 | def initialize(loc) 10 | super(loc) 11 | @app = $app 12 | @r = 24 13 | physics.add_particle(self) 14 | physics.add_behavior(Physics::AttractionBehavior2D.new(self, width, 0.1)) 15 | end 16 | 17 | def display 18 | fill(0) 19 | ellipse(x, y, r * 2, r * 2) 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_01_Recursion/NOC_8_01_Recursion.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_01_Recursion 3 | 4 | def setup 5 | size(640, 360) 6 | end 7 | 8 | def draw 9 | background(255) 10 | draw_circle(width / 2, height / 2, width) 11 | no_loop 12 | end 13 | 14 | # Very simple function that draws one circle 15 | # and recursively calls itself 16 | def draw_circle(x, y, r) 17 | ellipse(x, y, r, r) 18 | # Exit condition, stop when radius is too small 19 | return unless r > 2 20 | r *= 0.75 21 | # Call the function inside the function! (recursion!) 22 | draw_circle(x, y, r) 23 | end 24 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_3_forces_many_realgravity/NOC_2_3_forces_many_realgravity.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | require_relative 'mover' 6 | 7 | def setup 8 | size(800, 200) 9 | @movers = Array.new(20) { Mover.new(rand(1.0 .. 4), 0, 0) } 10 | end 11 | 12 | def draw 13 | background(255) 14 | @movers.each do |m| 15 | wind = Vec2D.new(0.01, 0) 16 | gravity = Vec2D.new(0, 0.1 * m.mass) 17 | m.apply_force(wind) 18 | m.apply_force(gravity) 19 | m.update 20 | m.display 21 | m.check_edges(width, height) 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_5_vector_magnitude/NOC_1_5_vector_magnitude.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_5_vector_magnitude 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # Example 1-5: Vector magnitude 5 | load_library :vecmath 6 | 7 | def setup 8 | size(800, 200) 9 | smooth 4 10 | end 11 | 12 | def draw 13 | background(255) 14 | mouse = Vec2D.new(mouse_x, mouse_y) 15 | center = Vec2D.new(width / 2, height / 2) 16 | mouse -= center 17 | fill(0) 18 | no_stroke 19 | rect(0, 0, mouse.mag, 10) 20 | translate(width / 2, height / 2) 21 | stroke(0) 22 | stroke_weight(2) 23 | line(0, 0, mouse.x, mouse.y) 24 | end 25 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_08_SeparationAndSeek/NOC_6_08_SeparationAndSeek.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_08_SeparationAndSeek 3 | load_library :vecmath 4 | require_relative 'vehicle' 5 | 6 | attr_reader :vehicles 7 | 8 | def setup 9 | size(640, 360) 10 | @vehicles = Array.new(100) { Vehicle.new(rand(width), rand(height)) } 11 | end 12 | 13 | def draw 14 | background(255) 15 | vehicles.each do |v| 16 | v.apply_behaviors(vehicles) 17 | v.update 18 | v.borders(width, height) 19 | v.display 20 | end 21 | end 22 | 23 | def mouse_dragged 24 | vehicles << Vehicle.new(mouse_x, mouse_y) 25 | end 26 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_03_ParticleSystemClass/particle_system.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_03_ParticleSystemClass 2 | require 'forwardable' 3 | require_relative 'particle' 4 | 5 | module Runnable 6 | def run 7 | self.reject! { |item| item.dead? } 8 | each { |item| item.run } 9 | end 10 | end 11 | 12 | class ParticleSystem 13 | include Enumerable, Runnable 14 | extend Forwardable 15 | def_delegators(:@particles, :reject!, :<<, :each) 16 | attr_reader :origin 17 | 18 | def initialize(origin) 19 | @origin = origin 20 | @particles = [] 21 | end 22 | 23 | def add_particle 24 | self << Particle.new(origin) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/particle_system.rb: -------------------------------------------------------------------------------- 1 | require_relative 'particle' 2 | require 'forwardable' 3 | 4 | module Runnable 5 | def run 6 | reject! { |item| item.dead? } 7 | each { |item| item.run } 8 | end 9 | end 10 | 11 | class ParticleSystem 12 | extend Forwardable 13 | def_delegators(:@particles, :reject!, :<<, :each) 14 | include Enumerable, Runnable 15 | 16 | def initialize(origin) 17 | @origin = origin 18 | @particles = [] 19 | end 20 | 21 | def add_particle 22 | part = (rand < 0.5) ? Particle.new(@origin) : Confetti.new(@origin) 23 | self << part 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_02_Recursion/NOC_8_02_Recursion.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_02_Recursion 3 | def setup 4 | size(640, 360) 5 | end 6 | 7 | def draw 8 | background(255) 9 | draw_circle(width / 2, height / 2, 400) 10 | no_loop 11 | end 12 | 13 | # Very simple function that draws one circle 14 | # and recursively calls itself 15 | def draw_circle(x, y, r) 16 | stroke(0) 17 | no_fill 18 | ellipse(x, y, r, r) 19 | # Exit condition, stop when radius is too small 20 | return unless r > 2 21 | # now we draw 2 circles, 1 on the left, 1 on the right 22 | draw_circle(x + r/2, y, r/2) 23 | draw_circle(x - r/2, y, r/2) 24 | end 25 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/mouse_joint/dummy_spring.rb: -------------------------------------------------------------------------------- 1 | # dummy_spring.rb by Martin Prout 2 | # using duck-typing so class can stand in for Spring 3 | 4 | # Using this class avoids test for nil 5 | class DummySpring 6 | def initialize; end 7 | 8 | # If it exists we set its target to the mouse location 9 | def update(_x, _y); end 10 | 11 | def display; end 12 | 13 | # This is the key function where 14 | # we attach the spring to an x,y location 15 | # and the Box object's location 16 | def bind(x, y, box) 17 | @spring = Spring.new.tap do |spr| 18 | spr.bind(x, y, box) 19 | end 20 | end 21 | 22 | def destroy; end 23 | end 24 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_04_CantorSet/NOC_8_04_CantorSet.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_04_CantorSet 3 | def setup 4 | size(800, 200) 5 | background(255) 6 | @h = 30 7 | # Call the recursive function 8 | cantor(35, 0, 730) 9 | end 10 | 11 | def cantor(x, y, len) 12 | # recursive exit condition 13 | return unless len >= 1 14 | # Draw line (as rectangle to make it easier to see) 15 | no_stroke 16 | fill(0) 17 | rect(x, y, len, @h / 3) 18 | # Go down to next y position 19 | y += @h 20 | # Draw 2 more lines 1/3rd the length (without the middle section) 21 | cantor(x, y, len / 3) 22 | cantor(x + len * 2 / 3, y, len / 3) 23 | end 24 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_01_SingleParticle_trail/NOC_4_01_SingleParticle_trail.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | # Simple Particle System 5 | # A simple Particle class 6 | 7 | load_library :vecmath 8 | require_relative 'particle' 9 | 10 | def setup 11 | size(800, 200) 12 | @p = Particle.new(Vec2D.new(width / 2, 20)) 13 | background(255) 14 | smooth 4 15 | end 16 | 17 | def draw 18 | # NB: in ruby-processing use mouse_pressed? instead of mousePressed 19 | # replacing a conditional with a guard clause 20 | return unless mouse_pressed? 21 | no_stroke 22 | fill(255, 5) 23 | rect(0, 0, width, height) 24 | @p.run 25 | end 26 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_4_vector_multiplication/NOC_1_4_vector_multiplication.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_4_vector_multiplication 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # Example 1-4: Vector multiplication 5 | load_library :vecmath 6 | 7 | def setup 8 | size 800, 200 9 | smooth 4 10 | end 11 | 12 | def draw 13 | background 255 14 | mouse = Vec2D.new(mouse_x, mouse_y) 15 | center = Vec2D.new(width/2, height/2) 16 | mouse -= center 17 | # Multiplying a vector! The vector is now half its original size (multiplied by 0.5). 18 | mouse *= 0.5 19 | translate(width/2, height/2) 20 | stroke_weight(2) 21 | stroke(0) 22 | line(0, 0, mouse.x, mouse.y) 23 | end 24 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_07_ParticleSystemForcesRepeller/NOC_4_07_ParticleSystemForcesRepeller.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_07_ParticleSystemForcesRepeller 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | require_relative 'repeller' 6 | require_relative 'particle_system' 7 | 8 | attr_reader :ps, :repeller 9 | 10 | def setup 11 | size(640, 360) 12 | @ps = ParticleSystem.new(Vec2D.new(width / 2, 50)) 13 | @repeller = Repeller.new(width / 2 - 20, height / 2) 14 | end 15 | 16 | def draw 17 | background(255) 18 | ps.add_particle 19 | gravity = Vec2D.new(0, 0.1) 20 | ps.apply_force(gravity) 21 | ps.apply_repeller(repeller) 22 | repeller.display 23 | ps.run 24 | end 25 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_01_angular_motion/NOC_3_01_angular_motion.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_01_angular_motion 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | attr_reader :acceleration, :angle, :velocity 5 | 6 | def setup 7 | size 800, 200 8 | smooth 4 9 | @angle = 0 10 | @velocity = 0 11 | @acceleration = 0.0001 12 | end 13 | 14 | def draw 15 | background 255 16 | fill 127 17 | stroke 0 18 | translate(width / 2, height / 2) 19 | rect_mode(CENTER) 20 | rotate(angle) 21 | stroke_weight(2) 22 | fill(127) 23 | line(-60, 0, 60, 0) 24 | ellipse(60, 0, 16, 16) 25 | ellipse(-60, 0, 16, 16) 26 | @angle += velocity 27 | @velocity += acceleration 28 | end 29 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_1_bouncingball_novectors/NOC_1_1_bouncingball_novectors.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_1_bouncingball_novectors 2 | # http://natureofcode.com 3 | # Example 1-1: Bouncing Ball, no vectors 4 | 5 | def setup 6 | size(800, 200) 7 | smooth 4 8 | @x = 100 9 | @y = 100 10 | @xspeed = 2.5 11 | @yspeed = 2 12 | end 13 | 14 | def draw 15 | background(255) 16 | # Add the current speed to the location. 17 | @x += @xspeed 18 | @y += @yspeed 19 | @xspeed = -@xspeed if @x > width or @x < 0 20 | @yspeed = -@yspeed if @y > height or @y < 0 21 | # Display circle at x location 22 | stroke(0) 23 | stroke_weight(2) 24 | fill(127) 25 | ellipse(@x, @y, 48, 48) 26 | end 27 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_02_forces_angular_motion/NOC_3_02_forces_angular_motion.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_02_forces_angular_motion 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | load_library :vecmath 5 | require_relative 'attractor' 6 | require_relative 'mover' 7 | 8 | # NOC_3_02_forces_angular_motion 9 | def setup 10 | size(640, 360) 11 | background(255) 12 | @movers = Array.new(20) { Mover.new(rand(0.1 .. 2), rand(width), rand(height)) } 13 | @a = Attractor.new(width, height) 14 | end 15 | 16 | def draw 17 | background(255) 18 | @a.display 19 | @movers.each do |m| 20 | force = @a.attract(m) 21 | m.apply_force(force) 22 | m.update 23 | m.display 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/collision_listening.rb: -------------------------------------------------------------------------------- 1 | require 'pbox2d' 2 | require_relative 'lib/custom_listener' 3 | require_relative 'lib/particle' 4 | require_relative 'lib/boundary' 5 | 6 | attr_reader :box2d, :particles, :wall 7 | 8 | def setup 9 | size 400, 400 10 | @box2d = Box2D.new(self) 11 | box2d.create_world 12 | box2d.add_listener(CustomListener.new) 13 | @particles = [] 14 | @wall = Boundary.new(box2d, width / 2, height - 5, width, 10) 15 | end 16 | 17 | def draw 18 | background(255) 19 | particles << Particle.new(box2d, rand(width), 20, rand(4..8)) if rand < 0.1 20 | particles.each{ |p| p.display(self) } 21 | particles.reject!(&:done) 22 | wall.display(self) 23 | end -------------------------------------------------------------------------------- /chp02_forces/NOC_2_4_forces_friction/NOC_2_4_forces_friction.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | load_library :vecmath 4 | require_relative 'mover' 5 | 6 | def setup 7 | size(383, 200) 8 | srand(1) 9 | @movers = Array.new(15) { Mover.new(rand(1.0 .. 4), rand(width), 0) } 10 | end 11 | 12 | def draw 13 | background(255) 14 | @movers.each do |m| 15 | wind = Vec2D.new(0.01, 0) 16 | gravity = Vec2D.new(0, 0.1 * m.mass) 17 | c = 0.05 18 | friction = m.velocity.copy 19 | friction *= -1 20 | friction.set_mag c 21 | m.apply_forces(wind, gravity, friction) 22 | m.update 23 | m.display 24 | m.check_edges(width, height) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_02_forces_angular_motion/attractor.rb: -------------------------------------------------------------------------------- 1 | class Attractor 2 | include Processing::Proxy 3 | 4 | def initialize(width, height) 5 | @location = Vec2D.new(width / 2, height / 2) 6 | @mass = 20 7 | @g = 0.4 8 | end 9 | 10 | def attract(mover) 11 | force = @location - mover.location 12 | distance = force.mag 13 | distance = constrain(distance, 5.0, 25.0) 14 | force.normalize! 15 | strength = (@g * @mass * mover.mass) / (distance * distance) 16 | force *= strength 17 | force 18 | end 19 | 20 | def display 21 | stroke(0) 22 | stroke_weight(2) 23 | fill(127) 24 | ellipse(@location.x, @location.y, 48, 48) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_06_ParticleSystemForces/particle_system.rb: -------------------------------------------------------------------------------- 1 | require 'forwardable' 2 | require_relative 'particle' 3 | 4 | module Runnable 5 | def run 6 | reject! { |item| item.dead? } 7 | each { |item| item.run } 8 | end 9 | end 10 | 11 | class ParticleSystem 12 | include Enumerable, Runnable 13 | extend Forwardable 14 | def_delegators(:@particle_system, :each, :<<, :reject!) 15 | 16 | attr_reader :origin 17 | 18 | def initialize(origin) 19 | @origin = origin 20 | @particle_system = [] 21 | end 22 | 23 | def add_particle 24 | self << Particle.new(origin) 25 | end 26 | 27 | def apply_force(f) 28 | each { |p| p.apply_force(f) } 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/attract_repel/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # class Spore extends the class "VerletParticle2D" 6 | class Particle < Physics::VerletParticle2D 7 | extend Forwardable 8 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :ellipse, :physics) 9 | attr_reader :r 10 | 11 | def initialize(loc) 12 | super(loc) 13 | @app = $app 14 | @r = 8 15 | physics.add_particle(self) 16 | physics.add_behavior(Physics::AttractionBehavior2D.new(self, r * 4, -1)) 17 | end 18 | 19 | def display 20 | fill 127 21 | stroke 0 22 | stroke_weight 2 23 | ellipse x, y, r * 2, r * 2 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp03_oscillation/Exercise_3_04_spiral/Exercise_3_04_spiral.rb: -------------------------------------------------------------------------------- 1 | # Exercise_3_04_spiral 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | attr_reader :theta, :r 6 | 7 | # A Polar coordinate, radius now starts at 0 to spiral outwards 8 | def setup 9 | size(750, 200) 10 | background(255) 11 | smooth 4 12 | @r = 0 13 | @theta = 0 14 | end 15 | 16 | def draw 17 | # Polar to Cartesian conversion 18 | x = r * cos(theta) 19 | y = r * sin(theta) 20 | # Draw an ellipse at x,y 21 | no_stroke 22 | fill(0) 23 | # Adjust for center of window 24 | ellipse(x + width / 2, y + height / 2, 16, 16) 25 | # Increment the angle 26 | @theta += 0.01 27 | # Increment the radius 28 | @r += 0.05 29 | end 30 | -------------------------------------------------------------------------------- /chp03_oscillation/MultipleOscillations/MultipleOscillations.rb: -------------------------------------------------------------------------------- 1 | # MultipleOscillations 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | attr_reader :angle1, :angle2, :velocity1, :velocity2 5 | 6 | def setup 7 | size 640, 360 8 | @angle1 = 0 9 | @velocity1 = 0.01 10 | @amplitude1 = 300 11 | @angle2 = 0 12 | @velocity2 = 0.3 13 | @amplitude2 = 10 14 | end 15 | 16 | def draw 17 | background(255) 18 | x = 0 19 | x += @amplitude1 * cos(angle1) 20 | x += @amplitude2 * sin(angle2) 21 | @angle1 += velocity1 22 | @angle2 += velocity2 23 | ellipse_mode(CENTER) 24 | stroke(0) 25 | fill(175) 26 | translate(width / 2, height / 2) 27 | line(0, 0, x, 0) 28 | ellipse(x, 0, 20, 20) 29 | end 30 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_body/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Notice how we are using inheritance here! 6 | # We could have just stored a reference to a VerletParticle object 7 | # inside the Particle class, but inheritance is a nice alternative 8 | class Particle < Physics::VerletParticle2D 9 | extend Forwardable 10 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :ellipse) 11 | def initialize(loc) 12 | super(loc) 13 | @app = $app 14 | end 15 | 16 | # All we're doing really is adding a display function to a VerletParticle 17 | def display 18 | fill(175) 19 | stroke(0) 20 | ellipse(x, y, 16, 16) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_03_SmartRockets/obstacle.rb: -------------------------------------------------------------------------------- 1 | # A class for an obstacle, just a simple rectangle that is drawn 2 | # and can check if a Rocket touches it 3 | # Also using this class for target location 4 | class Obstacle 5 | include Processing::Proxy 6 | attr_reader :location 7 | def initialize(x, y, w_, h_) 8 | @location = Vec2D.new(x, y) 9 | @w = w_ 10 | @h = h_ 11 | end 12 | 13 | def display 14 | stroke(0) 15 | fill(175) 16 | stroke_weight(2) 17 | rect_mode(CORNER) 18 | rect(location.x, location.y, @w, @h) 19 | end 20 | 21 | def contains(spot) 22 | ((location.x..location.x + @w).include? spot.x) && 23 | ((location.y..location.y + @h).include? spot.y) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_03_Recursion/NOC_8_03_Recursion.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_03_Recursion 3 | def setup 4 | size(640, 360) 5 | end 6 | 7 | def draw 8 | background(255) 9 | draw_circle(width / 2, height / 2, 400) 10 | no_loop 11 | end 12 | 13 | # Very simple function that draws one circle 14 | # and recursively calls itself 15 | def draw_circle(x, y, r) 16 | stroke(0) 17 | no_fill 18 | ellipse(x, y, r, r) 19 | # Exit condition, stop when radius is too small 20 | return unless r > 8 21 | # now we draw 2 circles, 1 on the left, 1 on the right 22 | draw_circle(x + r / 2, y, r / 2) 23 | draw_circle(x - r / 2, y, r / 2) 24 | draw_circle(x, y + r / 2, r / 2) 25 | draw_circle(x, y - r / 2, r / 2) 26 | end 27 | -------------------------------------------------------------------------------- /chp02_forces/NOC_02forces_many_mutual_boundaries/NOC_02forces_many_mutual_boundaries.rb: -------------------------------------------------------------------------------- 1 | # NOC_02forces_many_mutual_boundaries 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | load_library :vecmath 6 | require_relative 'mover' 7 | 8 | attr_reader :movers 9 | 10 | def setup 11 | size(640, 360) 12 | @movers = Array.new(20) { Mover.new(rand(1.0 .. 2), rand(width), rand(height)) } 13 | end 14 | 15 | def draw 16 | background(255) 17 | movers.size.times do |i| 18 | movers.size.times do |j| 19 | unless i == j 20 | force = movers[j].attract(movers[i]) 21 | movers[i].apply_force(force) 22 | end 23 | end 24 | movers[i].boundaries width, height 25 | movers[i].update 26 | movers[i].display 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/attract_repel/attract_repel.rb: -------------------------------------------------------------------------------- 1 | require 'toxiclibs' 2 | require 'forwardable' 3 | require_relative 'attractor' 4 | require_relative 'particle' 5 | 6 | attr_reader :particles, :attractor, :physics 7 | 8 | def setup 9 | size 640, 360 10 | @physics = Physics::VerletPhysics2D.new 11 | physics.setDrag(0.01) 12 | @particles = (0..50).map { Particle.new(TVec2D.new(rand(width), rand(height))) } 13 | @attractor = Attractor.new(TVec2D.new(width / 2, height / 2)) 14 | end 15 | 16 | def draw 17 | background(255) 18 | physics.update 19 | attractor.display 20 | particles.each(&:display) 21 | if mouse_pressed? 22 | attractor.lock 23 | attractor.set(mouse_x, mouse_y) 24 | else 25 | attractor.unlock 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/simple_spring/particle.rb: -------------------------------------------------------------------------------- 1 | require 'forwardable' 2 | 3 | # The Nature of Code 4 | # Daniel Shiffman 5 | # http://natureofcode.com 6 | # Notice how we are using inheritance here! 7 | # We could have just stored a reference to a VerletParticle2D object 8 | # inside the Particle class, but inheritance is an alternative 9 | class Particle < Physics::VerletParticle2D 10 | extend Forwardable 11 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :ellipse) 12 | def initialize(loc) 13 | super(loc) 14 | @app = $app 15 | end 16 | 17 | # All we're doing really is adding a display function to a VerletParticle 18 | def display 19 | fill(127) 20 | stroke(0) 21 | stroke_weight(2) 22 | ellipse(x, y, 32, 32) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/lib/custom_listener.rb: -------------------------------------------------------------------------------- 1 | # A custom listener allows us to get the physics engine to 2 | # to call our code, on say contact (collisions) 3 | class CustomListener 4 | include ContactListener 5 | 6 | def begin_contact(cp) 7 | # Get both fixtures 8 | f1 = cp.getFixtureA 9 | f2 = cp.getFixtureB 10 | # Get both bodies 11 | b1 = f1.getBody 12 | b2 = f2.getBody 13 | # Get our objects that reference these bodies 14 | o1 = b1.getUserData 15 | o2 = b2.getUserData 16 | return unless [o1, o2].all? { |obj| obj.respond_to?(:change) } 17 | o1.change 18 | o2.change 19 | end 20 | 21 | def end_contact(_cp) 22 | end 23 | 24 | def pre_solve(_cp, _m) 25 | end 26 | 27 | def post_solve(_cp, _ci) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_string/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Notice how we are using inheritance here! 6 | # We could have just stored a reference to a VerletPhysics2D object 7 | # inside the Particle class, but inheritance is a nice alternative 8 | 9 | class Particle < Physics::VerletParticle2D 10 | include Processing::Proxy 11 | attr_accessor :radius # Adding a radius for each particle 12 | 13 | def initialize(x, y) 14 | super(x, y) 15 | @radius = 4 16 | end 17 | 18 | # All we're doing really is adding a display function to a VerletParticle2D 19 | def display 20 | fill(127) 21 | stroke(0) 22 | stroke_weight(2) 23 | ellipse(x, y, radius * 2, radius * 2) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_2_bouncingball_vectors/NOC_1_2_bouncingball_vectors.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_2_bouncingball_vectors 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # Example 1-2: Bouncing Ball, with Vec2D! 5 | load_library :vecmath 6 | 7 | def setup 8 | size(200,200) 9 | background(255) 10 | @location = Vec2D.new(100.0, 100.0) 11 | @velocity = Vec2D.new(2.5, 5.0) 12 | end 13 | 14 | def draw 15 | no_stroke 16 | fill(255, 10) 17 | rect(0, 0, width, height) 18 | # Add the current speed to the location. 19 | @location += @velocity 20 | @velocity.x = -@velocity.x unless (0 .. width).include? @location.x 21 | @velocity.y = -@velocity.y unless (0 .. height).include? @location.y 22 | # Display circle at x location 23 | stroke(0) 24 | fill(175) 25 | ellipse(@location.x, @location.y, 16, 16) 26 | end 27 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_07_ParticleSystemForcesRepeller/particle_system.rb: -------------------------------------------------------------------------------- 1 | require 'forwardable' 2 | require_relative 'particle' 3 | 4 | module Runnable 5 | def run 6 | reject! { |item| item.dead? } 7 | each { |item| item.run } 8 | end 9 | end 10 | 11 | class ParticleSystem 12 | include Enumerable, Runnable 13 | extend Forwardable 14 | def_delegators(:@particle_system, :each, :<<, :reject!) 15 | 16 | 17 | def initialize(origin) 18 | @origin = origin 19 | @particle_system = [] 20 | end 21 | 22 | def add_particle 23 | self << Particle.new(@origin) 24 | end 25 | 26 | def apply_force(f) 27 | each { |p| p.apply_force(f) } 28 | end 29 | 30 | def apply_repeller(repeller) 31 | each do |p| 32 | f = repeller.repel(p) 33 | p.apply_force(f) 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_07_oscillating_objects/oscillator.rb: -------------------------------------------------------------------------------- 1 | class Oscillator 2 | include Processing::Proxy 3 | 4 | attr_reader :angle, :amplitude, :velocity, :width, :height 5 | def initialize(width, height) 6 | @width, @height = width, height 7 | @angle = Vec2D.new 8 | @velocity = Vec2D.new(rand(-0.05 .. 0.05), rand(-0.05 .. 0.05)) 9 | @amplitude = Vec2D.new(rand(20 .. width / 2), rand(20 .. height / 2)) 10 | end 11 | 12 | def oscillate 13 | @angle += velocity 14 | end 15 | 16 | def display 17 | x = sin(angle.x) * amplitude.x 18 | y = sin(angle.y) * amplitude.y 19 | push_matrix 20 | translate(width / 2, height / 2) 21 | stroke(0) 22 | stroke_weight(2) 23 | fill(127, 127) 24 | line(0, 0, x, y) 25 | ellipse(x, y, 32, 32) 26 | pop_matrix 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/NOC_10_03_NetworkViz.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # A static drawing of a Neural Network 6 | load_library :neural_network, :vecmath 7 | 8 | attr_reader :network 9 | 10 | def setup 11 | size 640, 360 12 | # Create the Network object 13 | @network = Network.new(width / 2, height / 2) 14 | # Create a bunch of s 15 | a = Neuron.new(-200, 0) 16 | b = Neuron.new(0, 75) 17 | c = Neuron.new(0, -75) 18 | d = Neuron.new(200, 0) 19 | # Connect them 20 | network.connect(a, b) 21 | network.connect(a, c) 22 | network.connect(b, d) 23 | network.connect(c, d) 24 | # Add them to the Network 25 | network.neurons = [a, b, c, d] 26 | end 27 | 28 | def draw 29 | background(255) 30 | # Draw the Network 31 | network.display 32 | no_loop 33 | end 34 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_6_attraction/NOC_2_6_attraction.rb: -------------------------------------------------------------------------------- 1 | # NOC_2_6_attraction 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # A class for a draggable attractive body in our world 5 | 6 | load_library :vecmath 7 | require_relative 'attractor' 8 | require_relative 'mover' 9 | 10 | attr_reader :attractor, :mover 11 | 12 | def setup 13 | size(640, 360) 14 | @mover = Mover.new 15 | @attractor = Attractor.new(width, height) 16 | end 17 | 18 | def draw 19 | background(255) 20 | force = attractor.attract(mover) 21 | mover.apply_force(force) 22 | mover.update 23 | attractor.drag 24 | attractor.hover(mouse_x, mouse_y) 25 | attractor.display 26 | mover.display 27 | end 28 | 29 | def mouse_pressed 30 | attractor.clicked(mouse_x, mouse_y) 31 | end 32 | 33 | def mouse_released 34 | attractor.stop_dragging 35 | end 36 | -------------------------------------------------------------------------------- /chp05_physicslibraries/CollisionsEqualMass/world.rb: -------------------------------------------------------------------------------- 1 | # Class provides an OO way constraining a Mover in a 2D space 2 | # use 3 | # world = World.new((0..width), (0..height)) 4 | # world.constrain_mover(mover) 5 | class World 6 | attr_reader :xrange, :yrange 7 | 8 | def initialize(xrange, yrange) 9 | @xrange, @yrange = xrange, yrange 10 | end 11 | 12 | # @param mover is expected respond to loc, vel 13 | # that in turn respond to x and y getter/setters (Vec2D does this) 14 | 15 | def constrain_mover(mover) 16 | # Note clip functionality, extends Range in ruby-processing 17 | unless xrange.cover? mover.loc.x 18 | mover.vel.x *= -1 19 | mover.loc.x = xrange.clip mover.loc.x 20 | end 21 | return if yrange.cover? mover.loc.y 22 | mover.vel.y *= -1 23 | mover.loc.y = yrange.clip mover.loc.y 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/force_directed_graph/node.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # Force directed graph 5 | # Heavily based on: http:#code.google.com/p/fidgen/ 6 | # Notice how we are using inheritance here! 7 | # We could have just stored a reference to a VerletParticle object 8 | # inside the Node class, but inheritance is a nice alternative 9 | class Node < Physics::VerletParticle2D 10 | extend Forwardable 11 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :ellipse) 12 | 13 | def initialize(pos) 14 | super(pos) 15 | @app = $app 16 | end 17 | 18 | # All we're doing really is adding a display function to a VerletParticle 19 | def display 20 | fill(50, 200, 200, 150) 21 | stroke(50, 200, 200) 22 | stroke_weight(2) 23 | ellipse(x, y, 16, 16) 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_7_attraction_many/mover.rb: -------------------------------------------------------------------------------- 1 | # NOC_2_7_attraction_many 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # A class for a draggable attractive body in our world 5 | 6 | 7 | class Mover 8 | include Processing::Proxy 9 | 10 | attr_reader :acceleration, :mass, :velocity, :location 11 | def initialize(x, y, m) 12 | @location = Vec2D.new(x, y) 13 | @velocity = Vec2D.new(1, 0) 14 | @acceleration = Vec2D.new 15 | @mass = m 16 | end 17 | 18 | def apply_force(force) 19 | @acceleration += force / mass 20 | end 21 | 22 | def update 23 | @velocity += acceleration 24 | @location += velocity 25 | @acceleration *= 0 26 | end 27 | 28 | def display 29 | stroke(0) 30 | stroke_weight(2) 31 | fill(0, 100) 32 | ellipse(location.x, location.y, mass*25, mass*25) 33 | end 34 | end 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_05_EvolutionEcosystem/evolution_ecosystem.rb: -------------------------------------------------------------------------------- 1 | # EvolutionEcoSystem 2 | # The Nature of Code 3 | # A World of creatures that eat food 4 | # The more they eat, the longer they survive 5 | # The longer they survive, the more likely they are to reproduce 6 | # The bigger they are, the easier it is to land on food 7 | # The bigger they are, the slower they are to find food 8 | # When the creatures die, food is left behind 9 | 10 | load_library :vecmath 11 | 12 | require_relative 'world' 13 | 14 | include Eco 15 | 16 | attr_reader :world 17 | 18 | def setup 19 | size(640, 360) 20 | @world = World.new(20, width, height) 21 | smooth 4 22 | end 23 | 24 | def draw 25 | background(255) 26 | world.run 27 | end 28 | 29 | def mouse_pressed 30 | world.born(mouse_x, mouse_y) 31 | end 32 | 33 | def mouse_dragged 34 | world.born(mouse_x, mouse_y) 35 | end 36 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_7_attraction_many/NOC_2_7_attraction_many.rb: -------------------------------------------------------------------------------- 1 | # NOC_2_7_attraction_many 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | load_library :vecmath 5 | require_relative 'mover' 6 | require_relative 'attractor' 7 | 8 | attr_reader :attractor, :movers 9 | 10 | def setup 11 | size(640, 360) 12 | @movers = Array.new(10) { Mover.new(rand(width), rand(height), rand(0.1 .. 2)) } 13 | @attractor = Attractor.new(width, height) 14 | end 15 | 16 | def draw 17 | background(255) 18 | attractor.display 19 | attractor.drag 20 | attractor.hover(mouse_x, mouse_y) 21 | movers.each do |m| 22 | force = attractor.attract(m) 23 | m.apply_force(force) 24 | m.update 25 | m.display 26 | end 27 | end 28 | 29 | def mouse_pressed 30 | attractor.clicked(mouse_x, mouse_y) 31 | end 32 | 33 | def mouse_released 34 | attractor.stop_dragging 35 | end 36 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_09_AdditiveBlending/particle_system.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_09_AdditiveBlending 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | require 'forwardable' 6 | require_relative 'particle' 7 | 8 | module Runnable 9 | def run 10 | reject! { |item| item.dead? } 11 | each { |item| item.run } 12 | end 13 | end 14 | 15 | class ParticleSystem 16 | include Processing::Proxy, Enumerable, Runnable 17 | extend Forwardable 18 | def_delegators(:@particles, :reject!, :<<, :each, :empty) 19 | def_delegator(:@particles, :empty?, :dead?) 20 | 21 | def initialize(num, origin) 22 | @origin = origin 23 | @img = load_image("#{Dir.pwd}/data/texture.png") 24 | @particles = Array.new(num) { Particle.new(@origin, @img) } 25 | end 26 | 27 | def add_particle(p = nil) 28 | p ||= Particle.new(@origin, @img) 29 | self << p 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/simple_cluster/node.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # 3 | # Spring 2010 4 | # Toxiclibs example: http://toxiclibs.org/ 5 | 6 | # Force directed graph 7 | # Heavily based on: http://code.google.com/p/fidgen/ 8 | 9 | # Notice how we are using inheritance here! 10 | # We could have just stored a reference to a VerletParticle object 11 | # inside the Node class, but inheritance is a nice alternative 12 | class Node < Physics::VerletParticle2D 13 | extend Forwardable 14 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :ellipse) 15 | 16 | def initialize(pos) 17 | super(pos) 18 | @app = $app 19 | end 20 | 21 | # All we're doing really is adding a :display function to a VerletParticle 22 | def display 23 | fill(0, 150) 24 | stroke(0) 25 | stroke_weight(2) 26 | ellipse(x, y, 16, 16) 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_03_ParticleSystemClass/particle.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_03_ParticleSystemClass 2 | 3 | class Particle 4 | include Processing::Proxy 5 | attr_reader :acceleration, :lifespan, :location, :velocity 6 | def initialize(location) 7 | @location = location 8 | @acceleration = Vec2D.new(0, 0.05) 9 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1 .. 0)) 10 | @lifespan = 255.0 11 | end 12 | 13 | def run 14 | update 15 | display 16 | end 17 | 18 | # Method to update location 19 | def update 20 | @velocity += acceleration 21 | @location += velocity 22 | @lifespan -= 2.0 23 | end 24 | 25 | # Method to display 26 | def display 27 | stroke(0, lifespan) 28 | stroke_weight(2) 29 | fill(127, lifespan) 30 | ellipse(location.x, location.y, 12, 12) 31 | end 32 | 33 | # Is the particle still useful? 34 | def dead? 35 | lifespan < 0.0 36 | end 37 | end 38 | 39 | 40 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_01_SingleParticle_trail/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | # A simple Particle class 5 | 6 | class Particle 7 | include Processing::Proxy 8 | 9 | attr_reader :acceleration, :lifespan, :location, :velocity 10 | 11 | def initialize(location) 12 | @acceleration = Vec2D.new(0, 0.05) 13 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1.0 .. 0)) 14 | @location = location.copy 15 | @lifespan = 255 16 | end 17 | 18 | def run 19 | update 20 | display 21 | puts 'Particle dead!' if lifespan < 0 22 | end 23 | 24 | # Method to update location 25 | def update 26 | @velocity += acceleration 27 | @location += velocity 28 | @lifespan -= 2 29 | end 30 | 31 | # Method to display 32 | def display 33 | stroke(0, lifespan) 34 | stroke_weight(2) 35 | fill(127, lifespan) 36 | ellipse(location.x, location.y, 12, 12) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_6_vector_normalize/NOC_1_6_vector_normalize.rb: -------------------------------------------------------------------------------- 1 | # NOC_1_6_vector_normalize 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | # Demonstration of normalizing a vector. 6 | # Normalizing a vector sets its length to 1. 7 | load_library :vecmath 8 | 9 | def setup 10 | size 800, 200 11 | smooth 4 12 | end 13 | 14 | def draw 15 | background(255) 16 | # A vector that points to the mouse location 17 | mouse = Vec2D.new(mouse_x, mouse_y) 18 | # A vector that points to the center of the window 19 | center = Vec2D.new(width / 2, height / 2) 20 | # Subtract center from mouse which results in a vector that points from center to mouse 21 | mouse -= center 22 | # Normalize the vector 23 | mouse.normalize! 24 | # Multiply its length by 50 25 | mouse *= 50 26 | translate(width / 2, height / 2) 27 | # Draw the resulting vector 28 | stroke(0) 29 | stroke_weight(2) 30 | line(0, 0, mouse.x, mouse.y) 31 | end 32 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_02_ArrayListParticles/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | # Simple Particle System 5 | # A simple Particle class 6 | 7 | class Particle 8 | include Processing::Proxy 9 | 10 | def initialize(location) 11 | @acceleration = Vec2D.new(0, 0.05) 12 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1 ..0)) 13 | @location = location.copy 14 | @lifespan = 255.0 15 | end 16 | 17 | def run 18 | update 19 | display 20 | end 21 | 22 | # Method to update location 23 | def update 24 | @velocity += @acceleration 25 | @location += @velocity 26 | @lifespan -= 2.0 27 | end 28 | 29 | # Method to display 30 | def display 31 | stroke(0, @lifespan) 32 | stroke_weight(2) 33 | fill(127, @lifespan) 34 | ellipse(@location.x, @location.y, 12, 12) 35 | end 36 | 37 | # Is the particle still useful? 38 | def dead? 39 | @lifespan < 0.0 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_6_attraction/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | attr_reader :acceleration, :mass, :velocity, :location 5 | def initialize 6 | @location = Vec2D.new(400, 50) 7 | @velocity = Vec2D.new(1, 0) 8 | @acceleration = Vec2D.new(0, 0) 9 | @mass = 1 10 | end 11 | 12 | def apply_force(force) 13 | @acceleration += force / mass 14 | end 15 | 16 | def update 17 | @velocity += acceleration 18 | @location += velocity 19 | @acceleration *= 0 20 | end 21 | 22 | def display 23 | stroke(0) 24 | stroke_weight(2) 25 | fill(127) 26 | ellipse(location.x, location.y, mass * 16, mass * 16) 27 | end 28 | 29 | def check_edges(width, height) 30 | if location.x > width 31 | location.x = 0 32 | elsif location.x < 0 33 | location.x = width 34 | end 35 | if location.y > height 36 | location.y = height 37 | velocity.y *= -1 38 | end 39 | end 40 | end 41 | 42 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_08_ParticleSystemSmoke_b/particle.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_08_ParticleSystemSmoke_b 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | class Particle 6 | include Processing::Proxy 7 | attr_reader :lifespan 8 | def initialize(loc, vel, img) 9 | @loc = loc.copy 10 | @img = img 11 | @vel = vel 12 | @acc = Vec2D.new 13 | @lifespan = 100 14 | end 15 | 16 | def run 17 | update 18 | render 19 | end 20 | 21 | def apply_force(force) 22 | @acc += force 23 | end 24 | 25 | def update 26 | @vel += @acc 27 | @loc += @vel 28 | @lifespan -= 2.5 29 | @acc *= 0 30 | end 31 | 32 | def render 33 | image_mode(CENTER) 34 | tint(255, lifespan) 35 | image(@img, @loc.x, @loc.y) 36 | # Drawing a circle instead 37 | # fill(255, @lifespan) 38 | # no_stroke 39 | # ellipse(@loc.x, @loc.y, 10, 10) 40 | end 41 | 42 | def dead? 43 | lifespan <= 0.0 44 | end 45 | end 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /chp05_physicslibraries/CollisionsEqualMass/collisions_equal_mass.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Collisions -- Elastic, Equal Mass, Two objects only 6 | 7 | # Based off of Chapter 9: Resolving Collisions 8 | # Mathematics and Physics for Programmers by Danny Kodicek 9 | 10 | # A Thing class for idealized collisions 11 | 12 | load_library :vecmath 13 | require_relative 'mover' 14 | 15 | attr_reader :a, :b, :show_vectors 16 | 17 | def setup 18 | size(200, 200) 19 | @a = Mover.new(self, Vec2D.new(rand(5.0), rand(-5..5.0)), Vec2D.new(10, 10)) 20 | @b = Mover.new(self, Vec2D.new(-2, 1), Vec2D.new(150, 150)) 21 | @show_vectors = true 22 | end 23 | 24 | def draw 25 | background 255 26 | a.go 27 | b.go 28 | # Note this function will ONLY WORK with two objects 29 | # Needs to be revised in the case of an array of objects 30 | a.collide_equal_mass(b) 31 | end 32 | 33 | def mouse_pressed 34 | @show_vectors = !show_vectors 35 | end 36 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_09_AdditiveBlending/particle.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_09_AdditiveBlending 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | class Particle 6 | include Processing::Proxy 7 | attr_reader :acceleration, :lifespan, :location, :velocity 8 | 9 | def initialize(location, img) 10 | @acceleration = Vec2D.new(0, 0.05) 11 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1.0 .. 0)) 12 | @velocity *= 2 13 | @location = location.copy 14 | @img = img 15 | @lifespan = 255.0 16 | end 17 | 18 | def run 19 | update 20 | render 21 | end 22 | 23 | # Method to update location 24 | def update 25 | @velocity += acceleration 26 | @location += velocity 27 | @lifespan -= 2.0 28 | end 29 | 30 | # Method to display 31 | def render 32 | image_mode(CENTER) 33 | tint(lifespan) 34 | image(@img, location.x, location.y) 35 | end 36 | 37 | # Is the particle still useful? 38 | def dead? 39 | lifespan < 0.0 40 | end 41 | end 42 | 43 | 44 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_04_PolarToCartesian_trail/NOC_3_04_PolarToCartesian_trail.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_04_PolarToCartesian_trail 2 | # PolarToCartesian 3 | # by Daniel Shiffman. 4 | # 5 | # Convert a polar coordinate (r,theta) to cartesian (x,y): 6 | # x = r * cos(theta) 7 | # y = r * sin(theta) 8 | 9 | def setup 10 | size 800, 200 11 | background 255 12 | # Initialize all values 13 | @r = height * 0.45 14 | @theta = 0 15 | end 16 | 17 | def draw 18 | #background(255) 19 | no_stroke 20 | fill 255, 5 21 | rect(0, 0, width, height) 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 | x = @r * cos(@theta) 28 | y = @r * sin(@theta) 29 | 30 | # Draw the ellipse at the cartesian coordinate 31 | ellipse_mode(CENTER) 32 | fill 127 33 | stroke(0) 34 | stroke_weight(2) 35 | line(0, 0, x, y) 36 | ellipse(x, y, 48, 48) 37 | 38 | # Increase the angle over time 39 | @theta += 0.02 40 | end 41 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_8_mutual_attraction/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | attr_reader :acceleration, :mass, :velocity, :location 5 | G = 0.4 6 | 7 | def initialize(x, y, m) 8 | @location = Vec2D.new(x, y) 9 | @velocity = Vec2D.new(0, 0) 10 | @acceleration = Vec2D.new(0, 0) 11 | @mass = m 12 | end 13 | 14 | def apply_force(force) 15 | @acceleration += force / mass 16 | end 17 | 18 | def update 19 | @velocity += acceleration 20 | @location += velocity 21 | @acceleration *= 0 22 | end 23 | 24 | def display 25 | stroke(0) 26 | stroke_weight(2) 27 | fill(0, 100) 28 | ellipse(location.x, location.y, mass * 24, mass * 24) 29 | end 30 | 31 | def attract(mover) 32 | force = location - mover.location 33 | distance = force.mag 34 | distance = constrain(distance, 5.0, 25.0) 35 | force.normalize! 36 | strength = (G * mass * mass) / (distance * distance) 37 | force *= strength 38 | force 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_06_ParticleSystemForces/particle.rb: -------------------------------------------------------------------------------- 1 | class Particle 2 | include Processing::Proxy 3 | attr_reader :acceleration, :lifespan, :location, :velocity 4 | 5 | def initialize(location) 6 | @acceleration = Vec2D.new(0, 0) 7 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-2 .. 0)) 8 | @location = location.copy 9 | @lifespan = 255.0 10 | @mass = 1 11 | end 12 | 13 | def run 14 | update 15 | display 16 | end 17 | 18 | def apply_force(force) 19 | f = force / @mass 20 | @acceleration += f 21 | end 22 | 23 | # Method to update location 24 | def update 25 | @velocity += acceleration 26 | @location += velocity 27 | @acceleration *= 0 28 | @lifespan -= 2.0 29 | end 30 | 31 | # Method to display 32 | def display 33 | stroke(0, lifespan) 34 | stroke_weight(2) 35 | fill(127, lifespan) 36 | ellipse(location.x, location.y, 12, 12) 37 | end 38 | 39 | # Is the particle still useful? 40 | def dead? 41 | lifespan < 0.0 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_10_motion101_acceleration/NOC_1_10_motion101_acceleration.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | class Mover 7 | def initialize(width, height) 8 | @location = Vec2D.new(rand(width/2.0), rand(height/2.0)) 9 | @velocity = Vec2D.new(0, 0) 10 | @topspeed = 6 11 | end 12 | 13 | def update 14 | mouse = Vec2D.new(mouse_x, mouse_y) 15 | acceleration = mouse - @location 16 | acceleration.normalize! 17 | acceleration *= 0.2 18 | @velocity += acceleration 19 | @velocity.set_mag(@topspeed) {@velocity.mag > @topspeed} 20 | @location += @velocity 21 | end 22 | 23 | def display 24 | stroke(0) 25 | stroke_weight(2) 26 | fill(127) 27 | ellipse(@location.x, @location.y, 48, 48) 28 | end 29 | end 30 | 31 | # NOC_1_10_motion101_acceleration 32 | def setup 33 | size(800, 200) 34 | @mover = Mover.new(width, height) 35 | end 36 | 37 | def draw 38 | background(255) 39 | @mover.update 40 | @mover.display 41 | end 42 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_07_ParticleSystemForcesRepeller/particle.rb: -------------------------------------------------------------------------------- 1 | class Particle 2 | include Processing::Proxy 3 | 4 | attr_reader :acceleration, :lifespan, :location, :velocity 5 | 6 | def initialize(loc) 7 | @acceleration = Vec2D.new(0, 0) 8 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-2.0 ... 0)) 9 | @location = loc.copy 10 | @lifespan = 255 11 | @mass = 1 12 | end 13 | 14 | def run 15 | update 16 | display 17 | end 18 | 19 | def apply_force(force) 20 | f = force / @mass 21 | @acceleration += f 22 | end 23 | 24 | # Method to update location 25 | def update 26 | @velocity += acceleration 27 | @location += velocity 28 | @acceleration *= 0 29 | @lifespan -= 2 30 | end 31 | 32 | # Method to display 33 | def display 34 | stroke(0, lifespan) 35 | stroke_weight(2) 36 | fill(127, lifespan) 37 | ellipse(location.x, location.y, 12, 12) 38 | end 39 | 40 | # Is the particle still useful? 41 | def dead? 42 | lifespan < 0.0 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_1_forces/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | def initialize 5 | @location = Vec2D.new(30, 30) 6 | @velocity = Vec2D.new 7 | @acceleration = Vec2D.new 8 | @mass = 1 9 | end 10 | 11 | def apply_force(force) 12 | @acceleration += force / @mass 13 | end 14 | 15 | def update 16 | @velocity += @acceleration 17 | @location += @velocity 18 | @acceleration *= 0 19 | end 20 | 21 | def display 22 | stroke(0) 23 | stroke_weight(2) 24 | fill(127) 25 | ellipse(@location.x, @location.y, 48, 48) 26 | end 27 | 28 | def check_edges(width, height) 29 | if @location.x > width 30 | @location.x = width 31 | @velocity.x *= -1 32 | elsif @location.x < 0 33 | @location.x = 0 34 | @velocity.x *= -1 35 | end 36 | 37 | if @location.y > height 38 | @location.y = height 39 | @velocity.y *= -1 40 | elsif @location.y < 0 41 | @location.y = 0 42 | @velocity.y *= -1 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_07_ParticleSystemForcesRepeller/repeller.rb: -------------------------------------------------------------------------------- 1 | class Repeller 2 | include Processing::Proxy 3 | 4 | G = 100 5 | attr_reader :location 6 | def initialize(x, y) 7 | @location = Vec2D.new(x, y) 8 | end 9 | 10 | def display 11 | stroke(0) 12 | stroke_weight(2) 13 | fill(175) 14 | ellipse(location.x, location.y, 48, 48) 15 | end 16 | 17 | def repel(particle) 18 | dir = location - particle.location # Calculate direction of force 19 | d = dir.mag # Distance between objects 20 | dir.normalize! # Normalize vector (distance doesn't matter here, we just want this vector for direction) 21 | d = constrain(d, 5.0, 100.0) # Keep distance within a reasonable range of float 22 | force = -1 * G / (d * d) # Repelling force is inversely proportional to distance 23 | dir *= force # Get force vector --> magnitude * direction 24 | dir 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/lib/boundary.rb: -------------------------------------------------------------------------------- 1 | CENTER ||= Java::ProcessingCore::PConstants::CENTER 2 | # The boundary class is used to create a floor in this 3 | # sketch. Note it does not have a change method 4 | class Boundary 5 | attr_reader :box2d, :x, :y, :w, :h, :b 6 | def initialize(b2d, x, y, w, h) 7 | @box2d, @x, @y, @w, @h = b2d, x, y, w, h 8 | sd = PolygonShape.new 9 | box2d_w = box2d.scale_to_world(w / 2) 10 | box2d_h = box2d.scale_to_world(h / 2) 11 | sd.set_as_box(box2d_w, box2d_h) 12 | # Create the body 13 | bd = BodyDef.new 14 | bd.type = BodyType::STATIC 15 | bd.position.set(box2d.processing_to_world(x, y)) 16 | @b = box2d.create_body(bd) 17 | # Attached the shape to the body using a Fixture 18 | b.create_fixture(sd, 1) 19 | b.set_user_data(self) 20 | end 21 | 22 | # Draw the boundary, if it were at an angle we'd have to do something fancier 23 | def display(app) 24 | app.fill(0) 25 | app.stroke(0) 26 | app.rect_mode(CENTER) 27 | app.rect(x, y, w, h) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/revolute_joint/revolute_joint.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Example demonstrating revolute joint 6 | require 'pbox2d' 7 | require_relative 'windmill' 8 | require_relative 'particle' 9 | 10 | attr_reader :box2d, :windmill, :particles 11 | 12 | def setup 13 | size(640,360) 14 | @box2d = Box2D.new(self) 15 | box2d.createWorld 16 | @windmill = Windmill.new(width / 2, 175) 17 | @particles = [] 18 | end 19 | 20 | # Click the mouse to turn on or off the motor 21 | def mouse_pressed 22 | windmill.toggle_motor 23 | end 24 | 25 | def draw 26 | background(255) 27 | if rand < 0.1 28 | sz = rand(4.0..8) 29 | particles << Particle.new(rand(width / 2 - 100..width / 2 + 100), -20, sz) 30 | end 31 | particles.each(&:display) 32 | particles.reject!(&:done?) 33 | # Draw the windmill 34 | windmill.display 35 | status = windmill.motor_on? ? "ON" : "OFF" 36 | fill(0) 37 | text(format("Click mouse to toggle motor.\nMotor: %s", status), 10, height - 30) 38 | end 39 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_02_forces_angular_motion/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | attr_reader :location, :mass 4 | 5 | def initialize(m, x, y) 6 | @mass = m 7 | @location = Vec2D.new(x,y) 8 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1.0 .. 1)) 9 | @acceleration = Vec2D.new(0, 0) 10 | @angle = 0 11 | @a_velocity = 0 12 | @a_acceleration = 0 13 | end 14 | 15 | def apply_force(force) 16 | f = force / @mass 17 | @acceleration += f 18 | end 19 | 20 | def update 21 | @velocity += @acceleration 22 | @location += @velocity 23 | @a_acceleration = @acceleration.x / 10.0 24 | @a_velocity += @a_acceleration 25 | @a_velocity = constrain(@a_velocity, -0.1, 0.1) 26 | @angle += @a_velocity 27 | @acceleration *= 0 28 | end 29 | 30 | def display 31 | stroke(0) 32 | fill(175, 200) 33 | rect_mode(CENTER) 34 | push_matrix 35 | translate(@location.x, @location.y) 36 | rotate(@angle) 37 | rect(0, 0, @mass * 16, @mass * 16) 38 | pop_matrix 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/liquidy.rb: -------------------------------------------------------------------------------- 1 | require 'pbox2d' 2 | require_relative 'lib/particle_system' 3 | attr_reader :box2d, :boundaries, :systems 4 | 5 | def setup 6 | size(400,300) 7 | @box2d = Box2D.new(self) 8 | box2d.init_options(gravity: [0, -20]) 9 | box2d.create_world 10 | # to set a custom gravity otherwise 11 | # box2d.gravity([0, -20]) 12 | # Create Arrays 13 | @systems = [] 14 | @boundaries = [] 15 | # Add a bunch of fixed boundaries 16 | boundaries << Boundary.new(box2d, 50, 100, 300, 5, -0.3) 17 | boundaries << Boundary.new(box2d, 250, 175, 300, 5, 0.5) 18 | end 19 | 20 | def draw 21 | background(255) 22 | # Run all the particle systems 23 | if systems.size > 0 24 | systems.each do |system| 25 | system.run 26 | system.add_particles(box2d, rand(0..2)) 27 | end 28 | end 29 | # Display all the boundaries 30 | boundaries.each(&:display) 31 | end 32 | 33 | def mouse_pressed 34 | # Add a new Particle System whenever the mouse is clicked 35 | systems << ParticleSystem.new(box2d, 0, mouse_x, mouse_y) 36 | end 37 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_2_forces_many/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | def initialize(mass, x, y) 5 | @location = Vec2D.new(x, y) 6 | @velocity = Vec2D.new(0, 0) 7 | @acceleration = Vec2D.new(0, 0) 8 | @mass = mass 9 | end 10 | 11 | def apply_force(force) 12 | @acceleration += force / @mass 13 | end 14 | 15 | def update 16 | @velocity += @acceleration 17 | @location += @velocity 18 | @acceleration *= 0 19 | end 20 | 21 | def display 22 | stroke(0) 23 | stroke_weight(2) 24 | fill(127) 25 | ellipse(@location.x, @location.y, @mass*16, @mass*16) 26 | end 27 | 28 | def check_edges(width, height) 29 | if @location.x > width 30 | @location.x = width 31 | @velocity.x *= -1 32 | elsif @location.x < 0 33 | @location.x = 0 34 | @velocity.x *= -1 35 | end 36 | 37 | if @location.y > height 38 | @location.y = height 39 | @velocity.y *= -1 40 | elsif @location.y < 0 41 | @location.y = 0 42 | @velocity.y *= -1 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /chp02_forces/Exercise_2_10_attractrepel/Exercise_2_10_attractrepel.rb: -------------------------------------------------------------------------------- 1 | # Exercise_2_10_attractrepel 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | load_library :vecmath 6 | 7 | require_relative 'attractor' 8 | require_relative 'mover' 9 | 10 | G = 1 # kind of pointless gravitational constant 11 | 12 | def setup 13 | size(800, 200) 14 | @attractor = Attractor.new(width, height) 15 | @movers = Array.new(20) { 16 | Mover.new( 17 | rand(4.0 .. 12), 18 | rand(width.to_f), 19 | rand(height.to_f) 20 | ) 21 | } 22 | end 23 | 24 | def draw 25 | background(255) 26 | @attractor.display 27 | @movers.each do |m| 28 | @movers.each do |mm| 29 | next if m.equal? mm 30 | force = mm.repel(m) 31 | m.apply_force(force) 32 | end 33 | force = @attractor.attract(m) 34 | m.apply_force(force) 35 | m.update 36 | m.display 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/NOC_10_04_NetworkAnimation.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http:#natureofcode.com 4 | # An animated drawing of a Neural Network 5 | load_libraries :vecmath, :neural_network 6 | 7 | attr_reader :network 8 | 9 | def setup 10 | size(640, 360) 11 | # Create the Network object 12 | @network = Network.new(width / 2, height / 2) 13 | # Create a bunch of Neurons 14 | a = Neuron.new(-275, 0) 15 | b = Neuron.new(-150, 0) 16 | c = Neuron.new(0, 75) 17 | d = Neuron.new(0, -75) 18 | e = Neuron.new(150, 0) 19 | f = Neuron.new(275, 0) 20 | # Connect them 21 | network.connect(a, b, 1.0) 22 | network.connect(b, c, rand) 23 | network.connect(b, d, rand) 24 | network.connect(c, e, rand) 25 | network.connect(d, e, rand) 26 | network.connect(e, f, 1.0) 27 | # Add them to the Network 28 | network.neurons = [a, b, c, d, e, f] 29 | end 30 | 31 | def draw 32 | background(255) 33 | # Update and display the Network 34 | network.update 35 | network.display 36 | # Every 30 frames feed in an input 37 | network.feedforward(rand) if (frame_count % 30 == 0) 38 | end 39 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_3_forces_many_realgravity/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | attr_reader :mass 5 | def initialize(mass, x, y) 6 | @location = Vec2D.new(x, y) 7 | @velocity = Vec2D.new(0, 0) 8 | @acceleration = Vec2D.new(0, 0) 9 | @mass = mass 10 | end 11 | 12 | def apply_force(force) 13 | @acceleration += force / @mass 14 | end 15 | 16 | def update 17 | @velocity += @acceleration 18 | @location += @velocity 19 | 20 | @acceleration *= 0 21 | end 22 | 23 | def display 24 | stroke(0) 25 | stroke_weight(2) 26 | fill(127) 27 | ellipse(@location.x, @location.y, @mass * 16, @mass * 16) 28 | end 29 | 30 | def check_edges(width, height) 31 | if @location.x > width 32 | @location.x = width 33 | @velocity.x *= -1 34 | elsif @location.x < 0 35 | @location.x = 0 36 | @velocity.x *= -1 37 | end 38 | 39 | if @location.y > height 40 | @location.y = height 41 | @velocity.y *= -1 42 | elsif @location.y < 0 43 | @location.y = 0 44 | @velocity.y *= -1 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/library/neural_network/lib/static_network.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | class StaticNetwork 6 | include Processing::Proxy 7 | attr_reader :neurons, :location 8 | 9 | def initialize(layers, inputs, _outputs) 10 | @location = Vec2D.new($app.width / 2, $app.height / 2) 11 | @neurons = [] 12 | output = Neuron.new(250, 0) 13 | layers.times do |i| 14 | inputs.times do |j| 15 | x = map1d(i, (0 .. layers), (-200 .. 200)) 16 | y = map1d(j, (0 .. inputs-1), (-100 .. 100)) 17 | puts "#{j} #{y}" 18 | n = Neuron.new(x, y) 19 | if i > 0 20 | inputs.times do |k| 21 | prev = neurons[neurons.size - inputs + k - j] 22 | prev.join(n) 23 | end 24 | end 25 | n.join(output) if (i == layers - 1) 26 | neurons << n 27 | end 28 | end 29 | neurons << output 30 | end 31 | 32 | def display 33 | push_matrix 34 | translate(location.x, location.y) 35 | neurons.each { |n| n.display } 36 | pop_matrix 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_7_motion101/NOC_1_7_motion101.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | class Mover 7 | attr_reader :location 8 | def initialize(width, height) 9 | @location = Vec2D.new(rand(0 .. width), rand(0 .. height)) 10 | @velocity = Vec2D.new(rand(-2.0 .. 2.0), rand(-2.0 .. 2.0)) 11 | end 12 | 13 | def update 14 | @location += @velocity 15 | end 16 | 17 | def display 18 | stroke(0) 19 | stroke_weight(2) 20 | fill(127) 21 | ellipse(location.x, location.y, 48, 48) 22 | end 23 | 24 | def check_edges(width, height) 25 | if location.x > width 26 | location.x = 0 27 | elsif location.x < 0 28 | location.x = width 29 | end 30 | if location.y > height 31 | location.y = 0 32 | elsif location.y < 0 33 | location.y = height 34 | end 35 | end 36 | end 37 | 38 | # NOC_1_7_motion101 39 | attr_reader :mover 40 | 41 | def setup 42 | size(800, 200) 43 | @mover = Mover.new(width, height) 44 | end 45 | 46 | def draw 47 | background(255) 48 | mover.update 49 | mover.check_edges(width, height) 50 | mover.display 51 | end 52 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_11_motion101_acceleration_array/NOC_1_11_motion101_acceleration_array.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | # NOC_1_11_motion101_acceleration_array 4 | 5 | load_library :vecmath 6 | 7 | class Mover 8 | TOP_SPEED = 6 9 | attr_reader :location, :velocity, :topspeed_squared 10 | 11 | def initialize(width, height) 12 | @location = Vec2D.new(rand(width/2.0), rand(height/2.0)) 13 | @velocity = Vec2D.new(0, 0) 14 | end 15 | 16 | def update 17 | mouse = Vec2D.new(mouse_x, mouse_y) 18 | acceleration = mouse - location 19 | acceleration.normalize! 20 | acceleration *= 0.2 21 | @velocity += acceleration 22 | velocity.set_mag(TOP_SPEED) {velocity.mag > TOP_SPEED} 23 | @location += velocity 24 | end 25 | 26 | def display 27 | stroke(0) 28 | stroke_weight(2) 29 | fill(127) 30 | ellipse(location.x, location.y, 48, 48) 31 | end 32 | end 33 | 34 | def setup 35 | size(800, 200) 36 | @movers = Array.new(20) { Mover.new(width, height) } 37 | end 38 | 39 | def draw 40 | background(255) 41 | @movers.each do |mover| 42 | mover.update 43 | mover.display 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/distance_joint/distance_joint.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Example demonstrating distance joints 6 | # A bridge is formed by connected a series of particles with joints 7 | 8 | require 'pbox2d' 9 | require 'forwardable' 10 | require_relative 'boundary' 11 | require_relative 'pair' 12 | require_relative 'particle' 13 | require_relative 'particle_system' 14 | 15 | attr_reader :box2d, :boundaries, :system 16 | 17 | def setup 18 | size(640, 360) 19 | # Initialize box2d physics and create the world 20 | @box2d = Box2D.new(self) 21 | box2d.create_world 22 | @system = ParticleSystem.new 23 | @boundaries = [] 24 | # Add a bunch of fixed boundaries 25 | boundaries << Boundary.new(width / 4, height - 5, width / 2 - 50, 10) 26 | boundaries << Boundary.new(3 * width / 4, height - 50, width / 2 - 50, 10) 27 | end 28 | 29 | def draw 30 | background(255) 31 | system.run 32 | # Display all the boundaries 33 | boundaries.each(&:display) 34 | fill(0) 35 | text('Click mouse to add connected particles.', 10, 20) 36 | end 37 | 38 | def mouse_pressed 39 | system.add_pair(mouse_x, mouse_y) 40 | end 41 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/liquid_fun_test.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # Basic example of falling rectangles 5 | 6 | require 'pbox2d' 7 | require_relative 'lib/box' 8 | 9 | attr_reader :boxes, :boundaries, :box2d 10 | 11 | def setup 12 | size(640, 360, P2D) 13 | @box2d = Box2D.new(self) 14 | box2d.init_options(gravity: [0, -10]) 15 | box2d.create_world 16 | @boundaries = [] 17 | @boxes = [] 18 | box2d.world.set_particle_radius(0.15) 19 | box2d.world.set_particle_damping(0.2) 20 | boundaries << Boundary.new(box2d, width / 4, height - 5, width / 2 - 50, 10) 21 | boundaries << Boundary.new(box2d, 3 * width / 4, height - 50, width / 2 - 50, 10) 22 | end 23 | 24 | def mouse_pressed 25 | boxes << Box.new(box2d, mouse_x, mouse_y) 26 | end 27 | 28 | def draw 29 | background(255) 30 | boundaries.each(&:display) 31 | pos_buffer = box2d.world.particle_position_buffer 32 | return if pos_buffer.nil? 33 | stroke(0) 34 | stroke_weight(2) 35 | pos_buffer.each do |buf| 36 | pos = box2d.world_to_processing(buf) 37 | point(pos.x, pos.y) 38 | end 39 | fill(0) 40 | text("f.p.s #{frame_rate.to_i}", 10, 60) 41 | end 42 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/library/neural_network/lib/network.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # An animated drawing of a Neural Network 5 | 6 | class Network 7 | include Processing::Proxy 8 | attr_accessor :neurons # this accessor is used to add neurons 9 | attr_reader :connections, :location 10 | 11 | def initialize(x, y) 12 | @location = Vec2D.new(x, y) 13 | @connections = [] 14 | end 15 | 16 | # We can connection two Neurons 17 | def connect(a, b, weight = 0.5) 18 | c = Connection.new(a, b, weight) 19 | a.join(c) 20 | # Also add them to the network 21 | connections << c 22 | end 23 | 24 | # Sending an input to the first Neuron 25 | # We should do something better to track multiple inputs 26 | def feedforward(input) 27 | start = neurons.first 28 | start.feedforward(input) 29 | end 30 | 31 | # Update the animation 32 | def update 33 | connections.each { |c| c.update } 34 | end 35 | 36 | # Draw everything 37 | def display 38 | push_matrix 39 | translate(location.x, location.y) 40 | neurons.each { |n| n.display } 41 | connections.each { |c| c.display } 42 | pop_matrix 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_4_forces_friction/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | attr_reader :acceleration, :location, :mass, :velocity 5 | def initialize(mass, x, y) 6 | @location = Vec2D.new(x, y) 7 | @velocity = Vec2D.new 8 | @acceleration = Vec2D.new 9 | @mass = mass 10 | end 11 | 12 | def apply_force(force) 13 | @acceleration += force / mass 14 | end 15 | 16 | def apply_forces(*forces) 17 | force = forces.reduce(:+) 18 | apply_force(force) 19 | end 20 | 21 | def update 22 | @velocity += acceleration 23 | @location += velocity 24 | @acceleration *= 0 25 | end 26 | 27 | def display 28 | stroke(0) 29 | stroke_weight(2) 30 | fill(0, 127) 31 | ellipse(location.x, location.y, mass * 16, mass * 16) 32 | end 33 | 34 | def check_edges(width, height) 35 | if location.x > width 36 | @location.x = width 37 | @velocity.x *= -1 38 | elsif location.x < 0 39 | @location.x = 0 40 | @velocity.x *= -1 41 | end 42 | if location.y > height 43 | @location.y = height 44 | @velocity.y *= -1 45 | elsif location.y < 0 46 | @location.y = 0 47 | @velocity.y *= -1 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_4_forces_nofriction/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | 4 | attr_reader :acceleration, :location, :mass, :velocity 5 | def initialize(mass, x, y) 6 | @location = Vec2D.new(x, y) 7 | @velocity = Vec2D.new 8 | @acceleration = Vec2D.new 9 | @mass = mass 10 | end 11 | 12 | def apply_force(force) 13 | @acceleration += force / mass 14 | end 15 | 16 | def apply_forces(*forces) 17 | force = forces.reduce(:+) 18 | apply_force(force) 19 | end 20 | 21 | def update 22 | @velocity += acceleration 23 | @location += velocity 24 | @acceleration *= 0 25 | end 26 | 27 | def display 28 | stroke(0) 29 | stroke_weight(2) 30 | fill(0, 127) 31 | ellipse(location.x, location.y, mass * 16, mass * 16) 32 | end 33 | 34 | def check_edges(width, height) 35 | if location.x > width 36 | @location.x = width 37 | @velocity.x *= -1 38 | elsif location.x < 0 39 | @location.x = 0 40 | @velocity.x *= -1 41 | end 42 | if location.y > height 43 | @location.y = height 44 | @velocity.y *= -1 45 | elsif location.y < 0 46 | @location.y = 0 47 | @velocity.y *= -1 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_03_pointing_velocity/mover.rb: -------------------------------------------------------------------------------- 1 | class Mover 2 | include Processing::Proxy 3 | attr_reader :location, :mass, :velocity, :width, :height 4 | 5 | def initialize(x, y) 6 | @width, @height = x * 2, y * 2 7 | @location = Vec2D.new(x, y) 8 | @velocity = Vec2D.new 9 | @topspeed = 4 10 | @xoff = 1_000 11 | @yoff = 0 12 | end 13 | 14 | def update 15 | mouse = Vec2D.new(mouse_x, mouse_y) 16 | dir = mouse - location 17 | dir.normalize! 18 | dir *= 0.5 19 | @velocity += dir 20 | @velocity.set_mag(@topspeed) {velocity.mag > @topspeed} 21 | @location += velocity 22 | end 23 | 24 | def display 25 | theta = velocity.heading 26 | stroke(0) 27 | stroke_weight(2) 28 | fill(127) 29 | push_matrix 30 | rect_mode(CENTER) 31 | translate(location.x, location.y) 32 | rotate(theta) 33 | rect(0, 0, 30, 10) 34 | pop_matrix 35 | end 36 | 37 | def check_edges 38 | if location.x > width 39 | location.x = 0 40 | elsif location.x < 0 41 | location.x = width 42 | end 43 | 44 | if location.y > height 45 | location.y = 0 46 | elsif location.y < 0 47 | location.y = height 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/distance_joint/boundary.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # A fixed boundary class 6 | class Boundary 7 | extend Forwardable 8 | def_delegators(:@app, :box2d, :rect_mode, :rect, :fill, :stroke) 9 | # A boundary is a simple rectangle with x, y, width, and height 10 | attr_reader :x, :y, :w, :h 11 | 12 | def initialize(x, y, w, h) 13 | @x, @y, @w, @h = x, y, w, h 14 | @app = $app 15 | # Define the polygon 16 | sd = PolygonShape.new 17 | # Figure out the box2d coordinates 18 | box2dW = box2d.scale_to_world(w / 2) 19 | box2dH = box2d.scale_to_world(h / 2) 20 | # We're just a box 21 | sd.setAsBox(box2dW, box2dH) 22 | # Create the body 23 | bd = BodyDef.new 24 | bd.type = BodyType::STATIC 25 | bd.position.set(box2d.processing_to_world(x,y)) 26 | b = box2d.createBody(bd) 27 | # Attached the shape to the body using a Fixture 28 | b.createFixture(sd,1) 29 | end 30 | 31 | # Draw the boundary, if it were at an angle we'd have to do something fancier 32 | def display 33 | fill(0) 34 | stroke(0) 35 | rect_mode(Java::ProcessingCore::PConstants::CENTER) 36 | rect(x, y, w, h) 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_08_ParticleSystemSmoke_b/particle_system.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_08_ParticleSystemSmoke_b 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | require 'forwardable' 6 | require_relative 'particle' 7 | 8 | module Runnable 9 | def run 10 | reject! { |item| item.lifespan <= 0 } 11 | each { |item| item.run } 12 | end 13 | end 14 | 15 | class ParticleSystem 16 | include Enumerable, Runnable 17 | extend Forwardable 18 | def_delegators(:@particles, :reject!, :<<, :each, :empty?) 19 | def_delegator(:@particles, :empty?, :dead?) 20 | 21 | def initialize(num, origin, img) 22 | @origin = origin.copy 23 | @img = img 24 | # avoid confusion with ruby Random 25 | @generator = Java::JavaUtil::Random.new 26 | @particles = Array.new(num) { create_particle } 27 | end 28 | 29 | def add_particle(particle = nil) 30 | particle ||= create_particle 31 | self << particle 32 | end 33 | 34 | def apply_force(f) 35 | each { |p| p.apply_force(f) } 36 | end 37 | 38 | private 39 | 40 | def create_particle 41 | vx = @generator.next_gaussian * 0.3 42 | vy = @generator.next_gaussian * 0.3 - 1 43 | vel = Vec2D.new(vx, vy) 44 | Particle.new(@origin, vel, @img) 45 | end 46 | end 47 | 48 | 49 | -------------------------------------------------------------------------------- /chp07_CA/NOC_7_01_WolframCA_simple/NOC_7_01_WolframCA_simple.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_7_01_WolframCA_simple 3 | class CA 4 | attr_reader :w, :generation 5 | def initialize(width) 6 | @w = 10 7 | @cells = Array.new(width / @w) { 0 } 8 | @cells[@cells.size / 2] = 1 9 | @ruleset = [0, 1, 0, 1, 1, 0, 1, 0] 10 | @generation = 0 11 | end 12 | 13 | def generate 14 | nextgen = Array.new(@cells.size) 15 | (1 ... @cells.size - 1).each do |i| 16 | left = @cells[i - 1] 17 | me = @cells[i] 18 | right = @cells[i + 1] 19 | nextgen[i] = rules(left, me, right) 20 | end 21 | @cells = nextgen 22 | @generation += 1 23 | end 24 | 25 | def rules(a, b, c) 26 | idx = (a.to_s + b.to_s + c.to_s).to_i(2) 27 | @ruleset[7 - idx] 28 | end 29 | 30 | def display 31 | @cells.each_index do |i| 32 | if @cells[i] == 1 33 | fill(0) 34 | else 35 | fill(255) 36 | end 37 | no_stroke 38 | rect(i * @w, @generation * @w, @w, @w) 39 | end 40 | end 41 | end 42 | 43 | def setup 44 | size(800, 400) 45 | background(255) 46 | @ca = CA.new(width) 47 | end 48 | 49 | def draw 50 | @ca.display 51 | @ca.generate if @ca.generation < height / @ca.w 52 | end 53 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_06_Tree_static/NOC_8_06_Tree_static.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_06_Tree_static 3 | # Renders a simple tree-like structure via recursion 4 | # Branching angle calculated as a function of horizontal mouse location 5 | 6 | def setup 7 | size(800, 200) 8 | smooth 9 | end 10 | 11 | def draw 12 | background(255) 13 | # Start the tree from the bottom of the screen 14 | translate(width / 2, height) 15 | stroke(0) 16 | branch(60) 17 | no_loop 18 | end 19 | 20 | def branch(len) 21 | stroke_weight(2) 22 | line(0, 0, 0, -len) 23 | # Move to the end of that line 24 | translate(0, -len) 25 | len *= 0.66 26 | # All recursive functions must have an exit condition!!!! 27 | # Here, ours is when the length of the branch is 2 pixels or less 28 | return unless len > 2 29 | push_matrix # Save the current state of transformation (i.e. where are we now) 30 | rotate(PI / 5) # Rotate by theta 31 | branch(len) # Ok, now call myself to draw two new branches!! 32 | pop_matrix # Whenever we get back here, we "pop" in order to restore the previous matrix state 33 | # Repeat the same thing, only branch off to the "left" this time! 34 | push_matrix 35 | rotate(-PI / 5) 36 | branch(len) 37 | pop_matrix 38 | end 39 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_body/blanket.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | class Blanket 5 | extend Forwardable 6 | def_delegators(:@app, :physics, :width) 7 | attr_reader :particles, :springs 8 | 9 | def initialize(app) 10 | @app = app 11 | @particles = [] 12 | @springs = [] 13 | w = 20 14 | h = 20 15 | len = 10 16 | strength = 0.125 17 | h.times do |y| 18 | w.times do |x| 19 | p = Particle.new(TVec2D.new(width / 2 + x * len - w * len / 2, y * len)) 20 | physics.addParticle(p) 21 | particles << p 22 | if x > 0 23 | previous = particles[particles.size - 2] 24 | c = Connection.new(p, previous, len, strength) 25 | physics.add_spring(c) 26 | springs << c 27 | end 28 | if y > 0 29 | above = particles[particles.size - w - 1] 30 | c = Connection.new(p, above, len, strength) 31 | physics.add_spring(c) 32 | springs << c 33 | end 34 | end 35 | end 36 | topleft = particles[0] 37 | topleft.lock 38 | topright = particles[w - 1] 39 | topright.lock 40 | end 41 | 42 | def display 43 | springs.each(&:display) 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/Exercise_10_05_LayeredNetworkAnimation.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # An animated drawing of a Neural Network 6 | load_libraries :vecmath, :neural_network 7 | 8 | attr_reader :network, :output 9 | 10 | def setup 11 | size 640, 360 12 | # Create the Network object 13 | @network = Network.new(width / 2, height / 2) 14 | layers = 3 15 | inputs = 2 16 | @output = Neuron.new 250, 0 17 | (0 ... layers).each do |i| 18 | inputs.times do |j| 19 | x = map1d(i, (0 .. layers), (-250 .. 300)) 20 | y = map1d(j, (0 .. inputs - 1), (-75 .. 75)) 21 | n = Neuron.new(x, y) 22 | if i > 0 23 | (0 ... inputs).each do |k| 24 | prev = network.neurons[network.neurons.size - inputs + k - j] 25 | network.connect(prev, n, rand) 26 | end 27 | end 28 | network.connect(n, output, rand) if (i == layers - 1) 29 | network.add_neuron(n) 30 | end 31 | end 32 | network.add_neuron(output) 33 | end 34 | 35 | def draw 36 | background 255 37 | # Update and display the Network 38 | network.update 39 | network.display 40 | # Every 30 frames feed in an input 41 | network.feedforward(rand, rand) if (frame_count % 30 == 0) 42 | end 43 | -------------------------------------------------------------------------------- /chp10_nn/xor/ext/nn/Connection.java: -------------------------------------------------------------------------------- 1 | // Daniel Shiffman 2 | // The Nature of Code, Fall 2006 3 | // Neural Network 4 | 5 | // Class to describe a connection between two neurons 6 | 7 | package nn; 8 | 9 | public class Connection { 10 | 11 | private final Neuron from; // Connection goes from. . . 12 | private final Neuron to; // To. . . 13 | private double weight; // Weight of the connection. . . 14 | 15 | // Constructor builds a connection with a random weight 16 | public Connection(Neuron a_, Neuron b_) { 17 | from = a_; 18 | to = b_; 19 | weight = Math.random()*2-1; 20 | } 21 | 22 | // In case I want to set the weights manually, using this for testing 23 | public Connection(Neuron a_, Neuron b_, double w) { 24 | from = a_; 25 | to = b_; 26 | weight = w; 27 | } 28 | 29 | public Neuron getFrom() { 30 | return from; 31 | } 32 | 33 | public Neuron getTo() { 34 | return to; 35 | } 36 | 37 | public double getWeight() { 38 | return weight; 39 | } 40 | 41 | // Changing the weight of the connection 42 | public void adjustWeight(double deltaWeight) { 43 | weight += deltaWeight; 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_01_SingleParticle/NOC_4_01_SingleParticle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | # Simple Particle System 5 | # A simple Particle class 6 | load_library :vecmath 7 | 8 | class Particle 9 | 10 | attr_reader :acceleration, :lifespan, :location, :velocity 11 | def initialize(location) 12 | @acceleration = Vec2D.new(0, 0.05) 13 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1.0 .. 1)) 14 | @location = location.copy 15 | @lifespan = 255.0 16 | end 17 | 18 | def run 19 | update 20 | display 21 | end 22 | 23 | # Method to update location 24 | def update 25 | @velocity += acceleration 26 | @location += velocity 27 | @lifespan -= 2.0 28 | end 29 | 30 | # Method to display 31 | def display 32 | stroke(0, lifespan) 33 | stroke_weight(2) 34 | fill(127, lifespan) 35 | ellipse(location.x, location.y, 12, 12) 36 | end 37 | 38 | # Is the particle still useful? 39 | def dead? 40 | lifespan < 0.0 41 | end 42 | end 43 | 44 | attr_reader :p 45 | 46 | def setup 47 | size(800, 200) 48 | @p = Particle.new(Vec2D.new(width / 2, 20)) 49 | background(255) 50 | smooth 4 51 | 52 | end 53 | 54 | def draw 55 | background(255) 56 | p.run 57 | @p = Particle.new(Vec2D.new(width / 2, 20)) if p.dead? 58 | end 59 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/polygons.rb: -------------------------------------------------------------------------------- 1 | # Basic example of falling rectangles 2 | require 'pbox2d' 3 | require_relative 'lib/custom_shape' 4 | 5 | attr_reader :box2d, :boundaries, :polygons 6 | 7 | def setup 8 | size(640, 360) 9 | smooth 10 | # Initialize box2d physics and create the world 11 | @box2d = Box2D.new(self) 12 | box2d.init_options(gravity: [0, -20]) 13 | box2d.create_world 14 | # To later set a custom gravity 15 | # box2d.gravity([0, -20] 16 | # Create Arrays 17 | @polygons = [] 18 | @boundaries = [] 19 | # Add a bunch of fixed boundaries 20 | boundaries << Boundary.new(box2d, width / 4, height - 5, width / 2 - 50, 10, 0) 21 | boundaries << Boundary.new(box2d, 3 * width / 4, height - 50, width / 2 - 50, 10, 0) 22 | boundaries << Boundary.new(box2d, width - 5, height / 2, 10, height, 0) 23 | boundaries << Boundary.new(box2d, 5, height / 2, 10, height, 0) 24 | end 25 | 26 | def draw 27 | background(255) 28 | # Display all the boundaries 29 | boundaries.each(&:display) 30 | # Display all the polygons 31 | polygons.each(&:display) 32 | # polygons that leave the screen, we delete them 33 | # (note they have to be deleted from both the box2d world and our list 34 | polygons.reject!(&:done) 35 | end 36 | 37 | def mouse_pressed 38 | polygons << CustomShape.new(box2d, mouse_x, mouse_y) 39 | end 40 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_8_motion101_acceleration/NOC_1_8_motion101_acceleration.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | class Mover 7 | attr_reader :width, :height 8 | def initialize(width, height) 9 | @width, @height = width, height 10 | @location = Vec2D.new(rand(width/2.0), rand(height/2.0)) 11 | @velocity = Vec2D.new(0, 0) 12 | @acceleration = Vec2D.new(-0.001, 0.01) 13 | @topspeed = 10 14 | end 15 | 16 | def update 17 | @velocity += @acceleration 18 | @velocity.set_mag(@topspeed) {@velocity.mag > @topspeed} 19 | @location += @velocity 20 | end 21 | 22 | def display 23 | stroke(0) 24 | stroke_weight(2) 25 | fill(127) 26 | ellipse(@location.x, @location.y, 48, 48) 27 | end 28 | 29 | def check_edges 30 | if @location.x > width 31 | @location.x = 0 32 | elsif @location.x < 0 33 | @location.x = width 34 | end 35 | if @location.y > height 36 | @location.y = 0 37 | elsif @location.y < 0 38 | @location.y = height 39 | end 40 | end 41 | end 42 | 43 | # NOC_1_8_motion101_acceleration 44 | def setup 45 | size(800, 200) 46 | @mover = Mover.new(width, height) 47 | end 48 | 49 | def draw 50 | background(255) 51 | 52 | @mover.update 53 | @mover.check_edges 54 | @mover.display 55 | end 56 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_04_Tree/NOC_8_04_Tree.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_04_Tree 3 | def setup 4 | size(300, 200) 5 | smooth 4 6 | @theta 7 | end 8 | 9 | def draw 10 | background(255) 11 | # Let's pick an angle 0 to 90 degrees based on the mouse position 12 | @theta = map1d(mouse_x, (0 .. width), (0 .. PI / 2)) 13 | 14 | # Start the tree from the bottom of the screen 15 | translate(width/2, height) 16 | stroke(0) 17 | branch(60) 18 | end 19 | 20 | def branch(len) 21 | # Each branch will be 2/3rds the size of the previous one 22 | sw = map1d(len, (2 .. 120), (1 .. 10)) 23 | stroke_weight(sw) 24 | line(0, 0, 0, -len) 25 | # Move to the end of that line 26 | translate(0, -len) 27 | len *= 0.66 28 | # All recursive functions must have an exit condition!!!! 29 | # Here, ours is when the length of the branch is 2 pixels or less 30 | return unless len > 2 31 | push_matrix # Save the current state of transformation (i.e. where are we now) 32 | rotate(@theta) # Rotate by theta 33 | branch(len) # Ok, now call myself to draw two new branches!! 34 | pop_matrix # Whenever we get back here, we "pop" in order to restore the previous matrix state 35 | # Repeat the same thing, only branch off to the "left" this time! 36 | push_matrix 37 | rotate(-@theta) 38 | branch(len) 39 | pop_matrix 40 | end 41 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/bumpy_surface_noise.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # PBox2D example 3 | # An uneven surface 4 | 5 | require 'pbox2d' 6 | require_relative 'lib/surface' 7 | 8 | attr_reader :surface, :box2d, :particles 9 | 10 | def setup 11 | size(500, 300) 12 | smooth 4 13 | # Initialize box2d physics and create the world 14 | @box2d = Box2D.new(self) 15 | box2d.init_options(gravity: [0, -20]) 16 | box2d.create_world 17 | # to later set a custom gravity 18 | # box2d.gravity([0, -20]) 19 | # Create the empty list 20 | @particles = [] 21 | # Create the surface 22 | @surface = Surface.new(box2d) 23 | end 24 | 25 | def draw 26 | # If the mouse is pressed, we make new particles 27 | # We must always step through time! 28 | background(138, 66, 54) 29 | # Draw the surface 30 | surface.display 31 | # NB ? reqd to call mouse_pressed value, else method gets called. 32 | particles << Particle.new(box2d, mouse_x, mouse_y, rand(2.0..6)) if mouse_pressed? 33 | # Draw all particles 34 | particles.each(&:display) 35 | # Particles that leave the screen, we delete them 36 | # (note they have to be deleted from both the box2d world and our list 37 | particles.reject!(&:done) 38 | # Just drawing the framerate to see how many particles it can handle 39 | fill(0) 40 | text("framerate: #{frame_rate.to_i}", 12, 16) 41 | end 42 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/library/neural_network/lib/network.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http:#natureofcode.com 4 | # An animated drawing of a Neural Network 5 | 6 | class Network 7 | include Processing::Proxy 8 | # The Network has a list of neurons 9 | attr_reader :neurons, :connections, :location 10 | 11 | def initialize(x, y) 12 | @location = Vec2D.new(x, y) 13 | @neurons = [] 14 | @connections = [] 15 | end 16 | 17 | # We can add a Neuron 18 | def add_neuron(n) 19 | neurons << n 20 | end 21 | 22 | # We can connection two Neurons 23 | def connect(a, b, weight = 0.5) 24 | c = Connection.new a, b, weight 25 | a.join c 26 | # Also add the Connection here 27 | connections << c 28 | end 29 | 30 | # Sending an input to the first Neuron 31 | # We should do something better to track multiple inputs 32 | def feedforward(input1, input2) 33 | n1 = neurons[0] 34 | n1.feedforward(input1) 35 | n2 = neurons[1] 36 | n2.feedforward(input2) 37 | end 38 | 39 | # Update the animation 40 | def update 41 | connections.each { |c| c.update } 42 | end 43 | 44 | # Draw everything 45 | def display 46 | push_matrix 47 | translate(location.x, location.y) 48 | neurons.each { |n| n.display } 49 | connections.each { |c| c.display } 50 | pop_matrix 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /chp01_vectors/NOC_1_9_motion101_acceleration/NOC_1_9_motion101_acceleration.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | load_library :vecmath 5 | 6 | class Mover 7 | attr_reader :height, :width 8 | def initialize(width, height) 9 | @width, @height = width, height 10 | @location = Vec2D.new(rand(width / 2.0), rand(height / 2.0)) 11 | @velocity = Vec2D.new(0, 0) 12 | @topspeed = 6 13 | end 14 | 15 | def update 16 | acceleration = Vec2D.new(rand, rand) 17 | acceleration *= rand(0 .. 2.0) 18 | @velocity += acceleration 19 | @velocity.set_mag(@topspeed) {@velocity.mag > @topspeed} 20 | @location += @velocity 21 | end 22 | 23 | def display 24 | stroke(0) 25 | stroke_weight(2) 26 | fill(127) 27 | ellipse(@location.x, @location.y, 48, 48) 28 | end 29 | 30 | def check_edges 31 | if @location.x > width 32 | @location.x = 0 33 | elsif @location.x < 0 34 | @location.x = width 35 | end 36 | if @location.y > height 37 | @location.y = 0 38 | elsif @location.y < 0 39 | @location.y = height 40 | end 41 | end 42 | end 43 | 44 | #NOC_1_9_motion101_acceleration 45 | def setup 46 | size(800, 200) 47 | @mover = Mover.new(width, height) 48 | end 49 | 50 | def draw 51 | background(255) 52 | @mover.update 53 | @mover.check_edges 54 | @mover.display 55 | end 56 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/library/neural_network/lib/neuron.rb: -------------------------------------------------------------------------------- 1 | # Daniel Shiffman 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # An animated drawing of a Neural Network 5 | 6 | class Neuron 7 | include Processing::Proxy 8 | # Neuron has a location 9 | attr_reader :location, :connections, :sum, :r 10 | 11 | def initialize(x, y) 12 | @sum = 0 13 | @r = 32 14 | @location = Vec2D.new(x, y) 15 | @connections = [] 16 | end 17 | 18 | # Add a Connection 19 | def join(c) 20 | connections << c 21 | end 22 | 23 | def origin 24 | location.copy 25 | end 26 | 27 | # Receive an input 28 | def feedforward(input) 29 | # Accumulate it 30 | @sum += input 31 | # Activate it? 32 | return sum unless sum > 1 33 | fire 34 | @sum = 0 # Reset the sum to 0 if it fires 35 | end 36 | 37 | # The Neuron fires 38 | def fire 39 | @r = 64 # It suddenly is bigger 40 | # We send the output through all connections 41 | connections.each { |c| c.feedforward(sum) } 42 | end 43 | 44 | # Draw it as a circle 45 | def display 46 | stroke(0) 47 | stroke_weight(1) 48 | # Brightness is mapped to sum 49 | b = map1d(sum, (0 .. 1), (255 .. 0)) 50 | fill(b) 51 | ellipse(location.x, location.y, r, r) 52 | # Size shrinks down back to original dimensions 53 | @r = lerp(r, 32, 0.1) 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/lib/box.rb: -------------------------------------------------------------------------------- 1 | # A Box class, note how to access class ParticleGroupDef in jruby 2 | # which is currently not on an included path for pbox2d 3 | class Box 4 | def initialize(b2d, x, y) 5 | w = rand(1..3) 6 | h = rand(1..3) 7 | shape = PolygonShape.new 8 | pos = b2d.processing_to_world(x, y) 9 | shape.setAsBox(w, h, pos, 0) 10 | pd = Java::OrgJbox2dParticle::ParticleGroupDef.new 11 | pd.shape = shape 12 | b2d.world.create_particle_group(pd) 13 | end 14 | end 15 | 16 | # The boundary class is used to create fixtures 17 | class Boundary 18 | include Processing::Proxy 19 | attr_reader :box2d, :x, :y, :w, :h, :b 20 | def initialize(b2d, x, y, w, h) 21 | @box2d, @x, @y, @w, @h = b2d, x, y, w, h 22 | sd = PolygonShape.new 23 | box2d_w = box2d.scale_to_world(w / 2) 24 | box2d_h = box2d.scale_to_world(h / 2) 25 | sd.setAsBox(box2d_w, box2d_h) 26 | # Create the body 27 | bd = BodyDef.new 28 | bd.type = BodyType::STATIC 29 | bd.position.set(box2d.processing_to_world(x, y)) 30 | @b = box2d.create_body(bd) 31 | # Attached the shape to the body using a Fixture 32 | b.create_fixture(sd, 1) 33 | end 34 | 35 | # Draw the boundary, if it were at an angle we'd have to do something fancier 36 | def display 37 | fill(0) 38 | stroke(0) 39 | rect_mode(CENTER) 40 | rect(x, y, w, h) 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/library/neural_network/lib/neuron.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # An animated drawing of a Neural Network 5 | 6 | class Neuron 7 | include Processing::Proxy 8 | ACTIVATION_THRESHOLD = 1.0 9 | 10 | attr_reader :connections, :location, :sum, :r 11 | 12 | def initialize(x, y) 13 | @location = Vec2D.new(x, y) 14 | @connections = [] 15 | @r = 32 16 | @sum = 0 17 | end 18 | 19 | # Add a connection to the neuron object 20 | def join(c) 21 | connections << c 22 | end 23 | 24 | # Receive an input 25 | def feedforward(input) 26 | # Accumulate it 27 | @sum += input 28 | # Activate the neuron when it reaches its threshold 29 | return sum unless sum > ACTIVATION_THRESHOLD 30 | fire 31 | @sum = 0 # On firing the resting action potential is set to 0 32 | end 33 | 34 | # The Neuron fires 35 | def fire 36 | @r = 64 # display a bigger ellipse to indicate firing 37 | # We forward the signal through all connections 38 | connections.each { |c| c.feedforward(sum) } 39 | end 40 | 41 | # Draw it as a circle 42 | def display 43 | stroke(0) 44 | stroke_weight(1) 45 | # Brightness is mapped to the accumulated action potential 46 | b = map1d(sum, (0 .. 1), (255 .. 0)) 47 | fill(b) 48 | ellipse(location.x, location.y, r, r) 49 | # Size shrinks down back to original dimensions 50 | @r = lerp(r, 32, 0.1) 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /chp10_nn/SimpleNetwork/library/neural_network/lib/connection.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # An animated drawing of a Neural Network 5 | 6 | class Connection 7 | include Processing::Proxy 8 | 9 | attr_reader :neuron_a, :neuron_b, :weight, :sending, :sender, :output 10 | 11 | def initialize(from, to, w) 12 | @weight = w 13 | @neuron_a = from 14 | @neuron_b = to 15 | @sending = false 16 | @output = 0 17 | end 18 | 19 | # The Connection is active 20 | def feedforward(val) 21 | @output = val * weight # Compute output 22 | @sender = neuron_a.location.copy # Start animation at Neuron A 23 | @sending = true # Turn on sending 24 | end 25 | 26 | # Update traveling sender 27 | def update 28 | return unless sending 29 | # Use a simple interpolation 30 | sender.lerp!(neuron_b.location, 0.1) 31 | d = sender.dist(neuron_b.location) 32 | # If we've reached the end 33 | return unless d < 1 34 | # Pass along the output! 35 | neuron_b.feedforward(output) 36 | @sending = false 37 | end 38 | 39 | # Draw line and traveling circle 40 | def display 41 | stroke(0) 42 | stroke_weight(1 + weight * 4) 43 | line(neuron_a.location.x, neuron_a.location.y, neuron_b.location.x, neuron_b.location.y) 44 | return unless sending 45 | fill(0) 46 | stroke_weight(1) 47 | ellipse(sender.x, sender.y, 16, 16) 48 | end 49 | end 50 | 51 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/simple_spring/simple_spring.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Simple Toxiclibs Spring requires 'toxiclibs gem' 6 | 7 | require 'toxiclibs' 8 | require_relative 'particle' 9 | 10 | attr_reader :physics, :p1, :p2 11 | 12 | def setup 13 | size(640, 360) 14 | # Initialize the physics 15 | @physics = Physics::VerletPhysics2D.new 16 | physics.addBehavior(Physics::GravityBehavior2D.new(TVec2D.new(0, 0.5))) 17 | # Set the world's bounding box 18 | physics.setWorldBounds(Toxi::Rect.new(0, 0, width, height)) 19 | # Make two particles 20 | @p1 = Particle.new(TVec2D.new(width / 2, 20)) 21 | @p2 = Particle.new(TVec2D.new(width / 2 + 160, 20)) 22 | # Lock one in place 23 | p1.lock 24 | # Make a spring connecting both Particles 25 | spring = Physics::VerletSpring2D.new(p1, p2, 160, 0.01) 26 | # Anything we make, we have to add into the physics world 27 | physics.addParticle(p1) 28 | physics.addParticle(p2) 29 | physics.addSpring(spring) 30 | end 31 | 32 | def draw 33 | # Update the physics world 34 | physics.update 35 | background(255) 36 | # Draw a line between the particles 37 | stroke(0) 38 | stroke_weight(2) 39 | line(p1.x, p1.y, p2.x, p2.y) 40 | # Display the particles 41 | p1.display 42 | p2.display 43 | # Move the second one according to the mouse 44 | return unless mouse_pressed? 45 | p2.lock 46 | p2.set_x mouse_x 47 | p2.set_y mouse_y 48 | p2.unlock 49 | end 50 | -------------------------------------------------------------------------------- /chp03_oscillation/AdditiveWave/AdditiveWave.rb: -------------------------------------------------------------------------------- 1 | # AdditiveWave 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | # Additive Wave 6 | # Create a more complex wave by adding two waves together. 7 | 8 | # Maybe better for this answer to be OOP??? 9 | 10 | def setup 11 | size(640, 360) 12 | colorMode(RGB, 255, 255, 255, 100) 13 | @w = width + 16 14 | @xspacing = 8 15 | @maxwaves = 5 16 | @theta = 0.0 17 | @amplitudes = Array.new(@maxwaves){ rand(10 .. 30) } 18 | @dx = Array.new(@maxwaves) do |i| 19 | period = rand(100, 300) 20 | (TWO_PI / period) * @xspacing 21 | end 22 | 23 | @yvalues = Array.new(@w/@xspacing) 24 | end 25 | 26 | def draw 27 | background(0) 28 | calc_wave 29 | render_wave 30 | end 31 | 32 | def calc_wave 33 | # Increment theta (try different values for 'angular velocity' here 34 | @theta += 0.02 35 | 36 | # Set all height values to zero 37 | @yvalues.each{ |yvalue| yvalue = 0 } 38 | 39 | # Accumulate wave height values 40 | (0...@maxwaves).each do |j| 41 | x = @theta 42 | @yvalues.each_index do |i| 43 | j % 2 == 0 ? @yvalues[i] = sin(x)*@amplitudes[j] : @yvalues[i] = cos(x) * @amplitudes[j] 44 | x += @dx[j] 45 | end 46 | end 47 | end 48 | 49 | def render_wave 50 | # A simple way to draw the wave with an ellipse at each location 51 | no_stroke 52 | fill(255, 50) 53 | ellipse_mode(CENTER) 54 | @yvalues.each_with_index do |yvalue, x| 55 | ellipse(x*@xspacing, height/2+yvalue, 16, 16) 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_03_SmartRockets/dna.rb: -------------------------------------------------------------------------------- 1 | # We only need to include Math module 2 | class DNA 3 | include Math 4 | TWO_PI = PI * 2 5 | attr_reader :genes 6 | # Constructor (makes a DNA of rand Vectors) 7 | def initialize(newgenes = nil) 8 | @maxforce = 0.1 9 | @lifetime = 400 10 | if newgenes 11 | @genes = newgenes 12 | else 13 | @genes = Array.new(@lifetime) do 14 | angle = rand(TWO_PI) 15 | gene = Vec2D.new(cos(angle), sin(angle)) 16 | gene *= rand(0...@maxforce) 17 | gene 18 | end 19 | end 20 | # Let's give each Rocket an extra boost of strength for its first frame 21 | @genes[0].normalize! 22 | end 23 | 24 | # CROSSOVER 25 | # Creates new DNA sequence from two (this & and a partner) 26 | def crossover(partner) 27 | child = Array.new(@genes.size) 28 | # Pick a midpoint 29 | crossover = rand(genes.length).to_i 30 | # Take "half" from one and "half" from the other 31 | @genes.each_with_index do |g, i| 32 | if i > crossover 33 | child[i] = g 34 | else 35 | child[i] = partner.genes[i] 36 | end 37 | end 38 | DNA.new(child) 39 | end 40 | 41 | # Based on a mutation probability, picks a new rand Vector 42 | def mutate(m) 43 | @genes.length.times do |i| 44 | next unless rand < m 45 | angle = rand(TWO_PI) 46 | @genes[i] = Vec2D.new(cos(angle), sin(angle)) 47 | @genes[i] *= rand(0...@maxforce) 48 | end 49 | @genes[0].normalize! 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/simple_cluster/cluster.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # 3 | # Spring 2010 4 | # Toxiclibs example: http://toxiclibs.org/ 5 | 6 | # Force directed graph 7 | # Heavily based on: http://code.google.com/p/fidgen/ 8 | # A cluster is a grouping of Nodes 9 | class Cluster 10 | extend Forwardable 11 | def_delegators(:@app, :physics, :stroke, :stroke_weight, :line) 12 | attr_reader :nodes, :diameter 13 | 14 | # We initialize a Cluster with a number of nodes, a diameter, and centerpoint 15 | def initialize(n, d, center) 16 | # Set the diameter 17 | @diameter, = d 18 | @app = $app 19 | # Create the nodes 20 | @nodes = (0..n).map { Node.new(center.add(TVec2D.randomVector)) } 21 | # Connect all the nodes with a Spring 22 | nodes[0..nodes.size - 2].each_with_index do |ni, i| 23 | nodes[i + 1..nodes.size - 1].each do |nj| 24 | # A Spring needs two particles, a resting length, and a strength 25 | physics.add_spring(Physics::VerletSpring2D.new(ni, nj, diameter, 0.01)) 26 | end 27 | end 28 | end 29 | 30 | def display 31 | # Show all the nodes 32 | nodes.each(&:display) 33 | end 34 | 35 | # Draw all the internal connections 36 | def show_connections 37 | stroke(0, 150) 38 | stroke_weight(2) 39 | nodes[0..nodes.size - 2].each_with_index do |pi, i| 40 | nodes[i + 1..nodes.size - 1].each do |pj| 41 | line(pi.x, pi.y, pj.x, pj.y) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /chp10_nn/LayeredNetwork/library/neural_network/lib/connection.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # An animated drawing of a Neural Network 6 | 7 | class Connection 8 | include Processing::Proxy 9 | # Connection is from A to B 10 | attr_reader :a, :b, :weight, :sending, :sender, :output 11 | 12 | def initialize(from, to, w) 13 | @weight, @a, @b = w, from, to 14 | @sending = false 15 | @sender = Vec2D.new 16 | @output = 0 17 | end 18 | 19 | # The Connection is active 20 | def feedforward(val) 21 | @output = val * weight # Compute output 22 | @sender = a.origin # Start animation at originating neuron 23 | @sending = true # Turn on sending 24 | end 25 | 26 | # Update traveling sender 27 | def update 28 | return unless sending # favour a guard clause in ruby 29 | # Use a simple interpolation 30 | sender.lerp!(b.location, 0.1) 31 | d = sender.dist(b.location) 32 | # If we've reached the end 33 | return unless d < 1 34 | # Pass along the output! 35 | b.feedforward(output) 36 | @sending = false 37 | end 38 | 39 | # Draw line and traveling circle 40 | def display 41 | stroke(0) 42 | stroke_weight(1 + weight * 4) 43 | draw_line a.location, b.location 44 | return unless sending 45 | fill(0) 46 | stroke_weight(1) 47 | ellipse(sender.x, sender.y, 16, 16) 48 | end 49 | 50 | def draw_line(a, b) 51 | line a.x, a.y, b.x, b.y 52 | end 53 | end 54 | 55 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_06_Tree/NOC_8_06_Tree.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_06_Tree 3 | # Recursive Tree 4 | # Renders a simple tree-like structure via recursion 5 | # Branching angle calculated as a function of horizontal mouse location 6 | 7 | def setup 8 | size(640, 360) 9 | end 10 | 11 | def draw 12 | background(255); 13 | # Let's pick an angle 0 to 90 degrees based on the mouse position 14 | @theta = map1d(mouse_x, (0 .. width), (0 .. PI / 2)) 15 | # Start the tree from the bottom of the screen 16 | translate(width / 2, height) 17 | stroke(0) 18 | branch(60) 19 | end 20 | 21 | def branch(len) 22 | # Each branch will be 2/3rds the size of the previous one 23 | 24 | # sw = map1d(len, (2 .. 120), (1 .. 10)) 25 | #stroke_weight(sw) 26 | stroke_weight(2) 27 | 28 | line(0, 0, 0, -len) 29 | # Move to the end of that line 30 | translate(0, -len) 31 | 32 | len *= 0.66 33 | # All recursive functions must have an exit condition!!!! 34 | # Here, ours is when the length of the branch is 2 pixels or less 35 | if len > 2 36 | push_matrix # Save the current state of transformation (i.e. where are we now) 37 | rotate(@theta) # Rotate by theta 38 | branch(len) # Ok, now call myself to draw two new branches!! 39 | pop_matrix # Whenever we get back here, we "pop" in order to restore the previous matrix state 40 | 41 | # Repeat the same thing, only branch off to the "left" this time! 42 | push_matrix 43 | rotate(-@theta) 44 | branch(len) 45 | pop_matrix 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/mouse_joint/boundary.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # A fixed boundary class (now incorporates angle) 6 | class Boundary 7 | extend Forwardable 8 | def_delegators(:@app, :fill, :no_fill, :stroke, :rect, :rect_mode, :box2d, 9 | :stroke_weight, :translate, :push_matrix, :pop_matrix, :rotate) 10 | # A boundary is a simple rectangle with x,y,width,and height 11 | attr_reader :x, :y, :w, :h, :b 12 | 13 | def initialize(x, y, w, h, a) 14 | @x, @y, @w, @h, @a = x, y, w, h, a 15 | @app = $app 16 | # Define the polygon 17 | sd = PolygonShape.new 18 | # Figure out the box2d coordinates 19 | box2dw = box2d.scale_to_world(w / 2) 20 | box2dh = box2d.scale_to_world(h / 2) 21 | # We're just a box 22 | sd.setAsBox(box2dw, box2dh) 23 | # Create the body 24 | bd = BodyDef.new 25 | bd.type = BodyType::STATIC 26 | bd.angle = a 27 | bd.position.set(box2d.processing_to_world(x, y)) 28 | @b = box2d.create_body(bd) 29 | # Attached the shape to the body using a Fixture 30 | b.create_fixture(sd, 1) 31 | end 32 | 33 | # Draw the boundary, if it were at an angle we'd have to do something fancier 34 | def display 35 | no_fill 36 | stroke(127) 37 | fill(127) 38 | stroke_weight(1) 39 | rect_mode(Java::ProcessingCore::PConstants::CENTER) 40 | a = b.get_angle 41 | push_matrix 42 | translate(x, y) 43 | rotate(-a) 44 | rect(0, 0, w, h) 45 | pop_matrix 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_08_ParticleSystemSmoke_b/NOC_4_08_ParticleSystemSmoke_b.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_08_ParticleSystemSmoke_b 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # Needs to run with jruby-complete (not system jruby) 5 | load_library :vecmath 6 | require_relative 'particle_system' 7 | 8 | attr_reader :ps 9 | 10 | def setup 11 | size(640, 360) 12 | img = load_image("#{Dir.pwd}/data/texture.png") 13 | @ps = ParticleSystem.new(0, Vec2D.new(width / 2, height - 75), img) 14 | smooth 4 15 | end 16 | 17 | def draw 18 | background(0) 19 | # Calculate a "wind" force based on mouse horizontal position 20 | dx = map1d(mouse_x, (0 .. width), (-0.2 .. 0.2)) 21 | wind = Vec2D.new(dx, 0) 22 | ps.apply_force(wind) 23 | ps.run 24 | 2.times { ps.add_particle } 25 | # Draw an arrow representing the wind force 26 | draw_vector(wind, Vec2D.new(width / 2, 50), 500) 27 | end 28 | 29 | # Renders a vector object 'v' as an arrow and a location 'loc' 30 | def draw_vector(v, loc, scayl) 31 | push_matrix 32 | arrowsize = 4 33 | # Translate to location to render vector 34 | translate(loc.x, loc.y) 35 | stroke(255) 36 | # Call vector heading function to get direction (note that pointing up is a heading of 0) and rotate 37 | rotate(v.heading) 38 | # Calculate length of vector & scale it to be bigger or smaller if necessary 39 | len = v.mag * scayl 40 | # Draw three lines to make an arrow (draw pointing up since we've rotate to the proper direction) 41 | line(0, 0, len, 0) 42 | line(len, 0, len - arrowsize, arrowsize / 2) 43 | line(len, 0, len - arrowsize, -arrowsize / 2) 44 | pop_matrix 45 | end 46 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_02_SmartRockets_superbasic/dna.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # DNA is an array of vectors 6 | class DNA 7 | include Math 8 | # The maximum strength of the forces 9 | MAX_FORCE = 0.1 10 | TWO_PI = PI * 2 11 | attr_reader :genes, :lifetime 12 | 13 | # Constructor (makes a DNA of random PVectors) 14 | def create_genes(lftm) 15 | @genes = (0...lftm).map do 16 | angle = rand(TWO_PI) 17 | Vec2D.new(cos(angle), sin(angle)) * rand(0..MAX_FORCE) 18 | end 19 | end 20 | 21 | # Constructor #2, creates the instance based on an existing array 22 | def initialize(lifetime, newgenes = nil) 23 | @lifetime = lifetime 24 | # We could make a copy if necessary 25 | # genes = (PVector []) newgenes.clone(); 26 | @genes = newgenes.nil? ? create_genes(lifetime) : newgenes.clone 27 | end 28 | 29 | # CROSSOVER 30 | # Creates new DNA sequence from two (this & and a partner) 31 | def crossover(partner) 32 | child = Array.new(genes.length, Vec2D.new) 33 | # Pick a midpoint 34 | crossover = rand(genes.length) 35 | # Take "half" from one and "half" from the other 36 | genes.length.times do |i| 37 | child[i] = (i > crossover) ? genes[i] : partner.genes[i] 38 | end 39 | DNA.new(lifetime, child) 40 | end 41 | 42 | # Based on a mutation probability, picks a new random Vector 43 | def mutate(m) 44 | genes.length.times do |i| 45 | if rand < m 46 | angle = rand(TWO_PI) 47 | genes[i] = Vec2D.new(cos(angle), sin(angle)) * rand(0..MAX_FORCE) 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /chp07_CA/NOC_7_01_WolframCA_figures/NOC_7_01_WolframCA_figures.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_7_01_WolframCA_figures 3 | class CA 4 | def initialize(r, width) 5 | @ruleset = r 6 | @scl = 20 7 | @cells = Array.new(width / @scl) 8 | @generation = 0 9 | restart 10 | end 11 | 12 | def restart 13 | @cells = Array.new(@cells.size) { 0 } 14 | @cells[@cells.size / 2] = 1 15 | @generation = 0 16 | end 17 | 18 | def randomize 19 | @ruleset = Array.new(@ruleset.size){ rand(2) } 20 | end 21 | 22 | def generate 23 | nextgen = Array.new(@cells.size) 24 | (1 ... @cells.size - 1).each do |i| 25 | left = @cells[i - 1] 26 | me = @cells[i] 27 | right = @cells[i + 1] 28 | nextgen[i] = rules(left, me, right) 29 | end 30 | @cells = nextgen 31 | @generation += 1 32 | end 33 | 34 | def rules(a, b, c) 35 | s = a.to_s + b.to_s + c.to_s 36 | @ruleset[s.to_i(2)] 37 | end 38 | 39 | def render 40 | @cells.each_index do |i| 41 | if @cells[i] == 1 42 | fill(0) 43 | else 44 | fill(255) 45 | end 46 | stroke(0) 47 | rect(i * @scl, @generation * @scl, @scl, @scl) 48 | end 49 | end 50 | 51 | def finished(height) 52 | @generation > height / @scl 53 | end 54 | end 55 | 56 | def setup 57 | size(1800, 600) 58 | background(255) 59 | ruleset = [0, 1, 1, 1, 1, 0, 1, 1] 60 | @ca = CA.new(ruleset, width) 61 | end 62 | 63 | def draw 64 | @ca.render 65 | @ca.generate 66 | if @ca.finished(height) 67 | save_frame('rule222.png') 68 | end 69 | end 70 | 71 | def mouse_pressed 72 | background(255) 73 | @ca.randomize 74 | @ca.restart 75 | end 76 | -------------------------------------------------------------------------------- /chp08_fractals/NOC_8_07_TreeStochastic/NOC_8_07_TreeStochastic.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_8_07_TreeStochastic 3 | # Stochastic Tree 4 | # Renders a simple tree-like structure via recursion 5 | # Angles and number of branches are rand 6 | 7 | def setup 8 | size(800, 200) 9 | new_tree 10 | end 11 | 12 | def draw 13 | no_loop 14 | end 15 | 16 | def mouse_pressed 17 | new_tree 18 | redraw 19 | end 20 | 21 | def new_tree 22 | background(255) 23 | fill(0) 24 | text('Click mouse to generate a new tree', 10, height - 10) 25 | stroke(0) 26 | push_matrix 27 | # Start the tree from the bottom of the screen 28 | translate(width/2, height) 29 | # Start the recursive branching! 30 | branch(80) 31 | pop_matrix 32 | end 33 | 34 | def branch(h) 35 | # thickness of the branch is mapped to its length 36 | sw = map1d(h, (2 .. 120), (1 .. 5)) 37 | stroke_weight(sw) 38 | # Draw the actual branch 39 | line(0, 0, 0, -h) 40 | # Move along to end 41 | translate(0, -h) 42 | # Each branch will be 2/3rds the size of the previous one 43 | h *= 0.66 44 | # All recursive functions must have an exit condition!!!! 45 | # Here, ours is when the length of the branch is 2 pixels or less 46 | return unless h > 2 47 | # A rand number of branches 48 | n = rand(1 .. 4) 49 | n.times do 50 | # Picking a rand angle 51 | theta = rand(-PI / 2 .. PI / 2) 52 | push_matrix # Save the current state of transformation (i.e. where are we now) 53 | rotate(theta) # Rotate by theta 54 | branch(h) # Ok, now call myself to branch again 55 | pop_matrix # Whenever we get back here, we "pop" in order to restore the previous matrix state 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /chp04_systems/NOC_4_05_ParticleSystemInheritancePolymorphism/particle.rb: -------------------------------------------------------------------------------- 1 | # NOC_4_05_ParticleSystemInheritancePolymorphism 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | class Particle 6 | include Processing::Proxy 7 | attr_reader :acceleration, :lifespan, :location, :velocity 8 | 9 | def initialize(location) 10 | @acceleration = Vec2D.new(0, 0.05) 11 | @velocity = Vec2D.new(rand(-1.0 .. 1), rand(-1 ..0)) 12 | @location = location 13 | @lifespan = 255.0 14 | end 15 | 16 | def run 17 | update 18 | display 19 | end 20 | 21 | # Method to update location 22 | def update 23 | @velocity += @acceleration 24 | @location += @velocity 25 | @lifespan -= 2.0 26 | end 27 | 28 | # Method to display 29 | def display 30 | stroke(0, @lifespan) 31 | stroke_weight(2) 32 | fill(127, @lifespan) 33 | ellipse(@location.x, @location.y, 12, 12) 34 | end 35 | 36 | # Is the particle still useful? 37 | def dead? 38 | @lifespan < 0.0 39 | end 40 | end 41 | 42 | class Confetti < Particle 43 | # NB: inherits initialize from Particle no need for super here 44 | 45 | def display 46 | rect_mode(CENTER) 47 | fill(127, lifespan) 48 | stroke(0, lifespan) 49 | stroke_weight(2) 50 | push_matrix 51 | translate(location.x, location.y) 52 | theta = map1d(location.x, (0 .. 640), (0 .. TAU * 2)) 53 | rotate(theta) 54 | rect(0, 0, 12, 12) 55 | pop_matrix 56 | end 57 | end 58 | 59 | 60 | 61 | 62 | def setup 63 | size(640, 360) 64 | @particle_system = ParticleSystem.new(Vec2D.new(width / 2, 50)) 65 | end 66 | 67 | def draw 68 | background(255) 69 | @particle_system.add_particle 70 | @particle_system.run 71 | end 72 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/simple_cluster/simple_cluster.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Force directed graph, 6 | # heavily based on: http://code.google.com/p/fidgen/ 7 | require 'forwardable' 8 | require 'toxiclibs' 9 | require_relative 'cluster' 10 | require_relative 'node' 11 | 12 | attr_reader :physics, :cluster, :f, :show_physics, :show_particles 13 | 14 | def setup 15 | size(640, 360) 16 | @f = createFont('Georgia', 12, true) 17 | @show_physics = true 18 | @show_particles = true 19 | @show_physics = true 20 | @show_particles = true 21 | # Initialize the physics 22 | @physics = Physics::VerletPhysics2D.new 23 | @physics.setWorldBounds(Toxi::Rect.new(10, 10, width - 20, height - 20)) 24 | 25 | # Spawn a new random graph 26 | @cluster = Cluster.new(8, 100, TVec2D.new(width / 2, height / 2)) 27 | end 28 | 29 | def draw 30 | # Update the physics world 31 | physics.update 32 | background(255) 33 | # Display all points 34 | cluster.display if show_particles 35 | # If we want to see the physics 36 | cluster.show_connections if show_physics 37 | # Instructions 38 | fill(0) 39 | text_font(f) 40 | text("'p' to display or hide particles\n'c' to display or hide connections\n'n' for new graph", 10, 20) 41 | end 42 | 43 | # Key press commands 44 | def key_pressed 45 | case key 46 | when 'c' 47 | @show_physics = !show_physics 48 | @show_particles = true if show_physics 49 | when 'p' 50 | @show_particles = !show_particles 51 | @show_particles = true unless show_physics 52 | when 'n' 53 | physics.clear 54 | @cluster = Cluster.new(rand(3..20), rand(10..width / 2), TVec2D.new(width / 2, height / 2)) 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_10_PendulumExampleSimplified/NOC_3_10_PendulumExampleSimplified.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_10_PendulumExampleSimplified 2 | load_library :vecmath 3 | 4 | class Pendulum 5 | attr_reader :angle, :origin, :location 6 | def initialize(origin_, r_) 7 | @origin = origin_ 8 | @location = Vec2D.new 9 | @r = r_ # length of arm 10 | @angle = PI / 4 11 | @aVelocity = 0.0 12 | @aAcceleration = 0.0 13 | @damping = 0.995 # Arbitrary damping 14 | end 15 | 16 | def go 17 | update 18 | display 19 | end 20 | 21 | def update 22 | gravity = 0.4 # Arbitrary constant 23 | # Calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html) 24 | @aAcceleration = (-1 * gravity / @r) * sin(angle) 25 | @aVelocity += @aAcceleration # Increment velocity 26 | @aVelocity *= @damping # Arbitrary damping 27 | @angle += @aVelocity # Increment angle 28 | end 29 | 30 | def display 31 | # Polar to cartesian conversion 32 | @location = Vec2D.new(@r * sin(angle), @r * cos(angle)) 33 | @location += origin # Set the location is relative to the pendulum's origin 34 | stroke(0) 35 | stroke_weight(2) 36 | # Draw the arm 37 | line(origin.x, origin.y, location.x, location.y) 38 | ellipse_mode(CENTER) 39 | fill(175) 40 | # Draw the ball 41 | ellipse(location.x, location.y, 48, 48) 42 | end 43 | end 44 | 45 | # NOC_3_10_PendulumExampleSimplified 46 | def setup 47 | size(800, 200) 48 | # Make a new Pendulum with an origin location and armlength 49 | @p = Pendulum.new(Vec2D.new(width / 2, 0), 175) 50 | smooth 4 51 | end 52 | 53 | def draw 54 | background(255) 55 | @p.go 56 | end 57 | -------------------------------------------------------------------------------- /chp02_forces/Exercise_2_10_attractrepel/mover.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | 4 | class Mover 5 | include Processing::Proxy 6 | 7 | attr_reader :location, :mass 8 | 9 | def initialize(m, x , y) 10 | @mass = m; 11 | @location = Vec2D.new(x,y) 12 | @velocity = Vec2D.new(0,0) 13 | @acceleration = Vec2D.new(0,0) 14 | end 15 | 16 | def apply_force(force) 17 | @acceleration += force / @mass 18 | end 19 | 20 | def update 21 | @velocity += @acceleration 22 | @location += @velocity 23 | @acceleration *= 0 24 | end 25 | 26 | def display 27 | stroke(0) 28 | fill(175, 200) 29 | ellipse(@location.x, @location.y, @mass * 2, @mass * 2) 30 | end 31 | 32 | def repel(mover) 33 | force = @location - mover.location # Calculate direction of force 34 | distance = force.mag # Distance between objects 35 | # Limit "extreme" results for very close or very far objects 36 | distance = constrain(distance, 1.0, 10_000.0) 37 | # Normalize we just want this vector for direction 38 | force.normalize! 39 | # Calculate gravitional force magnitude 40 | strength = (G * @mass * mover.mass) / (distance * distance) 41 | force *= -strength # Get force vector --> magnitude * direction 42 | force 43 | end 44 | 45 | def check_edges 46 | if @location.x > width 47 | @location.x = width 48 | @velocity.x *= -1 49 | elsif @location.x < 0 50 | @location.x = 0 51 | @velocity.x *= -1 52 | end 53 | 54 | if @location.y > height 55 | @location.y = height 56 | @velocity.y *= -1 57 | elsif @location.y < 0 58 | @location.y = 0 59 | @velocity.y *= -1 60 | end 61 | end 62 | end 63 | 64 | 65 | -------------------------------------------------------------------------------- /chp10_nn/xor/landscape.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http:#natureofcode.com 4 | 5 | # "Landscape" example 6 | 7 | class Landscape 8 | include Processing::Proxy 9 | 10 | attr_reader :scl, :w, :h, :rows, :cols, :z, :zoff 11 | 12 | def initialize(scl, w, h) 13 | @scl, @w, @h = scl, w, h 14 | @cols = w / scl 15 | @rows = h / scl 16 | @z = Array.new(cols, Array.new(rows, 0.0)) 17 | @zoff = 0 18 | end 19 | 20 | # Calculate height values (based off a neural network) 21 | def calculate(nn) 22 | val = ->(curr, net, x, y) { curr * 0.95 + 0.05 * (net.feed_forward([x, y]) * 280.0 - 140.0) } 23 | @z = (0 ... cols).map { |i| 24 | (0 ... rows).map { |j| 25 | val.call(z[i][j], nn, i * 1.0 / cols, j * 1.0 / cols) 26 | } 27 | } 28 | end 29 | 30 | # Render landscape as grid of quads 31 | def render 32 | # Every cell is an individual quad 33 | # (could use quad_strip here, but produces funny results, investigate this) 34 | (0 ... z.size - 1).each do |x| 35 | (0 ... z[0].size - 1).each do |y| 36 | # one quad at a time 37 | # each quad's color is determined by the height value at each vertex 38 | # (clean this part up) 39 | no_stroke 40 | push_matrix 41 | begin_shape(QUADS) 42 | translate(x * scl - w * 0.5, y * scl - h * 0.5, 0) 43 | fill(z[x][y] + 127, 220) 44 | vertex(0, 0, z[x][y]) 45 | fill(z[x + 1][y] + 127, 220) 46 | vertex(scl, 0, z[x + 1][y]) 47 | fill(z[x + 1][y + 1] + 127, 220) 48 | vertex(scl, scl, z[x + 1][y + 1]) 49 | fill(z[x][y + 1] + 127, 220) 50 | vertex(0, scl, z[x][y + 1]) 51 | end_shape 52 | pop_matrix 53 | end 54 | end 55 | end 56 | end 57 | 58 | -------------------------------------------------------------------------------- /chp03_oscillation/OOPWaveParticles/OOPWaveParticles.rb: -------------------------------------------------------------------------------- 1 | # OOPWaveParticles 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | Vect = Struct.new(:x, :y) # no fancy behaviour reqd we can use a struct here 6 | 7 | class Particle 8 | 9 | def initialize 10 | @location = Vect.new(0, 0) 11 | end 12 | 13 | def set_location(x, y) 14 | @location.x = x 15 | @location.y = y 16 | end 17 | 18 | def display 19 | fill(rand(255)) 20 | ellipse(@location.x, @location.y, 16, 16) 21 | end 22 | end 23 | 24 | class Wave 25 | 26 | def initialize(o, w_, a, p) 27 | @origin = o.dup 28 | @w = w_ 29 | @period = p 30 | @amplitude = a 31 | @xspacing = 8 32 | @dx = (TWO_PI / @period) * @xspacing 33 | @theta = 0.0 34 | @particles = Array.new(@w/@xspacing){ Particle.new } 35 | end 36 | 37 | def calculate 38 | # Increment theta (try different values for 'angular velocity' here 39 | @theta += 0.02 40 | 41 | # For every x value, calculate a y value with sine function 42 | x = @theta 43 | @particles.each_index do |i| 44 | @particles[i].set_location(@origin.x+i*@xspacing, @origin.y+sin(x)*@amplitude) 45 | x += @dx 46 | end 47 | end 48 | 49 | def display 50 | # A simple way to draw the wave with an ellipse at each location 51 | @particles.each { |p| p.display } 52 | end 53 | end 54 | 55 | def setup 56 | size(640, 360) 57 | # Initialize a wave with starting point, width, amplitude, and period 58 | @wave0 = Wave.new(Vect.new(200, 75), 100, 20, 500) 59 | @wave1 = Wave.new(Vect.new(150, 250), 300, 40, 220) 60 | end 61 | 62 | def draw 63 | background(255) 64 | 65 | # Update and display waves 66 | @wave0.calculate 67 | @wave0.display 68 | 69 | @wave1.calculate 70 | @wave1.display 71 | end 72 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_01_Seek/NOC_6_01_Seek.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_01_Seek 3 | 4 | load_library :vecmath 5 | 6 | class Vehicle 7 | attr_reader :location, :velocity, :acceleration 8 | def initialize(x, y) 9 | @acceleration = Vec2D.new 10 | @velocity = Vec2D.new(0, -2) 11 | @location = Vec2D.new(x, y) 12 | @r = 6 13 | @maxspeed = 4 14 | @maxforce = 0.1 15 | end 16 | 17 | def apply_force(force) 18 | @acceleration += force 19 | end 20 | 21 | def update 22 | @velocity += acceleration 23 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 24 | @location += velocity 25 | @acceleration *= 0 26 | end 27 | 28 | def seek(target) 29 | desired = target - location 30 | return if desired.mag < PConstants.EPSILON 31 | desired.normalize! 32 | desired *= @maxspeed 33 | steer = desired - velocity 34 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 35 | apply_force(steer) 36 | end 37 | 38 | def display 39 | theta = velocity.heading + PI / 2 40 | fill(127) 41 | stroke(0) 42 | stroke_weight(1) 43 | push_matrix 44 | translate(location.x, location.y) 45 | rotate(theta) 46 | begin_shape 47 | vertex(0, -@r * 2) 48 | vertex(-@r, @r * 2) 49 | vertex(@r, @r * 2) 50 | end_shape(CLOSE) 51 | pop_matrix 52 | end 53 | end 54 | 55 | attr_reader :seeker 56 | 57 | def setup 58 | size(640, 360) 59 | @seeker = Vehicle.new(width / 2, height / 2) 60 | end 61 | 62 | def draw 63 | background(255) 64 | mouse = Vec2D.new(mouse_x, mouse_y) 65 | fill(200) 66 | stroke(0) 67 | stroke_weight(2) 68 | ellipse(mouse.x, mouse.y, 48, 48) 69 | # Call the appropriate steering behaviors for our agents 70 | seeker.seek(mouse) 71 | seeker.update 72 | seeker.display 73 | end 74 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_body/soft_body_square_adapted.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # 5 | # This example is adapted from Karsten Schmidt's SoftBodySquare example 6 | # 7 | #

Softbody square demo is showing how to create a 2D square mesh out of 8 | # verlet particles and make it stable enough to adef total structural 9 | # deformation by including an inner skeleton.

10 | # 11 | #

Usage: move mouse to drag/deform the square

12 | # 13 | # 14 | # Copyright (c) 2008-2009 Karsten Schmidt 15 | # 16 | # This demo & library is free software you can redistribute it and/or 17 | # modify it under the terms of the GNU Lesser General Public 18 | # License as published by the Free Software Foundation either 19 | # version 2.1 of the License, or (at your option) any later version. 20 | # 21 | # http://creativecommons.org/licenses/LGPL/2.1/ 22 | # 23 | # This library is distributed in the hope that it will be useful, 24 | # but WITHOUT ANY WARRANTY without even the implied warranty of 25 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 26 | # Lesser General Public License for more details. 27 | # 28 | # You should have received a copy of the GNU Lesser General Public 29 | # License along with this library if not, write to the Free Software 30 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 31 | # 32 | require 'forwardable' 33 | require 'toxiclibs' 34 | require_relative 'blanket' 35 | require_relative 'connection' 36 | require_relative 'particle' 37 | 38 | attr_reader :b, :physics 39 | 40 | def setup 41 | size(640, 360) 42 | @physics = Physics::VerletPhysics2D.new 43 | physics.addBehavior(Physics::GravityBehavior2D.new(TVec2D.new(0, 0.1))) 44 | @b = Blanket.new(self) 45 | end 46 | 47 | def draw 48 | background(255) 49 | physics.update 50 | b.display 51 | end 52 | -------------------------------------------------------------------------------- /chp03_oscillation/Exercise_3_11_AdditiveWave/Exercise_3_11_AdditiveWave.rb: -------------------------------------------------------------------------------- 1 | # Exercise_3_11_AdditiveWave 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | # Additive Wave 6 | # Create a more complex wave by adding two waves together. 7 | 8 | def setup 9 | size(750, 200) 10 | @w = width + 16 # Width of entire wave 11 | @xspacing = 8 # How far apart should each horizontal location be spaced 12 | @maxwaves = 5 # total # of waves to add together 13 | @theta = 0.0 14 | @amplitudes = Array.new(@maxwaves) do |amplitude| # Height of wave 15 | amplitude = rand(10 .. 30) 16 | end 17 | @dx = Array.new(@maxwaves) do |x| # Value for incrementing X, to be calculated as a function of period and xspacing 18 | period = rand(100 .. 300) # How many pixels before the wave repeats 19 | (TWO_PI / period) * @xspacing 20 | end 21 | @yvalues = Array.new(@w/@xspacing) 22 | end 23 | 24 | def draw 25 | background(255) 26 | calc_wave 27 | render_wave 28 | end 29 | 30 | 31 | def calc_wave 32 | # Increment theta (try different values for 'angular velocity' here 33 | @theta += 0.02 34 | # Set all height values to zero 35 | @yvalues.each_index{ |i| @yvalues[i] = 0 } 36 | # Accumulate wave height values 37 | (0...@maxwaves).each do |j| 38 | x = @theta 39 | @yvalues.each_index do |i| 40 | # Every other wave is cosine instead of sine 41 | if j.even? 42 | @yvalues[i] += sin(x) * @amplitudes[j] 43 | else 44 | @yvalues[i] += cos(x) * @amplitudes[j] 45 | end 46 | x += @dx[j] 47 | end 48 | end 49 | end 50 | 51 | def render_wave 52 | # A simple way to draw the wave with an ellipse at each location 53 | stroke(0) 54 | fill(127, 50) 55 | ellipse_mode(CENTER) 56 | @yvalues.each_with_index { |yvalue, idx| ellipse(idx * @xspacing, height / 2 + yvalue, 48, 48) } 57 | end 58 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/revolute_joint/windmill.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | require 'forwardable' 5 | require_relative 'box' 6 | 7 | # Class to describe a fixed spinning object 8 | class Windmill 9 | extend Forwardable 10 | def_delegators(:@app, :ellipse, :no_stroke, :box2d, :fill) 11 | # Our object is two boxes and one joint 12 | # Consider making the fixed box much smaller and not drawing it 13 | attr_reader :joint, :box1, :box2 14 | 15 | def initialize(x, y) 16 | @app = $app 17 | # Initialize locations of two boxes 18 | @box1 = Box.new(x, y - 20, 120, 10, false) 19 | @box2 = Box.new(x, y, 10, 40, true) 20 | # Define joint as between two bodies 21 | rjd = RevoluteJointDef.new 22 | # NB: using java_send to access the unreachable 'initialize' method 23 | rjd.java_send :initialize, [Body, Body, Vec2], box1.body, box2.body, box1.body.getWorldCenter 24 | # Turning on a motor (optional) 25 | rjd.motorSpeed = Math::PI * 2 # how fast? 26 | rjd.maxMotorTorque = 1000.0 # how powerful? 27 | rjd.enableMotor = false # is it on? 28 | # There are many other properties you can set for a Revolute joint 29 | # For example, you can limit its angle between a minimum and a maximum 30 | # See box2d manual for more 31 | # Create the joint 32 | @joint = box2d.world.createJoint(rjd) 33 | end 34 | 35 | # Turn the motor on or off 36 | def toggle_motor 37 | joint.enableMotor(!joint.isMotorEnabled) 38 | end 39 | 40 | def motor_on? 41 | joint.isMotorEnabled 42 | end 43 | 44 | def display 45 | box2.display 46 | box1.display 47 | # Draw anchor just for debug 48 | anchor = box2d.vector_to_processing(box1.body.getWorldCenter) 49 | fill(0) 50 | no_stroke 51 | ellipse(anchor.x, anchor.y, 8, 8) 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /chp02_forces/NOC_02forces_many_mutual_boundaries/mover.rb: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Mover 4 | include Processing::Proxy 5 | 6 | G = 0.4 # gravitational constant 7 | 8 | attr_reader :acceleration, :location, :mass, :velocity 9 | 10 | def initialize(m, x, y) 11 | @mass = m 12 | @location = Vec2D.new(x, y) 13 | @velocity = Vec2D.new 14 | @acceleration = Vec2D.new 15 | end 16 | 17 | def apply_force(force) 18 | @acceleration += force / mass 19 | end 20 | 21 | def update 22 | @velocity += acceleration 23 | @location += velocity 24 | @acceleration *= 0 25 | end 26 | 27 | def display 28 | stroke(0) 29 | fill(175, 200) 30 | ellipse(location.x, location.y, mass * 16, mass * 16) 31 | end 32 | 33 | def attract(mover) 34 | force = location - mover.location # Calculate direction of force 35 | distance = force.mag # Distance between objects 36 | distance = constrain(distance, 5.0, 25.0) # Limiting the distance to eliminate "extreme" results for very close or very far objects 37 | force.normalize! # Normalize vector (distance doesn't matter here, we just want this vector for direction 38 | strength = (G * mass * mover.mass) / (distance * distance) # Calculate gravitional force magnitude 39 | force *= strength # Get force vector --> magnitude * direction 40 | end 41 | 42 | def boundaries width, height 43 | d = 50 44 | force = Vec2D.new 45 | if location.x < d 46 | force.x = 1 47 | elsif location.x > width - d 48 | force.x = -1 49 | end 50 | if location.y < d 51 | force.y = 1 52 | elsif location.y > height - d 53 | force.y = -1 54 | end 55 | force.set_mag 0.1 56 | apply_force(force) 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/mouse_joint/mouse_joint.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Basic example of controlling an object with the mouse (by attaching a spring) 6 | 7 | require 'pbox2d' 8 | require_relative 'box' 9 | require_relative 'boundary' 10 | require_relative 'spring' 11 | require_relative 'dummy_spring' 12 | require 'forwardable' 13 | 14 | # A reference to our box2d world 15 | attr_reader :box2d, :boundaries, :box, :spring 16 | 17 | def setup 18 | size(640, 360) 19 | # Initialize box2d physics and create the world 20 | @box2d = Box2D.new self 21 | box2d.create_world 22 | # Make the box 23 | @box = Box.new(width / 2, height / 2) 24 | # Make a dummy spring 25 | @spring = DummySpring.new 26 | # Add a bunch of fixed boundaries 27 | @boundaries = [] 28 | boundaries << Boundary.new(width / 2, height - 5, width, 10, 0) 29 | boundaries << Boundary.new(width / 2, 5, width, 10, 0) 30 | boundaries << Boundary.new(width - 5, height / 2, 10, height, 0) 31 | boundaries << Boundary.new(5, height / 2, 10, height, 0) 32 | end 33 | 34 | # When the mouse is released we're done with the spring 35 | def mouse_released 36 | spring.destroy 37 | @spring = DummySpring.new 38 | end 39 | 40 | # When the mouse is pressed we. . . 41 | def mouse_pressed 42 | # Check to see if the mouse was clicked on the box and if so create 43 | # a real spring and bind the mouse location to the box with a spring 44 | return unless box.contains(mouse_x, mouse_y) 45 | @spring = spring.bind(mouse_x, mouse_y, box) 46 | end 47 | 48 | def draw 49 | background(255) 50 | # Always alert the spring to the new mouse location 51 | spring.update(mouse_x, mouse_y) 52 | # Draw the boundaries 53 | boundaries.each(&:display) 54 | # Draw the box 55 | box.display 56 | # Draw the spring (it only appears when active) 57 | spring.display 58 | end 59 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_02_Arrive/NOC_6_02_Arrive.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_02_Arrive 3 | 4 | load_library :vecmath 5 | 6 | class Vehicle 7 | attr_reader :location, :velocity, :acceleration 8 | 9 | def initialize(x, y) 10 | @acceleration = Vec2D.new 11 | @velocity = Vec2D.new(0, -2) 12 | @location = Vec2D.new(x, y) 13 | @r = 6 14 | @maxspeed = 4 15 | @maxforce = 0.1 16 | end 17 | 18 | def apply_force(force) 19 | @acceleration += force 20 | end 21 | 22 | def update 23 | @velocity += acceleration 24 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 25 | @location += velocity 26 | @acceleration *= 0 27 | end 28 | 29 | def arrive(target) 30 | desired = target - location 31 | d = desired.mag 32 | 33 | if d < 100 # scale with arbitrary damping withing 100 pixels 34 | desired.set_mag(map1d(d, (0 .. 100), (0 .. @maxspeed))) 35 | else 36 | desired.set_mag(@maxspeed) 37 | end 38 | steer = desired - velocity 39 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 40 | apply_force(steer) 41 | end 42 | 43 | def display 44 | theta = velocity.heading + PI / 2 45 | fill(127) 46 | stroke(0) 47 | stroke_weight(1) 48 | push_matrix 49 | translate(location.x, location.y) 50 | rotate(theta) 51 | begin_shape 52 | vertex(0, -@r * 2) 53 | vertex(-@r, @r * 2) 54 | vertex(@r, @r * 2) 55 | end_shape(CLOSE) 56 | pop_matrix 57 | end 58 | end 59 | 60 | attr_reader :seeker 61 | 62 | def setup 63 | size(640, 360) 64 | @seeker = Vehicle.new(width / 2, height / 2) 65 | end 66 | 67 | def draw 68 | background(255) 69 | mouse = Vec2D.new(mouse_x, mouse_y) 70 | fill(200) 71 | stroke(0) 72 | stroke_weight(2) 73 | ellipse(mouse.x, mouse.y, 48, 48) 74 | # Call the appropriate steering behaviors for our agents 75 | seeker.arrive(mouse) 76 | seeker.update 77 | seeker.display 78 | end 79 | -------------------------------------------------------------------------------- /chp03_oscillation/Exercise_3_03_cannon/Exercise_3_03_cannon.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # http://natureofcode.com 3 | load_library :vecmath 4 | 5 | class CannonBall 6 | attr_reader :location 7 | 8 | def initialize(x, y) 9 | @location = Vec2D.new(x, y) 10 | @velocity = Vec2D.new 11 | @acceleration = Vec2D.new 12 | @topspeed = 10 13 | @r = 8 14 | end 15 | 16 | # Standard Euler integration 17 | def update 18 | @velocity += @acceleration 19 | @velocity.set_mag(@topspeed) {@velocity.mag > @topspeed} 20 | @location += @velocity 21 | @acceleration *= 0 22 | end 23 | 24 | def apply_force(force) 25 | @acceleration += force 26 | end 27 | 28 | def display 29 | stroke(0) 30 | stroke_weight(2) 31 | push_matrix() 32 | translate(@location.x, @location.y) 33 | ellipse(0, 0, @r * 2, @r * 2) 34 | pop_matrix 35 | end 36 | end 37 | 38 | attr_reader :angle, :location 39 | 40 | def setup 41 | size(640, 360) 42 | # All of this stuff should go into a Cannon class 43 | @angle = -PI / 4 44 | @location = Vec2D.new(50, 300) 45 | @shot = false 46 | @ball = CannonBall.new(location.x, location.y) 47 | end 48 | 49 | def draw 50 | background(255) 51 | push_matrix 52 | translate(location.x, location.y) 53 | rotate(angle) 54 | rect(0, -5, 50, 10) 55 | pop_matrix 56 | if @shot 57 | gravity = Vec2D.new(0, 0.2) 58 | @ball.apply_force(gravity) 59 | @ball.update 60 | end 61 | @ball.display 62 | if @ball.location.y > height or @ball.location.x > width 63 | @ball = CannonBall.new(location.x, location.y) 64 | @shot = false 65 | end 66 | end 67 | 68 | def key_pressed 69 | if key == CODED && key_code == RIGHT 70 | @angle += 0.1 71 | elsif key == CODED && key_code == LEFT 72 | @angle -= 0.1 73 | elsif key == ' ' 74 | @shot = true 75 | force = Vec2D.new(Math.cos(angle), Math.sin(angle)) 76 | force *= 10 77 | @ball.apply_force(force) 78 | end 79 | end 80 | -------------------------------------------------------------------------------- /chp02_forces/Exercise_2_10_attractrepel/attractor.rb: -------------------------------------------------------------------------------- 1 | class Attractor 2 | include Processing::Proxy 3 | 4 | attr_reader :mass, :location 5 | def initialize(width, height) 6 | @location = Vec2D.new(width/2, height/2) 7 | @mass = 10 8 | @drag_offset = Vec2D.new(0.0, 0.0) 9 | @dragging = false 10 | @rollover = false 11 | end 12 | 13 | def attract(mover) 14 | force = location - mover.location # Calculate direction of force 15 | d = force.mag # Distance between objects 16 | d = constrain(d, 5.0, 25.0) # Limiting the distance to eliminate "extreme" results for very close or very far objects 17 | force.normalize! # Normalize vector (distance doesn't matter here, we just want this vector for direction) 18 | strength = (G * mass * mover.mass) / (d * d) # Calculate gravitional force magnitude 19 | force *= strength # Get force vector --> magnitude * direction 20 | force 21 | end 22 | 23 | def display 24 | ellipse_mode CENTER 25 | stroke 0 26 | if @dragging 27 | fill 50 28 | elsif @rollover 29 | fill 100 30 | else 31 | fill 0 32 | end 33 | ellipse(location.x, location.y, mass * 6, mass * 6) 34 | end 35 | 36 | # The methods below are for mouse interaction 37 | def clicked(mx, my) 38 | d = dist(mx ,my, location.x, location.y) 39 | if d < @mass 40 | @dragging = true; 41 | @drag_offset.x = location.x - mx 42 | @drag_offset.y = location.y - my 43 | end 44 | end 45 | 46 | def hover(mx, my) 47 | d = dist(mx, my, location.x, location.y) 48 | @rollover = d < mass 49 | end 50 | 51 | def stop_dragging 52 | @dragging = false 53 | end 54 | 55 | def drag 56 | if @dragging 57 | @location.x = mouse_x + @drag_offset.x 58 | @location.y = mouse_y + @drag_offset.y 59 | end 60 | end 61 | end 62 | 63 | 64 | -------------------------------------------------------------------------------- /chp03_oscillation/NOC_3_09_exercise_additive_wave/NOC_3_09_exercise_additive_wave.rb: -------------------------------------------------------------------------------- 1 | # NOC_3_09_exercise_additive_wave 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | # Additive Wave 6 | # Create a more complex wave by adding two waves together. 7 | 8 | # Maybe better for this answer to be OOP??? 9 | 10 | attr_reader :dx, :amplitude, :max_waves, :y_values 11 | 12 | def setup 13 | size 640, 360 14 | @max_waves = 5 # Total number of waves to add together 15 | @wave_width = width + 16 # Width of entire wave 16 | @x_spacing = 8 # How far apart should each horizontal location be spaced 17 | @theta = 0.0 18 | @amplitude = [] # Height of wave 19 | @dx = [] # Value for incrementing X, to be calculated as a function of period and x_spacing 20 | 21 | @max_waves.times do |i| 22 | amplitude << rand(10 .. 30) 23 | period = rand(100 .. 300) # How many pixels before the wave repeats 24 | dx << (TAU / period) * @x_spacing 25 | end 26 | 27 | frame_rate 30 28 | color_mode RGB, 255, 255, 255, 100 29 | smooth 30 | end 31 | 32 | def draw 33 | background 0 34 | calculate_wave 35 | render_wave 36 | end 37 | 38 | def calculate_wave 39 | # Increment theta (try different values for 'angular velocity' here 40 | @theta += 0.02 41 | 42 | # Set all height values to zero 43 | @y_values = Array.new(@wave_width / @x_spacing, 0) 44 | 45 | # Accumulate wave height values 46 | max_waves.times do |j| 47 | x = @theta 48 | y_values.length.times do |i| 49 | # Every other wave is cosine instead of sine 50 | value = j.even? ? sin(x) : cos(x) 51 | y_values[i] += value * amplitude[j] 52 | x += dx[j] 53 | end 54 | end 55 | end 56 | 57 | def render_wave 58 | # A simple way to draw the wave with an ellipse at each location 59 | no_stroke 60 | fill 255, 50 61 | ellipse_mode CENTER 62 | y_values.each_with_index do |y, i| 63 | ellipse i * @x_spacing, height/2 + y, 16, 16 64 | end 65 | end 66 | 67 | 68 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/distance_joint/pair.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | require 'forwardable' 5 | 6 | # Series of Particles connected with distance joints 7 | class Pair 8 | extend Forwardable 9 | def_delegators(:@app, :box2d, :stroke, :line, :stroke_weight) 10 | attr_reader :p1, :p2, :len, :joint 11 | # Chain constructor 12 | def initialize(x, y) 13 | @app = $app 14 | @len = 32 15 | @p1 = Particle.new(x, y) 16 | @p2 = Particle.new(x + rand(-1..1.0), y + rand(-1..1.0)) 17 | djd = DistanceJointDef.new 18 | # Connection between previous particle and this one 19 | djd.bodyA = p1.body 20 | djd.bodyB = p2.body 21 | # Equilibrium length 22 | djd.length = box2d.scale_to_world(len) 23 | # These properties affect how springy the joint is 24 | djd.frequencyHz = 3 # Try a value less than 5 (0 for no elasticity) 25 | djd.dampingRatio = 0.1 # Ranges between 0 and 1 (1 for no springiness) 26 | # Make the joint. 27 | @joint = box2d.world.create_joint(djd) 28 | end 29 | 30 | def kill_bodies 31 | box2d.world.destroy_joint(joint) 32 | @joint = nil 33 | box2d.destroy_body(p1.body) 34 | box2d.destroy_body(p2.body) 35 | end 36 | 37 | # Is the pair ready for deletion? 38 | def done? 39 | # Let's find the screen position of the particle 40 | pos1 = box2d.body_coord(p1.body) 41 | pos2 = box2d.body_coord(p2.body) 42 | # Is it off the screen? 43 | if (0..@app.width).include?(pos1.x) || (0..@app.width).include?(pos2.x) 44 | if (0..@app.height).include?(pos1.y) || (0..@app.height).include?(pos2.y) 45 | return false 46 | end 47 | end 48 | kill_bodies 49 | return true 50 | end 51 | 52 | def display 53 | pos1 = box2d.body_coord(p1.body) 54 | pos2 = box2d.body_coord(p2.body) 55 | stroke(0) 56 | stroke_weight(2) 57 | line(pos1.x, pos1.y, pos2.x, pos2.y) 58 | p1.display 59 | p2.display 60 | end 61 | end 62 | 63 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_02_SmartRockets_superbasic/smart_rocket_basic.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http:#natureofcode.com 4 | 5 | # Smart Rockets w/ Genetic Algorithms 6 | 7 | # Each Rocket's DNA is an array of PVectors 8 | # Each PVector acts as a force for each frame of animation 9 | # Imagine an booster on the end of the rocket that can point in any direction 10 | # and fire at any strength every frame. The Rocket's fitness is a function of 11 | # how close it gets to the target as well as how fast it gets there 12 | # This example is inspired by Jer Thorp's Smart Rockets 13 | # http://www.blprnt.com/smartrockets/ 14 | load_library :vecmath 15 | require_relative 'population' 16 | require_relative 'dna' 17 | require_relative 'rocket' 18 | 19 | attr_reader :lifetime, :population, :life_counter, :target, :mutation_rate 20 | 21 | def setup 22 | size(640, 360) 23 | # The number of cycles we will allow a generation to live 24 | @lifetime = height 25 | # Initialize variables 26 | @life_counter = 0 27 | @target = Vec2D.new(width / 2, 24) 28 | # Create a population with a mutation rate, and population max 29 | @mutation_rate = 0.01 30 | @population = Population.new(mutation_rate, 50, width, height, target) 31 | end 32 | 33 | def draw 34 | background(255) 35 | # Draw the start and target locations 36 | fill(0) 37 | ellipse(target.x, target.y, 24, 24) 38 | # If the generation hasn't ended yet 39 | if life_counter < lifetime 40 | population.live 41 | @life_counter += 1 42 | # Otherwise a new generation 43 | else 44 | @life_counter = 0 45 | population.fitness 46 | population.selection 47 | population.reproduction 48 | end 49 | # Display some info 50 | fill(0) 51 | text(format('Generation #: %d', population.generations), 10, 18) 52 | text(format('Cycles left: %d', lifetime - life_counter), 10, 36) 53 | end 54 | 55 | # Move the target if the mouse is pressed 56 | # System will adapt to new target 57 | def mouse_pressed 58 | target.x = mouse_x 59 | target.y = mouse_y 60 | end 61 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/revolute_joint/box.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | require 'forwardable' 5 | 6 | # A rectangular box 7 | class Box 8 | extend Forwardable 9 | def_delegators(:@app, :push_matrix, :pop_matrix, :fill, :rotate, :box2d, 10 | :stroke_weight, :translate, :rect_mode, :stroke, :rect) 11 | # We need to keep track of a Body and a width and height 12 | attr_reader :body, :w, :h 13 | 14 | # Constructor 15 | def initialize(x, y, w, h, lock) 16 | @w, @h = w, h 17 | @app = $app 18 | # Define and create the body 19 | bd = BodyDef.new 20 | bd.position.set(box2d.processing_to_world(Vec2.new(x, y))) 21 | bd.type = lock ? BodyType::STATIC : BodyType::DYNAMIC 22 | 23 | @body = box2d.createBody(bd) 24 | 25 | # Define the shape -- a (this is what we use for a rectangle) 26 | sd = PolygonShape.new 27 | box2dW = box2d.scale_to_world(w / 2) 28 | box2dH = box2d.scale_to_world(h / 2) 29 | sd.setAsBox(box2dW, box2dH) 30 | 31 | # Define a fixture 32 | fd = FixtureDef.new 33 | fd.shape = sd 34 | # Parameters that affect physics 35 | fd.density = 1 36 | fd.friction = 0.3 37 | fd.restitution = 0.5 38 | 39 | body.createFixture(fd) 40 | 41 | # Give it some initial random velocity 42 | body.setLinearVelocity(Vec2.new(rand(-5..5),rand(2..5))) 43 | body.setAngularVelocity(rand(-5..5)) 44 | end 45 | 46 | # This function removes the particle from the box2d world 47 | def killBody 48 | box2d.destroyBody(body) 49 | end 50 | 51 | # Drawing the box 52 | def display 53 | # We look at each body and get its screen position 54 | pos = box2d.body_coord(body) 55 | # Get its angle of rotation 56 | a = body.getAngle 57 | 58 | rect_mode(Java::ProcessingCore::PConstants::CENTER) 59 | push_matrix 60 | translate(pos.x,pos.y) 61 | rotate(-a) 62 | fill(127) 63 | stroke(0) 64 | stroke_weight(2) 65 | rect(0,0,w,h) 66 | pop_matrix 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /chp05_physicslibraries/toxiclibs/soft_string/soft_string_pendulum.rb: -------------------------------------------------------------------------------- 1 | #

A soft pendulum (series of connected springs)
2 | # The Nature of Code
3 | # Spring 2010

4 | # Copyright (c) 2010 Daniel Shiffman 5 | # 6 | # This demo & library is free software you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public 8 | # License as published by the Free Software Foundation either 9 | # version 2.1 of the License, or (at your option) any later version. 10 | # 11 | # http:#creativecommons.org/licenses/LGPL/2.1/ 12 | # 13 | # This library is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | # Lesser General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU Lesser General Public 19 | # License along with this library if not, write to the Free Software 20 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 21 | 22 | require 'toxiclibs' 23 | require_relative 'particle' 24 | require_relative 'chain' 25 | 26 | attr_reader :physics, :chain 27 | 28 | def setup 29 | size(640, 360) 30 | # Initialize the physics world 31 | @physics = Physics::VerletPhysics2D.new 32 | physics.addBehavior(Physics::GravityBehavior2D.new(TVec2D.new(0, 0.1))) 33 | physics.setWorldBounds(Toxi::Rect.new(0, 0, width, height)) 34 | 35 | # Initialize the chain 36 | @chain = Chain.new(physics, 180, 20, 16, 0.2) 37 | end 38 | 39 | def draw 40 | background(255) 41 | # Update physics 42 | physics.update 43 | # Update chain's tail according to mouse location 44 | chain.update_tail(mouse_x, mouse_y) 45 | # Display chain 46 | chain.display 47 | end 48 | 49 | def mouse_pressed 50 | # Check to see if we're grabbing the chain 51 | chain.contains(mouse_x, mouse_y) 52 | end 53 | 54 | def mouse_released 55 | # Release the chain 56 | chain.release 57 | end 58 | -------------------------------------------------------------------------------- /chp10_nn/xor/xor.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | # XOR Multi-Layered Neural Network Example 5 | # Neural network code is all in the "code" folder 6 | load_library :nn 7 | 8 | require_relative './landscape' 9 | include_package 'nn' 10 | 11 | ITERATIONS_PER_FRAME = 5 12 | 13 | attr_reader :inputs, :nn, :count, :land, :theta, :f, :result, :known 14 | 15 | def setup 16 | size(400, 400, P3D) 17 | @theta = 0.0 18 | # Create a landscape object 19 | @land = Landscape.new(20, 300, 300) 20 | @f = create_font('Courier', 12, true) 21 | @nn = Network.new(2, 4) 22 | @count = 0 23 | # Create a list of 4 training inputs 24 | @inputs = [] 25 | inputs << [1.0, 0] 26 | inputs << [0, 1.0] 27 | inputs << [1.0, 1.0] 28 | inputs << [0, 0.0] 29 | end 30 | 31 | def draw 32 | lights 33 | ITERATIONS_PER_FRAME.times do 34 | inp = inputs.sample 35 | # Compute XOR 36 | @known = ((inp[0] > 0.0 && inp[1] > 0.0) || (inp[0] < 1.0 && inp[1] < 1.0)) ? 0 : 1.0 37 | # Train that sucker! 38 | @result = nn.train(inp, known) 39 | @count += 1 40 | end 41 | # Ok, visualize the solution space 42 | background(175) 43 | push_matrix 44 | translate(width / 2, height / 2 + 20, -160) 45 | rotate_x(Math::PI / 3) 46 | rotate_z(theta) 47 | # Put a little BOX on screen 48 | push_matrix 49 | stroke(50) 50 | no_fill 51 | translate(-10, -10, 0) 52 | box(280) 53 | land.calculate(nn) 54 | land.render 55 | # Draw the landscape 56 | pop_matrix 57 | @theta += 0.0025 58 | pop_matrix 59 | # Display overal neural net stats 60 | network_status 61 | end 62 | 63 | def network_status 64 | mse = 0.0 65 | text_font(f) 66 | fill(0) 67 | text('Your friendly neighborhood neural network solving XOR.', 10, 20) 68 | text("Total iterations: #{count}", 10, 40) 69 | mse += (result - known) * (result - known) 70 | rmse = Math.sqrt(mse / 4.0) 71 | out = "Root mean squared error: #{format('%.5f', rmse)}" 72 | hint DISABLE_DEPTH_SORT 73 | text(out, 10, 60) 74 | hint ENABLE_DEPTH_SORT 75 | end 76 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_01_Seek_trail/NOC_6_01_Seek_trail.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_01_Seek_trail 3 | 4 | load_library :vecmath 5 | 6 | class Vehicle 7 | attr_reader :location, :velocity, :acceleration, :history 8 | def initialize(x, y) 9 | @acceleration = Vec2D.new 10 | @velocity = Vec2D.new(0, -2) 11 | @location = Vec2D.new(x, y) 12 | @r = 6 13 | @maxspeed = 4 14 | @maxforce = 0.1 15 | @history = [] 16 | end 17 | 18 | def apply_force(force) 19 | @acceleration += force 20 | end 21 | 22 | def update 23 | @velocity += acceleration 24 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 25 | @location += velocity 26 | @acceleration *= 0 27 | history << location.copy 28 | history.shift if history.size > 100 29 | end 30 | 31 | def seek(target) 32 | desired = target - location 33 | return if desired.mag < PConstants.EPSILON 34 | desired.normalize! 35 | desired *= @maxspeed 36 | steer = desired - velocity 37 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 38 | apply_force(steer) 39 | end 40 | 41 | def display 42 | begin_shape 43 | stroke(0) 44 | stroke_weight(1) 45 | no_fill 46 | @history.each { |v| vertex(v.x, v.y) } 47 | end_shape 48 | theta = velocity.heading + PI / 2 49 | fill(127) 50 | stroke(0) 51 | stroke_weight(1) 52 | push_matrix 53 | translate(location.x, location.y) 54 | rotate(theta) 55 | begin_shape 56 | vertex(0, -@r * 2) 57 | vertex(-@r, @r * 2) 58 | vertex(@r, @r * 2) 59 | end_shape(CLOSE) 60 | pop_matrix 61 | end 62 | end 63 | 64 | attr_reader :seeker 65 | 66 | def setup 67 | size(640, 360) 68 | @seeker = Vehicle.new(width / 2, height / 2) 69 | end 70 | 71 | def draw 72 | background(255) 73 | mouse = Vec2D.new(mouse_x, mouse_y) 74 | fill(200) 75 | stroke(0) 76 | stroke_weight(2) 77 | ellipse(mouse.x, mouse.y, 48, 48) 78 | # Call the appropriate steering behaviors for our agents 79 | seeker.seek(mouse) 80 | seeker.update 81 | seeker.display 82 | end 83 | -------------------------------------------------------------------------------- /chp03_oscillation/Exercise_3_10_OOPWave/Exercise_3_10_OOPWave.rb: -------------------------------------------------------------------------------- 1 | # Exercise_3_10_OOPWave 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | 5 | Vect = Struct.new(:x, :y) # no fancy functionality required why use PVector? 6 | 7 | class Wave 8 | 9 | def initialize(o, w_, a, p) 10 | @xspacing = 8 # How far apart should each horizontal location be space 11 | @theta = 0.0 12 | @origin = o.dup # Where does the wave's first point start 13 | @w = w_ # Width of entire wave 14 | @period = p # How many pixels before the wave repeats 15 | @amplitude = a # Height of wave 16 | @dx = (TWO_PI / @period) * @xspacing # Value for incrementing X, to be calculated as a function of period and xspacing 17 | @yvalues = Array.new(@w / @xspacing) # Using an array to store height values for the wave (not entirely necessary) 18 | end 19 | 20 | def calculate 21 | # Increment theta (try different values for 'angular velocity' here 22 | @theta += 0.02 23 | # For every x value, calculate a y value with sine function 24 | x = @theta 25 | @yvalues.each_index do |i| 26 | @yvalues[i] = sin(x) * @amplitude 27 | x += @dx 28 | end 29 | end 30 | 31 | def display 32 | # A simple way to draw the wave with an ellipse at each location 33 | @yvalues.each_with_index do |yvalue, idx| 34 | stroke(0) 35 | fill(0, 50) 36 | ellipse_mode(CENTER) 37 | ellipse(@origin.x + idx * @xspacing, @origin.y + yvalue, 48, 48) 38 | end 39 | end 40 | end 41 | 42 | attr_reader :wave0, :wave1 43 | 44 | # Exercise_3_10_OOPWave 45 | def setup 46 | size(750, 200) 47 | # Initialize a wave with starting point, width, amplitude, and period 48 | @wave0 = Wave.new(Vect.new(50, 75), 100, 20, 500) 49 | @wave1 = Wave.new(Vect.new(300, 100), 300, 40, 220) 50 | end 51 | 52 | def draw 53 | background(255) 54 | # Update and display waves 55 | wave0.calculate 56 | wave0.display 57 | wave1.calculate 58 | wave1.display 59 | end 60 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/distance_joint/particle.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # A circular particle 6 | class Particle 7 | extend Forwardable 8 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :box2d, :height, :line, 9 | :push_matrix, :pop_matrix, :ellipse, :rotate, :translate) 10 | # We need to keep track of a Body and a radius 11 | attr_reader :body, :r 12 | 13 | def initialize(x, y) 14 | @r = 8 15 | @app = $app 16 | # Define a body 17 | bd = BodyDef.new 18 | # Set its position 19 | bd.position = box2d.processing_to_world(x,y) 20 | bd.type = BodyType::DYNAMIC 21 | @body = box2d.world.createBody(bd) 22 | 23 | # Make the body's shape a circle 24 | cs = CircleShape.new 25 | cs.m_radius = box2d.scale_to_world(r) 26 | 27 | fd = FixtureDef.new 28 | fd.shape = cs 29 | # Parameters that affect physics 30 | fd.density = 1 31 | fd.friction = 0.01 32 | fd.restitution = 0.3 33 | 34 | # Attach fixture to body 35 | body.createFixture(fd) 36 | body.setLinearVelocity(Vec2.new(rand(-5..5), rand(2..5))) 37 | end 38 | 39 | # This function removes the particle from the box2d world 40 | def kill_body 41 | box2d.destroy_body(body) 42 | end 43 | 44 | # Is the particle ready for deletion? 45 | def done 46 | # Let's find the screen position of the particle 47 | pos = box2d.body_coord(body) 48 | # Is it off the bottom of the screen? 49 | if pos.y > height + r * 2 50 | kill_body 51 | return true 52 | end 53 | false 54 | end 55 | 56 | def display 57 | # We look at each body and get its screen position 58 | pos = box2d.body_coord(body) 59 | # Get its angle of rotation 60 | a = body.get_angle 61 | push_matrix 62 | translate(pos.x, pos.y) 63 | rotate(a) 64 | fill(127) 65 | stroke(0) 66 | stroke_weight(2) 67 | ellipse(0, 0, r * 2, r * 2) 68 | # Let's add a line so we can see the rotation 69 | line(0, 0, r, 0) 70 | pop_matrix 71 | end 72 | end 73 | 74 | 75 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/mouse_joint/spring.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Class to describe the spring joint (displayed as a line) 6 | class Spring 7 | extend Forwardable 8 | def_delegators(:@app, :line, :box2d, :stroke, :stroke_weight) 9 | # This is the box2d object we need to create 10 | attr_reader :mouse_joint 11 | 12 | def initialize 13 | @app = $app 14 | end 15 | 16 | # If it exists we set its target to the mouse location 17 | def update(x, y) 18 | # Always convert to world coordinates! 19 | mouse_world = box2d.processing_to_world(x, y) 20 | mouse_joint.set_target(mouse_world) 21 | end 22 | 23 | def display 24 | # We can get the two anchor points 25 | v1 = Vec2.new 26 | mouse_joint.getAnchorA(v1) 27 | v2 = Vec2.new 28 | mouse_joint.getAnchorB(v2) 29 | # Convert them to screen coordinates 30 | vd1 = box2d.world_to_processing(v1) 31 | vd2 = box2d.world_to_processing(v2) 32 | # And just draw a line 33 | stroke(0) 34 | stroke_weight(1) 35 | line(vd1.x, vd1.y, vd2.x, vd2.y) 36 | end 37 | 38 | # This is the key function where 39 | # we attach the spring to an x,y location 40 | # and the Box object's location 41 | def bind(x, y, box) 42 | # Define the joint 43 | md = MouseJointDef.new 44 | # Body A is just a fake ground body for simplicity 45 | # (there isn't anything at the mouse) 46 | md.bodyA = box2d.ground_body 47 | # Body 2 is the box's boxy 48 | md.bodyB = box.body 49 | # Get the mouse location in world coordinates 50 | mp = box2d.processing_to_world(x, y) 51 | # And that's the target 52 | md.target.set(mp) 53 | # Some stuff about how strong and bouncy the spring should be 54 | md.maxForce = 1000.0 * box.body.m_mass 55 | md.frequencyHz = 5.0 56 | md.dampingRatio = 0.9 57 | # Make the joint! 58 | @mouse_joint = box2d.world.create_joint(md) 59 | end 60 | 61 | def destroy 62 | # We can get rid of the joint when the mouse is released 63 | box2d.world.destroy_joint(mouse_joint) 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /chp02_forces/NOC_2_6_attraction/attractor.rb: -------------------------------------------------------------------------------- 1 | # NOC_2_6_attraction 2 | # The Nature of Code 3 | # http://natureofcode.com 4 | # A class for a draggable attractive body in our world 5 | 6 | class Attractor 7 | include Processing::Proxy 8 | attr_reader :acceleration, :location, :mass 9 | G = 1 10 | 11 | def initialize(width, height) 12 | @location = Vec2D.new(width / 2, height / 2) 13 | @mass = 20 14 | @drag_offset = Vec2D.new(0.0, 0.0) 15 | @dragging = false 16 | @rollover = false 17 | end 18 | 19 | def attract(mover) 20 | force = @location - mover.location # Calculate direction of force 21 | d = force.mag # Distance between objects 22 | d = constrain(d, 5.0, 25.0) # Limiting the distance to eliminate "extreme" results for very close or very far objects 23 | force.normalize! # Normalize vector (distance doesn't matter here, we just want this vector for direction) 24 | strength = (G * mass * mover.mass) / (d * d) # Calculate gravitional force magnitude 25 | force *= strength # Get force vector --> magnitude * direction 26 | force 27 | end 28 | 29 | def display 30 | ellipse_mode(CENTER) 31 | stroke_weight(4) 32 | stroke(0) 33 | if @dragging 34 | fill(50) 35 | elsif @rollover 36 | fill(100) 37 | else 38 | fill(175, 200) 39 | end 40 | ellipse(location.x, location.y, mass * 2, mass * 2) 41 | end 42 | 43 | # The methods below are for mouse interaction 44 | def clicked(mx, my) 45 | d = dist(mx ,my, location.x, location.y) 46 | if d < @mass 47 | @dragging = true; 48 | @drag_offset.x = @location.x - mx 49 | @drag_offset.y = @location.y - my 50 | end 51 | end 52 | 53 | def hover(mx, my) 54 | d = dist(mx, my, location.x, location.y) 55 | @rollover = d < @mass 56 | end 57 | 58 | def stop_dragging 59 | @dragging = false 60 | end 61 | 62 | def drag 63 | if @dragging 64 | location.x = mouse_x + @drag_offset.x 65 | location.y = mouse_y + @drag_offset.y 66 | end 67 | end 68 | end 69 | 70 | 71 | -------------------------------------------------------------------------------- /chp07_CA/NOC_7_02_GameOfLifeSimple/NOC_7_02_GameOfLifeSimple.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_7_02_GameOfLifeSimple 3 | class GOL 4 | def initialize(width, height) 5 | @w = 8 6 | @rows, @cols = height / @w, width / @w 7 | puts "rows: #{@rows} - @cols #{@cols}" 8 | init 9 | end 10 | 11 | def init 12 | @board = Array.new(@cols) do 13 | Array.new(@rows) { rand(2).to_i } 14 | end 15 | end 16 | 17 | def generate 18 | nextgen = Array.new(@cols) { Array.new(@rows) { 0 } } 19 | (1 ... @cols - 1).each do |x| 20 | (1 ... @rows - 1).each do |y| 21 | neighbors = 0 22 | (-1 .. 1).each do |i| 23 | (-1 .. 1).each do |j| 24 | if @board[x + i][y + j] == nil 25 | puts "x+i #{x + i} - y+j #{y + j}" 26 | end 27 | neighbors += @board[x + i][y + j] if @board[x + i][y + j] 28 | end 29 | end 30 | # A little trick to subtract the current cell's state since 31 | # we added it in the loop above 32 | neighbors -= @board[x][y] 33 | # rules of life 34 | if @board[x][y] == 1 && neighbors < 2 35 | nextgen[x][y] = 0 # Loneliness 36 | elsif @board[x][y] == 1 && neighbors > 3 37 | nextgen[x][y] = 0 # Overpopulation 38 | elsif @board[x][y] == 0 && neighbors == 3 39 | nextgen[x][y] = 1 # Reproduction 40 | else 41 | nextgen[x][y] = @board[x][y] # Stasis 42 | end 43 | end 44 | end 45 | @board = nextgen 46 | end 47 | 48 | def display 49 | (0...@cols).each do |i| 50 | (0...@rows).each do |j| 51 | if @board[i][j] == 0 52 | fill(120) 53 | else 54 | fill(255) 55 | end 56 | stroke(0) 57 | rect(i * @w, j * @w, @w, @w) 58 | end 59 | end 60 | end 61 | end 62 | 63 | def setup 64 | size(400, 400) 65 | frame_rate(24) 66 | @gol = GOL.new(width, height) 67 | end 68 | 69 | def draw 70 | background(255) 71 | @gol.generate 72 | @gol.display 73 | end 74 | 75 | # reset board when mouse is pressed 76 | def mouse_pressed 77 | @gol.init 78 | end 79 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_07_Separation/NOC_6_07_Separation.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_07_Separation 3 | 4 | load_library :vecmath 5 | 6 | class Vehicle 7 | attr_reader :acceleration, :location, :velocity 8 | def initialize(x, y) 9 | @location = Vec2D.new(x, y) 10 | @r = 12 11 | @maxspeed = 3 12 | @maxforce = 0.2 13 | @acceleration = Vec2D.new(0, 0) 14 | @velocity = Vec2D.new(0, 0) 15 | end 16 | 17 | def apply_force(force) 18 | @acceleration += force 19 | end 20 | 21 | def separate(vehicles) 22 | desired_separation = @r * 2 23 | sum = Vec2D.new 24 | count = 0 25 | vehicles.each do |other| 26 | next if other.equal? self 27 | d = location.dist(other.location) 28 | if (PConstants.EPSILON .. desired_separation).include? d 29 | diff = location - other.location 30 | diff.normalize! 31 | diff /= d 32 | sum += diff 33 | count += 1 34 | end 35 | end 36 | return if count == 0 37 | sum /= count 38 | sum.normalize! 39 | sum *= @maxspeed 40 | steer = sum + velocity 41 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 42 | apply_force(steer) 43 | end 44 | 45 | def update 46 | @velocity += acceleration 47 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 48 | @location += velocity 49 | @acceleration *= 0 50 | end 51 | 52 | def display 53 | fill(175) 54 | stroke(0) 55 | push_matrix 56 | translate(location.x, location.y) 57 | ellipse(0, 0, @r, @r) 58 | pop_matrix 59 | end 60 | 61 | def borders(width, height) 62 | @location.x = width + @r if location.x < -@r 63 | @location.y = height + @r if location.y < -@r 64 | @location.x = -@r if location.x > width + @r 65 | @location.y = -@r if location.y < -@r 66 | end 67 | end 68 | 69 | def setup 70 | size(640, 360) 71 | @vehicles = Array.new(100) { Vehicle.new(rand(width), rand(height)) } 72 | end 73 | 74 | def draw 75 | background(255) 76 | @vehicles.each do |v| 77 | v.separate(@vehicles) 78 | v.update 79 | v.borders(width, height) 80 | v.display 81 | end 82 | end 83 | 84 | 85 | def mouse_dragged 86 | @vehicles << Vehicle.new(mouse_x, mouse_y) 87 | end 88 | -------------------------------------------------------------------------------- /chp09_ga/NOC_9_02_SmartRockets_superbasic/rocket.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # Pathfinding w/ Genetic Algorithms 6 | 7 | # Rocket class -- this is just like our Boid / Particle class 8 | # the only difference is that it has DNA & fitness 9 | class Rocket 10 | include Processing::Proxy 11 | # All of our physics stuff 12 | attr_reader :location, :velocity, :acceleration, :r, :dna, :target 13 | attr_reader :gene_counter, :hit_target 14 | 15 | # constructor 16 | def initialize(l, dna, target) 17 | @location, @dna, @target = l.dup, dna, target 18 | @acceleration = Vec2D.new 19 | @velocity = Vec2D.new 20 | @r = 4 21 | @gene_counter = 0 22 | @hit_target = false 23 | end 24 | 25 | # Fitness function 26 | # fitness = one divided by distance squared 27 | def fitness 28 | d = dist(location.x, location.y, target.x, target.y) 29 | (1 / d)**2 30 | end 31 | 32 | # Run in relation to all the obstacles 33 | # If I'm stuck, don't bother updating or checking for intersection 34 | def run 35 | check_target # Check to see if we've reached the target 36 | unless hit_target 37 | apply_force(dna.genes[gene_counter]) 38 | @gene_counter = (gene_counter + 1) % dna.genes.length 39 | update 40 | end 41 | display 42 | end 43 | 44 | # Did I make it to the target? 45 | def check_target 46 | @hit_target = dist(location.x, location.y, target.x, target.y) < 12 47 | end 48 | 49 | def apply_force(f) 50 | @acceleration += f 51 | end 52 | 53 | def update 54 | @velocity += acceleration 55 | @location += velocity 56 | @acceleration *= 0 57 | end 58 | 59 | def display 60 | theta = velocity.heading + PI / 2 61 | fill(200, 100) 62 | stroke(0) 63 | push_matrix 64 | translate(location.x, location.y) 65 | rotate(theta) 66 | # Thrusters 67 | rect_mode(CENTER) 68 | fill(0) 69 | rect(-r / 2.0, r * 2, r / 2.0, r) 70 | rect(r / 2.0, r * 2, r / 2.0, r) 71 | # Rocket body 72 | fill(175) 73 | begin_shape(TRIANGLES) 74 | vertex(0, -r * 2) 75 | vertex(-r, r * 2) 76 | vertex(r, r * 2) 77 | end_shape 78 | pop_matrix 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_08_SeparationAndSeek/vehicle.rb: -------------------------------------------------------------------------------- 1 | class Vehicle 2 | include Processing::Proxy 3 | attr_reader :location, :velocity, :acceleration 4 | def initialize(x, y) 5 | @location = Vec2D.new(x, y) 6 | @r = 12 7 | @maxspeed = 3 8 | @maxforce = 0.2 9 | @acceleration = Vec2D.new 10 | @velocity = Vec2D.new 11 | end 12 | 13 | def apply_force(force) 14 | @acceleration += force 15 | end 16 | 17 | def apply_behaviors(vehicles) 18 | separate_force = separate(vehicles) 19 | seek_force = seek(Vec2D.new(mouse_x, mouse_y)) 20 | separate_force *= 2 21 | apply_force(separate_force) 22 | apply_force(seek_force) 23 | end 24 | 25 | def seek(target) 26 | desired = target - location 27 | return desired if desired.mag < PConstants.EPSILON 28 | desired.normalize! 29 | desired *= @maxspeed 30 | steer = desired - velocity 31 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 32 | steer 33 | end 34 | 35 | def separate(vehicles) 36 | desired_separation = @r * 2 37 | sum = Vec2D.new 38 | count = 0 39 | vehicles.each do |other| 40 | next if other.equal? self 41 | d = location.dist(other.location) 42 | next unless (PConstants.EPSILON .. desired_separation).include? d 43 | diff = location - other.location 44 | diff.normalize! 45 | diff /= d 46 | sum += diff 47 | count += 1 48 | end 49 | return sum if count == 0 50 | sum /= count 51 | sum.normalize! 52 | sum *= @maxspeed 53 | steer = sum + velocity 54 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 55 | sum 56 | end 57 | 58 | def update 59 | @velocity += acceleration 60 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 61 | @location += velocity 62 | @acceleration *= 0 63 | end 64 | 65 | def display 66 | fill(175) 67 | stroke(0) 68 | push_matrix 69 | translate(location.x, location.y) 70 | ellipse(0, 0, @r, @r) 71 | pop_matrix 72 | end 73 | 74 | def borders(width, height) 75 | @location.x = width + @r if location.x < -@r 76 | @location.y = height + @r if location.y < -@r 77 | @location.x = -@r if location.x > width + @r 78 | @location.y = -@r if location.y < -@r 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #The-Nature-of-Code-Examples-in-Ruby 2 | 3 | __IMPORTANT SINCE 2017 RUBY-PROCESSING HAS BEEN SUPERSEDED BY JRUBY_ART AND PROPANE__ 4 | 5 | The current versions of pbox2d gem and toxiclibs gem do not work with ruby-processing (and there is no easy way to clamp the version). [JRubyArt][] just works, is better designed and supports latest processing. See alternative Nature of Code examples [here][]. 6 | 7 | A ruby port of the [examples][] from [The Nature of Code][] by Daniel Shiffman. 8 | In this fork PVector has been replaced by Vec2D, Vec3D or a lighweight alternative. Processing map has been replaced by ruby-processings map1d. 9 | 10 | Although many of the sketches here stand on their own merit, you should remember that they were originally designed to illustrate the book (so to get the most from them you should definetly [get the book][]). Since the sketches have been translated to a more idiomatic ruby, some of the sketches may not exactly match the points made in the book. However such sketches do serve to demonstrate the differences between processing and ruby-processing. Since the book is now also available in [Japanese][] it would be great if someone would fork this and add Japanese annotations. For the most part the code is just ruby and processing, but see [glossary][] for some convenience methods unique to ruby-processing (eg `load_library` and `clip`). 11 | 12 | ## Tested versions 13 | 14 | ruby 2.1 (note syntax clamped to 1.9.3 for jruby) 15 | 16 | jruby-1.7.16.1 17 | 18 | ruby-processing gem version 2.6.4 19 | 20 | pbox2d gem version 0.3.0 21 | 22 | [here]:https://github.com/ruby-processing/The-Nature-of-Code-for-JRubyArt 23 | [JRubyArt]:https://github.com/ruby-processing/JRubyArt 24 | [The Nature of Code]:http://natureofcode.com 25 | [get the book]:http://natureofcode.com 26 | [Japanese]:http://www.amazon.co.jp/Nature-Code--Processing%E3%81%A7%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E8%87%AA%E7%84%B6%E7%8F%BE%E8%B1%A1%E3%81%AE%E3%82%B7%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3--%E3%83%80%E3%83%8B%E3%82%A8%E3%83%AB%E3%83%BB%E3%82%B7%E3%83%95%E3%83%9E%E3%83%B3/dp/4862462456/ 27 | [examples]:https://github.com/shiffman/The-Nature-of-Code-Examples 28 | 29 | [glossary]:https://github.com/ruby-processing/The-Nature-of-Code-Examples-in-Ruby/wiki/Glossary 30 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/lib/particle.rb: -------------------------------------------------------------------------------- 1 | # Note the particle class change method is use to change color to red 2 | # when two particles collide (no change just hitting boundary) 3 | class Particle 4 | attr_accessor :body 5 | attr_reader :box2d, :radius, :col 6 | 7 | def initialize(b2d, x, y, r) 8 | @box2d, @x, @y, @radius = b2d, x, y, r 9 | # This function puts the particle in the Box2d world 10 | make_body(x, y, radius) 11 | @col = -5_263_441 # grey 12 | body.setUserData(self) 13 | end 14 | 15 | # This function removes the particle from the box2d world 16 | def kill_body 17 | box2d.destroy_body(body) 18 | end 19 | 20 | # Change color when hit 21 | def change 22 | @col = -65_536 # red 23 | end 24 | 25 | # Is the particle ready for deletion? 26 | def done 27 | # Let's find the screen position of the particle 28 | pos = box2d.body_coord(body) 29 | # Is it off the bottom of the screen? 30 | return false unless pos.y > (box2d.height + radius * 2) 31 | kill_body 32 | true 33 | end 34 | 35 | def display(app) 36 | # We look at each body and get its screen position 37 | pos = box2d.body_coord(body) 38 | # Get its angle of rotation 39 | a = body.get_angle 40 | app.push_matrix 41 | app.translate(pos.x, pos.y) 42 | app.rotate(a) 43 | app.fill(col) 44 | app.stroke(0) 45 | app.stroke_weight(1) 46 | app.ellipse(0, 0, radius * 2, radius * 2) 47 | # Let's add a line so we can see the rotation 48 | app.line(0, 0, radius, 0) 49 | app.pop_matrix 50 | end 51 | 52 | # Here's our function that adds the particle to the Box2D world 53 | def make_body(x, y, r) 54 | # Define a body 55 | bd = BodyDef.new 56 | # Set its position 57 | bd.position = box2d.processing_to_world(x, y) 58 | bd.type = BodyType::DYNAMIC 59 | @body = box2d.create_body(bd) 60 | # Make the body's shape a circle 61 | cs = CircleShape.new 62 | cs.m_radius = box2d.scale_to_world(r) 63 | fd = FixtureDef.new 64 | fd.shape = cs 65 | # Parameters that affect physics 66 | fd.density = 1 67 | fd.friction = 0.01 68 | fd.restitution = 0.3 69 | # Attach fixture to body 70 | body.create_fixture(fd) 71 | body.set_angular_velocity(rand(-10.0..10)) 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /chp05_physicslibraries/box2d/mouse_joint/box.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # Daniel Shiffman 3 | # http://natureofcode.com 4 | 5 | # A rectangular box 6 | class Box 7 | extend Forwardable 8 | def_delegators(:@app, :fill, :stroke, :stroke_weight, :rect, :rect_mode, 9 | :box2d, :rotate, :translate, :push_matrix, :pop_matrix) 10 | # We need to keep track of a Body and a width and height 11 | attr_accessor :body, :w, :h 12 | # Constructor 13 | def initialize(x, y) 14 | @app = $app 15 | @w, @h = 24, 24 16 | # Add the box to the box2d world 17 | make_body(Vec2.new(x, y), w, h) 18 | end 19 | 20 | # This function removes the particle from the box2d world 21 | def kill_body 22 | box2d.destroy_body(body) 23 | end 24 | 25 | def contains(x, y) 26 | world_point = box2d.processing_to_world(x, y) 27 | f = body.get_fixture_list 28 | f.test_point(world_point) 29 | end 30 | 31 | # Drawing the box 32 | def display 33 | # We look at each body and get its screen position 34 | pos = box2d.body_coord(body) 35 | # Get its angle of rotation 36 | a = body.getAngle 37 | rect_mode(Java::ProcessingCore::PConstants::CENTER) 38 | push_matrix 39 | translate(pos.x, pos.y) 40 | rotate(a) 41 | fill(127) 42 | stroke(0) 43 | stroke_weight(2) 44 | rect(0, 0, w, h) 45 | pop_matrix 46 | end 47 | 48 | # This function adds the rectangle to the box2d world 49 | def make_body(center, w, h) 50 | # Define and create the body 51 | bd = BodyDef.new 52 | bd.type = BodyType::DYNAMIC 53 | bd.position.set(box2d.processing_to_world(center)) 54 | @body = box2d.createBody(bd) 55 | # Define a polygon (this is what we use for a rectangle) 56 | sd = PolygonShape.new 57 | box2dw = box2d.scale_to_world(w / 2) 58 | box2dh = box2d.scale_to_world(h / 2) 59 | sd.setAsBox(box2dw, box2dh) 60 | # Define a fixture 61 | fd = FixtureDef.new 62 | fd.shape = sd 63 | # Parameters that affect physics 64 | fd.density = 1 65 | fd.friction = 0.3 66 | fd.restitution = 0.5 67 | body.create_fixture(fd) 68 | # Give it some initial random velocity 69 | body.set_linear_velocity(Vec2.new(rand(-5.0..5), rand(2.0..5))) 70 | body.set_angular_velocity(rand(-5.0..5)) 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /chp06_agents/NOC_6_03_StayWithinWalls/NOC_6_03_StayWithinWalls.rb: -------------------------------------------------------------------------------- 1 | # The Nature of Code 2 | # NOC_6_01_Seek_trail 3 | 4 | load_library :vecmath 5 | 6 | class Vehicle 7 | attr_reader :location, :velocity, :acceleration, :world 8 | def initialize(x, y, world, safe_distance) 9 | @acceleration = Vec2D.new 10 | @velocity = Vec2D.new(3, -2) 11 | @location = Vec2D.new(x, y) 12 | @r = 6 13 | @maxspeed = 3 14 | @maxforce = 0.15 15 | @world = world 16 | @d = safe_distance 17 | end 18 | 19 | def run 20 | update 21 | display 22 | end 23 | 24 | def apply_force(force) 25 | @acceleration += force 26 | end 27 | 28 | def update 29 | @velocity += acceleration 30 | @velocity.set_mag(@maxspeed) { velocity.mag > @maxspeed } 31 | @location += velocity 32 | @acceleration *= 0 33 | end 34 | 35 | def boundaries 36 | if location.x < @d 37 | desired = Vec2D.new(@maxspeed, velocity.y) 38 | elsif location.x > world.width - @d 39 | desired = Vec2D.new(-@maxspeed, velocity.y) 40 | elsif location.y < @d 41 | desired = Vec2D.new(velocity.x, @maxspeed) 42 | elsif location.y > world.height - @d 43 | desired = Vec2D.new(velocity.x, -@maxspeed) 44 | else 45 | desired = nil 46 | end 47 | return if desired.nil? 48 | desired.normalize! 49 | desired *= @maxspeed 50 | steer = desired - velocity 51 | steer.set_mag(@maxforce) { steer.mag > @maxforce } 52 | apply_force(steer) 53 | end 54 | 55 | def display 56 | theta = velocity.heading + PI / 2 57 | fill(127) 58 | stroke(0) 59 | stroke_weight(1) 60 | push_matrix 61 | translate(location.x, location.y) 62 | rotate(theta) 63 | begin_shape 64 | vertex(0, -@r * 2) 65 | vertex(-@r, @r * 2) 66 | vertex(@r, @r * 2) 67 | end_shape(CLOSE) 68 | pop_matrix 69 | end 70 | end 71 | 72 | attr_reader :seeker 73 | 74 | def setup 75 | size(640, 360) 76 | @d = 25 77 | @seeker = Vehicle.new(width / 2, height / 2, self, @d) 78 | end 79 | 80 | def draw 81 | background(255) 82 | 83 | stroke(175) 84 | no_fill 85 | rect_mode(CENTER) 86 | rect(width / 2, height / 2, width - @d * 2, height - @d * 2) 87 | 88 | # Call the appropriate steering behaviors for our agents 89 | @seeker.boundaries 90 | @seeker.run 91 | end 92 | --------------------------------------------------------------------------------