Xiaozao Coding Assignment #4

Coding Assignment #4 – Simple Harmonic Motion

This week, we are drawing inspiration from Memo Akten and creating some simple harmonic motion using the sine wave. I created three sketches. But before introducing them, let me explain my organized code structure of the sine wave class.

In the class, we analyzed the three attributes of a sine wave: the amplitude, the period, and the phase. And we used a formula to calculate the corresponding x and y positions of the balls.

let y = sin((TWO_PI*x)/period+phase_shift)*amp;

However, if we want to further manipulate the motion of the balls, it’s better to create a class. And with all these attributes of the class object, we can break down the calculation of the objects’ position into sub-steps, which, in my perspective, is easier to understand. Here’s the class structure that I reorganized.

let gap = 10;
let w = 600;
let h = 600;
let num = w/gap;
let period = 2; // length of two whole periods = width of the canvas
let phase = 0; // starting x-offset
let phase_shift = 0.01; // phase shifting speed
let amp = 100;

let joints = [];



function setup() {
  
  createCanvas(w, h);
  background(0);
  noFill();
  strokeWeight(2);
  stroke(255);
  
  let total_angle = period * 2 * PI;
  for (let x = gap; x < w; x += gap) {
    let this_angle = map(x, 0, w, 0, total_angle);
    joints.push(new Joint(x, 0, this_angle));
  }
  
}



function draw() {
  
  background(0);
  
  for (let i = 0; i < joints.length; i ++) {
    let joint = joints[i];
    joint.update();
    joint.display();
  }
  
}


class Joint {
  constructor(x, y, angle) {
    this.x = x;
    this.y = y;
    this.angle = angle;
    this.r = gap*0.7;
    this.phase = phase; // set a phase for each class object
  }
  
  update() {
    this.y = amp * sin(this.angle + this.phase);
    this.phase += phase_shift;
    
  }
  
  display() {
    push();
    translate(0, h/2);
    // lines
    line(this.x, 0, this.x, this.y);
    
    // balls
    ellipse(this.x, this.y, this.r);
    pop();
  }
}

As you can see, I first defined the parameters at the beginning of the code. Then in setup(), I create a set of objects of the Joint class according to the x position of them. Now they all have the same period, but it’s easy to modify if needed. Then the essential parameters are passed through the constructor() function be become class attributes. In the update() function, I calculate the y position in a simpler formula, because I don’t need to consider the period as it’s already dealt with in the previous steps and is ready to be invoked. Finally, I call the display() function for each joint in the draw() loop.

By customizing the parameters at the beginning and the formula in the update function, we can change the motion pattern more efficiently.

1. Manta Ray

This is a really simple but harmonic motion. I think it looks like a manta ray swimming in the ocean, and staring at it calms me down.

I mainly changed the period of each joint so that the joints near the edge of the canvas have a slower period and the joints in the middle have a faster period. Also, I make the amplitude of the joints in the middle a bit larger.

function setup() {
  
  createCanvas(w, h);
  // frameRate(600);
  background(0);
  noFill();
  strokeWeight(2);
  stroke(255);
  
  
  for (let x = gap; x < w; x += gap) {
    let this_period = abs(w-x)/500;
    let total_angle = this_period * 2 * PI;
    let this_angle = map(x, 0, w, 0, total_angle);
    joints.push(new Joint(x, 0, this_angle, log(w/2-abs(w/2-x))*30));
  }
  
}

 

2. Linked Nodes

This one is more directly inspired by Memo’s work. Basically, I adjusted the phase of every joint. In other words, you can imagine that they have the same period but are moving along the X-axis at different speeds. At some point, the y positions reach zero at the same time and align with each other.

The most important line of code:

let this_shift = (x+w/2)/20000;

Also, I draw an alpha line between two nodes if the distance between them falls in a certain range.

3. Flower Generator

This one is also interesting. I positioned the joints around a circle and also modified the phase. And it created a really beautiful effect!

Reflection:

The most important takeaway from this exercise is that I learned to use different ways to draw my joints. Sometimes (especially when it comes to circular patterns) it gets hard to use the concept of period, therefore you have to find a different way to utilize the sine wave. For example, I found that adjusting the phase-shifting speed is much simpler and intuitive. After all, a sin wave is kind of a “relative” concept. You never know its scale before comparing it to another thing’s scale. So, if it is an intensive sine wave, you can either say that it has a rather short period or it is shifting rather fast along the time axis. Therefore we can be flexible when writing our code as long as we are clear about what to do!

And although randomly trying can sometimes generate unexpected beautiful results, it’s still important to understand the principle and design your outcome purposefully.

By the way, I also tried to combine multiple sine waves of different amplitude and period:

Xiaozao Coding Assignment #3

Concept:

In this assignment, I wanted to generate some minimalist patterns using the interaction force between the attractor and multiple movers. I wanted to keep the visual style simple and reduce the user interaction to focus more on the final patterns that the movement of the objects will be able to create. The parameters that I’ve tried adjusting include the gravitational constant G, the mass of the attractor and the mover, the starting position and velocity of the objects, and the way of calculating the force between the attractor and the movers.

Codes:

I tried to write several p5js sketches that share the same classes and parameters but are slightly different in force functions and the logic behind them.

01

The first one places a line or grid of movers that have no initial velocity. However, the attractor has been set with a constant speed to keep it moving in a straight line, so that it can lead the direction of the movers to a certain extent, based on its own mass, moving speed, and distance from the movers. I created several versions.

02

In the second set of sketches, I changed the movement of the attractor to a circular pattern and placed the movers in a circle to see what would happen. And I discovered something interesting.

When the attractor is moving rather slowly (move by an angle of frameRate/500 every frame), we can see that it places a strong force to the moving direction of the movers. It’s like macaroni.

If we increase the moving rate of the attractor (frameRate/100), we can see that the movers are not heading in the same direction. It’s because the attractor has already changed its position before it puts enough force to the mover to move towards a certain direction.

When the attractor is moving very fast (frameRate/1), you can actually find that its directional impact on the movers is more even. In other words, it’s moving like a centrifugal machine and due to its more rapid change of position, its force on the movers in every direction is evenly distributed. When it is moving extremely fast, we can actually say that it puts no force on the movers at all. This makes me rethink of how the impact of force can change with a change in time scale!

03

In the last experiment, I attempted to create a combination of the gravitational acceleration and the vector acceleration. So what’s the difference between the two?

The gravitational acceleration is calculated through Newton’s second law, which is a rather complicated formula. However, vector acceleration is simply applying the subtraction of the position of the attractor and the position of the mover as a force. I discovered this because I was trying to create a flower-like pattern with the gravitational force but I could never succeed. Later I found out that we can only achieve this through applying the vector force.

Here is the comparison of these two kind of forces. In these two sketches, only the force calculation formula has been changed. (basically one line of code)

Vector force:

Gravitational force:

And then I wrote both of the functions and applied the two forces to the same mover. This is what I got. Look at the movement and you can find there’s a twist each time when the mover is near the attractor. It’s done by the gravitational force.

Then I tried to make the attractor move and also adjusted some parameters. And I got these patterns:

Future direction:

I think the next step can be manipulating more movers instead of a single mover. I can also make more interactive sketches. It’s also a good idea to add a fraction or a force that will push away the mover when it’s too close to the attractor.

Xiaozao Coding Assignment #2

Create your Planet System

Source code: https://editor.p5js.org/Xiaozao/sketches/55EaOIHQ9

Reference: The Coding Train https://thecodingtrain.com/learning/nature-of-code/2.5-gravitational-attraction.html

Part 1: Concept

The movement of objects that I found in nature was the solar system.

It’s amazing to discover how the sun and the planets interact with each other and apply acceleration to each other’s movement. Therefore I intended to simulate this process. I watched the videos for forces from the Coding Train, and learned how to generate a N-body system. However, I wasn’t able to simulate the solar system in the end. It’s because the real parameters are extremely large, and the gravitational interaction is actually far more complicated than I expected. It is impossible to simulate it using only Newton’s gravitational law. Therefore although I was not satisfied with the final product, I had no better solutions and had to turn it in. But I will definitely try it in the next weeks!

Part 2: Coding

The basis of my coding gained lots of help from the Coding Train. I defined one class called “Mover”, which is basically every planet in the system. I set the position, initial velocity, mass, and acceleration for every object of the class. And then I defined an attract() function that calculates the distance between two planets to get the mutual force using Newton’s gravitational law. I’ve got an array for storing all the Mover objects, and calculate the force between every single pair of movers.

The fun part was to design the user interface that enables the players of the system to generate their new planets in whatever mass and initial velocity they want. The user simply has to press the up or down arrow key to adjust the mass of the planet and drag and drop the mouse to release a new planet in any direction.

The larger the circle, the larger the mass. The longer the arrow, the higher the initial speed.

However, if I draw the circle and arrow in the mousePressed and mouseDragged functions, there will be a problem. The mousePressed will only be called once at the exact moment the mouse is being pressed, and the mouseDragged will also stop looping when the mouse position doesn’t move, even if the mouse is still triggered. This will cause the circle and arrow to be covered by the background of the next draw loop.

To solve this, I store every parameter of the detail of the circle and arrow in some variable, and draw them in the draw loop under certain conditions.

  // in draw:
  if (mouseIsPressed) {
    stroke(255);
    strokeWeight(1);
    noFill();
    ellipse(mouseXStore, mouseYStore, newSize, newSize);
    arrow(mouseXStore, mouseYStore,mouseX, mouseY);
  } else {
    ellipse(mouseX, mouseY, newSize, newSize);
  }
  
  if (keyIsPressed) {
    if (keyCode === UP_ARROW ) {
      newSize += 0.5;
    } else if (keyCode === DOWN_ARROW) {
      newSize -= 0.5;
    } else if (key == "c" || key == "C") {
      for (let i = movers.length - 1; i >= 0; i --) {
        movers.splice(i,1);
      }
    }
  }
  noStroke();
  fill(255);
  text("Drag and release to create a new planet", 10,15);
  text("Press up and down arrow to change planet mass", 10, 25);
}


function mousePressed() {
  mouseXStore = mouseX;
  mouseYStore = mouseY;
}


function mouseReleased() {
  movers.push(new Mover(mouseXStore, mouseYStore, newDir.x, newDir.y, newInitSpd, newSize**2)); 
}


function arrow(x1,y1,x2,y2) {
  let vec = createVector(x2-x1,y2-y1);
  let dist = vec.mag();
  newInitSpd = dist/30;
  stroke(255);
  strokeWeight(1);
  fill(255);
  line(x1,y1,x2,y2);
  push();
  translate(mouseX, mouseY);
  let dir = atan2(vec.y, vec.x);
  rotate(dir);
  triangle(0,0,-3,-2,-3,2);
  pop();
  newDir = vec.normalize();
}

Part 3: Reflection

I don’t think I did well on this assignment. I failed to learn more about the physics principles of gravity interaction and didn’t achieve my initial goal of simulating the solar system. Instead, I only did a customizable n-body system. Given that I had two semesters’ experience in p5js coding, I should try to create more original and math/physics-based projects next time!!!

Xiaozao Reading Reflection – Week#1

I really like the reading passage. It tells us about how different disciplines interact with each other and have shared underlying logic. The author mentioned two opposite theories, the reductionism and the holism. He said that these two theories won’t agree with each other because reductionism is about how we break down things in parts, and smaller parts, right to the quantum level, while holism is studying how simple things can form together into a more complex system. But from my perspective, these theories are not only contradictory but also complementary. When looking at something, we always look at it from “eye level”, which means we observe its appearance and try to get information about what it is naturally. Then we apply reductionism and break down its concepts. After that, we apply holism and analyze how it behaves in a larger context or environment. Finally we go back to the middle stage and will be able to get a clearer idea of not only “what it is”, but also “why it does this”. This is how we get to know every individual in the universe, and how we develop an interdisciplinary perspective.

There are many examples in life that prove the ideas of the author. For example, the clusters of galaxies in the field of astronomy are quite similar to neural networks in the field of neural science. And actually, the structure and logic of computers are inspired by the two. Many manmade things are bionic, meaning that they all got inspiration from the micro and macro world in nature. When we break them down, we will see similar basic patterns; and when we look from the macroscopic perspective, we will find they have similar behaviors under that respective context. As the author has mentioned, the invention of the computer brings all the subjects together and promotes communication between them. This is right because the computer simulators found out the similarity of structure and interaction type among them. Therefore, what we are doing in this class is very important to not only the application of computer programming, but also the discovery of nature theories.

Xiaozao Week1 Coding Assignment

This week, I tried on two different kinds of random walkers, which are the self-avoiding walker and the chance-control walker.

Self-avoiding Snake

Video: https://drive.google.com/file/d/1Y0-no7La1HUOdGIHNaVAoFkQJxFrM-Tg/view?usp=drive_link


P5js sketch: https://editor.p5js.org/Xiaozao/sketches/st5NS1k5R


(I’m sorry, something went wrong with my wordpress editor and I really don’t know how to insert the p5 sketch in this new editor. I will try to figure it out asap!!)


This project is inspired by the classic game “Snake”. Since the self-avoiding random walker moves either vertically or horizontally on a grid, why can’t I make a snake game by controlling the length of the path of this random walker, and placing some “apples” on the grid, so that whenever the snake touches an apple, it will eat it and grow in length? And the special property of the self-avoiding walker, which is that it will either find another path or terminate walking when it meets its own body, is very suitable for making a snake game.


I started with coding a self-avoiding random walker. I learned it from the coding train: https://youtu.be/m6-cm6GZ1iw?si=cbg0Dx-YE7jZplUc.

Basically, I first create a grid of size (rows, cols) and initialize the value of each pixel in the grid to be True, meaning that it’s empty and available to be occupied. And then, I create an array, which consists of every node of the snake’s body, and I change the status of the pixels that have been occupied by the snake’s body, meaning that they can no longer be stepping into when I’m considering the next step. After that, I begin to check the 4 neighbours of my current position (up, down, left and right), and if they are still empty and not occupied, I put them into my “available options” array. Finally, I choose a random direction from the available options, and go to the next step. This is how the self-avoiding walker works.

And then, I began to program the snake game. There are two main considerations of this game. Firstly, different from the original random walker, which draws every single node that I’ve been to, now I want to control the length of my snake. This can lower the chance of terminating the game too fast because a long body occupies a lot of space so there will be fewer choices in every step. To do this, I have to keep track of every node of the snake’s body, and pop the tail out if it’s too long. I made an array of nodes, and used the function splice() to pop out the older parts of the snake body.

The second important part is the apple-eating mechanism. Whenever I click the mouse, an apple will be placed at the same place and can be eaten by the snake. The snake’s length will plus by one every time it eats an apple. I made a class for the Apple objects, and came up with a formula that calculates the position to place the apples so that they will always be in the center of the pixels, so that they can be easily eaten by the snake.

Lastly, I placed a “keyboard” in the grid. The value of mouseY will control the frequency rate of the sound being played so it creates a really funny sound effect! (By the way, I recorded the sound on my own~)

Chance-control random walker

This is another experiment that comes from a mistake. Please look at the explanation below:

I mistakenly wrote the code when I was trying to create a uniform random distribution. Instead of generating a single random number and checking its value using if/else statement, I generated a brand new random number in each “else if” statement”. But it accidentally created a non-uniform random distribution which the chance of executing the second “else if” block is somehow dependent on the chance of executing the first “if” block, and so on. I then tried to pass the chance values for the four statements as parameters and map the hue of the random walker with the chance values. And the result turned out to be interesting!

Here is the code: https://editor.p5js.org/Xiaozao/sketches/vyNmsjMgc

There’s so much more to explore about this chance-controlling random walker!