Mini Project 3: Generative Motion

Project Link

Sketch 1: https://editor.p5js.org/King-Raphael/sketches/W1yWhF780

Sketch 2: https://editor.p5js.org/King-Raphael/sketches/SRvTRY2wZ

Sketch 3: https://editor.p5js.org/King-Raphael/sketches/XAmtepc77

Brief Description and Concept

In this project, I explored different generative motion techniques using the p5.js. The goal was to create dynamic animations with various shapes and movements. Each sketch demonstrates unique types of motion influenced by noise functions, trigonometric calculations, and interactive elements.

Visual Documentation

 

Coding

Sketch 1

let shapes = [];
let currentShapeIndex = 0;

function setup() {
  createCanvas(800, 600);

  // Initialize shapes with different directions
  for (let i = 0; i < 4; i++) {
    shapes.push({
      x: random(width),
      y: random(height),
      size: random(30, 60),
      speedX: random(-3, 3),
      speedY: random(-3, 3),
      shapeType: i, // Each shape has a different type (0 to 3)
    });
  }
}

function draw() {
  background(0, 65);

  for (let i = 0; i < shapes.length; i++) {
    let s = shapes[i];

    // Update position
    s.x += s.speedX;
    s.y += s.speedY;

    // Check for boundaries and reverse direction if necessary
    if (s.x < 0 || s.x > width) s.speedX *= -1;
    if (s.y < 0 || s.y > height) s.speedY *= -1;

    // Set random color
    noStroke();
    fill(random(255), random(255), 200, 150);

    // Draw shapes based on shapeType
    if (s.shapeType === 0) {
      ellipse(s.x, s.y, s.size, s.size);
    } else if (s.shapeType === 1) {
      rect(s.x, s.y, s.size, s.size);
    } else if (s.shapeType === 2) {
      triangle(
        s.x, s.y - s.size / 2,
        s.x - s.size / 2, s.y + s.size / 2,
        s.x + s.size / 2, s.y + s.size / 2
      );
    } else if (s.shapeType === 3) {
      beginShape();
      vertex(s.x, s.y - s.size / 2);
      vertex(s.x + s.size / 4, s.y - s.size / 4);
      vertex(s.x + s.size / 2, s.y);
      vertex(s.x + s.size / 4, s.y + s.size / 4);
      vertex(s.x, s.y + s.size / 2);
      vertex(s.x - s.size / 4, s.y + s.size / 4);
      vertex(s.x - s.size / 2, s.y);
      vertex(s.x - s.size / 4, s.y - s.size / 4);
      endShape(CLOSE);
    }
  }
}

// Change shape types with mouse press
function mousePressed() {
  // Change the shapeType of each shape to the next type
  for (let i = 0; i < shapes.length; i++) {
    shapes[i].shapeType = (shapes[i].shapeType + 1) % 4;
  }
}
 

Inner Workings:

  • Variables: angle controls the phase of the sine function, amplitude determines the height of oscillation, and x and y track the position of the ellipse.
  • Sinusoidal Movement: The y value oscillates based on the sin(angle), creating an up-and-down motion.
  • Horizontal Movement: x moves horizontally, influenced by xSpeed for varied speeds, giving it a dynamic feel.
  • Color Dynamics: The fill function assigns random colors to each circle.

Failures and Successes:

  • Initial versions used static speeds, resulting in uniform movement. Adding random improved the dynamic nature.
  • Color transitions were initially jarring; applying semi-transparent fills enhanced the blending effect.

Alternative Approach:
Use cos() for y and sin() for x to reverse the directional oscillation. This would create a different, yet harmonious, wave motion:

Sketch 2

let xoff = 0;
let yoff = 1000;
let r, g, b;

function setup() {
  createCanvas(600, 600);
}

function draw() {
  noStroke();
  background(255,40);
  let x = noise(xoff) * width;
  let m = map(x, 100, 500, 0, 600);
  let y = noise(yoff) * height;
  let n = map(y, 100, 500, 0, 600);
  
  fill(r, g, b, 80);
  ellipse(m, n, 50, 50);
  
  xoff += 0.01;
  yoff += 0.01;
  
  if(m > 550 || m < 50){ // xoff = -xoff; r = random(0, 255); g = random(0, 255); b = random(0, 255); } if(n > 550 || n < 50){
    // yoff = -yoff;
    r = random(0, 255);
    g = random(0, 255);
    b = random(0, 255);
  }
  
  console.log(m,n);
}

Inner Workings:

  • Noise Function: noise() is used to generate smooth, organic movements for x and y.
  • Mapping: The map() function constrains the noise values to a specific range.
  • Color Change: Colors change dynamically when m or n go beyond set boundaries, creating a vibrant effect.

Failures and Successes:

  • The initial attempt used only random() for movement, which resulted in erratic behavior. Switching to noise()provided smoother transitions.
  • The boundary conditions sometimes led to abrupt color changes, which were softened by adjusting the alpha values in fill().

Alternative Approach:
Instead of changing colors when boundaries are crossed, modify the speed of noise increment (xoff and yoff). This would slow down or speed up the motion dynamically, giving a different pace to the movement.

Sketch 3

let numCircles = 10;
let circles = [];

function setup() {
  createCanvas(800, 600);
  
  // Initialize circles with random properties
  for (let i = 0; i < numCircles; i++) {
    let newCircle = {
      x: random(width),
      y: random(height),
      radius: random(20, 50),
      angle: random(TWO_PI),
      speed: random(0.01, 0.05),
      radiusOffset: random(50, 150),
      color: [random(255), random(255), random(255), 150] // Random color with alpha
    };
    circles.push(newCircle);
  }
}

function draw() {
  background(255);
  noStroke();
  
  for (let i = 0; i < circles.length; i++) {
    let c = circles[i];
    
    // Calculate new position based on angle and radius offset
    let x = c.x + cos(c.angle) * c.radiusOffset;
    let y = c.y + sin(c.angle) * c.radiusOffset;
    
    // Set the circle color
    fill(c.color);
    ellipse(x, y, c.radius * 2, c.radius * 2);
    
    // Update angle to move the circle
    c.angle += c.speed;
    
    // Update the center position to create a linear movement effect
    c.x += random(-1, 1);
    c.y += random(-1, 1);
    
    // Reset position if the circle moves out of the canvas
    if (c.x < 0 || c.x > width || c.y < 0 || c.y > height) {
      c.x = random(width);
      c.y = random(height);
    }
  }
} 
  • Variables:
    • numCircles: Specifies the number of circles to be created.
    • circles: An array to store circle objects, each with its own properties.
  • setup() Function:
    • Initializes the canvas to 800x600 pixels.
    • Creates an array of numCircles circle objects, each with:
      • Random initial position (x, y).
      • Random radius size.
      • Random starting angle.
      • Random speed of rotation, determining how fast the circle moves along its path.
      • Random radiusOffset, determining the size of the circular path.
      • A random color stored as an array [r, g, b, alpha].
  • draw() Function:
    • Sets the background color to white with background(255);.
    • Iterates over each circle object in the circles array.
    • Position Calculation:
      • x and y are calculated using cos() and sin() functions respectively, based on the circle’s angle and radiusOffset.
    • Color and Shape:
      • Sets the fill color to the circle’s stored color (fill(c.color);).
      • Draws the circle using the ellipse() function at the calculated position.
    • Movement:
      • Updates the circle’s angle to move it along its circular path.
      • Adds a small random value to c.x and c.y to make the center of the circle drift slightly, giving a more dynamic movement.
    • Boundary Check:
      • If the circle’s center moves outside the canvas bounds, it is repositioned randomly within the canvas.

Findings / Lessons Learned

  • Core Takeaways: Mastery of the noise() function and its applications in creative coding can lead to more sophisticated visual outputs. The integration of interactive features (mouse and keyboard inputs) opens new avenues for dynamic designs.
  • Challenges: The main challenge was balancing randomness with smooth motion. Ensuring the sketches were visually appealing yet distinct required iterative tuning of parameters.

Reflection Prompts

  • The project challenged me to think beyond simple movements and explore complex interactions between shapes, motion, and user inputs.
  • Tuning parameters like speed and amplitude to get the desired movement patterns was time-consuming and required multiple iterations.
  • It strengthened my grasp of generative art principles and the synergy between coding and creativity.

Leave a Reply

Your email address will not be published. Required fields are marked *