Final Project (Draft 1) – Khalifa Alshamsi

Design Concept

The project “Gravity Dance” aims to create an immersive simulation that explores the graceful and sometimes chaotic interactions within a celestial system.

Storyline

As participants engage with “Gravity Dance,” they will enter a dynamic universe where they can introduce new celestial bodies into a system. Each interaction not only alters the trajectory and speed of these bodies but also impacts the existing celestial dance, creating a living tapestry of motion that mirrors the interconnectivity of space itself.

Interaction Methodology

Users interact with the simulation through simple mouse inputs:

  • Clicking on the canvas adds a new celestial body at the point of click.
  • Dragging allows users to set the initial velocity of the celestial bodies, giving them tangential speed and direction.
  • Hovering provides details about the mass and current velocity of the celestial bodies.

Technical Setup and Code Insights

  • Gravitational Physics: Each planet’s movement is influenced by Newton’s law of universal gravitation.
  • Cellular Automata: The background is dynamically generated using cellular automata to create a starry night effect. Different shapes and brightness levels represent various types of celestial phenomena.

Design of Canvas

User Interaction Instructions:

  • Startup Screen: Instructions are displayed briefly when the user first enters the simulation, explaining how to add and manipulate celestial bodies.
  • During Interaction: Cursor changes to indicate different modes (add, drag).
  • Feedback: Visual cues such as changes in color or size indicate the mass and speed of the celestial bodies. Textual feedback appears when hovering over a body, showing details.

Current Sketch

Base p5.js Code

let planets = [];
let G = 6.67430e-11;  // Universal Gravitational Constant
let grid, cols, rows;
let resolution = 10;  // Adjust resolution for visual detail

function setup() {
  createCanvas(windowWidth, windowHeight);
  cols = floor(width / resolution);
  rows = floor(height / resolution);
  grid = Array.from({ length: cols }, () => Array.from({ length: rows }, () => random(1) < 0.1));
  frameRate(30);
}

function draw() {
  background(0, 20); // Slight fade effect for motion blur

  // Draw the space-themed cellular automata background
  drawSpaceCA();

  // Draw the central sun
  fill(255, 204, 0);
  ellipse(width / 2, height / 2, 40, 40);

  // Update and display all planets
  planets.forEach(planet => {
    planet.update();
    planet.display();
  });
}

function mouseClicked() {
  let newPlanet = new Planet(mouseX, mouseY, random(5, 20), random(0.5, 2));
  planets.push(newPlanet);
}

class Planet {
  constructor(x, y, mass, velocity) {
    this.pos = createVector(x, y);
    this.mass = mass;
    this.vel = createVector(velocity, 0);
  }

  update() {
    let force = createVector(width / 2, height / 2).sub(this.pos);
    let distance = force.mag();
    force.setMag(G * this.mass * 10000 / (distance * distance));
    this.vel.add(force);
    this.pos.add(this.vel);
  }

  display() {
    fill(255);
    ellipse(this.pos.x, this.pos.y, this.mass);
  }
}

function drawSpaceCA() {
  noStroke();
  for (let i = 0; i < cols; i++) {
    for (let j = 0; j < rows; j++) {
      let x = i * resolution;
      let y = j * resolution;
      if (grid[i][j]) {
        let shapeType = floor(random(3)); // Choose between 0, 1, 2 for different shapes
        let size = random(3, 6); // Size variation for visual interest
        fill(255, 255, 255, 150); // Slightly opaque for glow effect
        if (shapeType === 0) {
          ellipse(x + resolution / 2, y + resolution / 2, size, size);
        } else if (shapeType === 1) {
          rect(x, y, size, size);
        } else {
          triangle(x, y, x + size, y, x + size / 2, y + size);
        }
      }
    }
  }

  if (frameCount % 10 === 0) {
    grid = updateCA(grid); // Update less frequently
  }
}

function updateCA(current) {
  let next = Array.from({ length: cols }, () => Array.from({ length: rows }, () => false));
  for (let i = 0; i < cols; i++) {
    for (let j = 0; j < rows; j++) {
      let state = current[i][j];
      let neighbors = countNeighbors(current, i, j);
      if (state === false && neighbors === 3) {
        next[i][j] = true;
      } else if (state === true && (neighbors === 2 || neighbors === 3)) {
        next[i][j] = true;
      } else {
        next[i][j] = false;
      }
    }
  }
  return next;
}

function countNeighbors(grid, x, y) {
  let sum = 0;
  for (let i = -1; i <= 1; i++) {
    for (let j = -1; j <= 1; j++) {
      let col = (x + i + cols) % cols;
      let row = (y + j + rows) % rows;
      sum += grid[col][row] ? 1 : 0;
    }
  }
  sum -= grid[x][y] ? 1 : 0;
  return sum;
}

Next Steps

As I continue to develop “Celestial Choreography,” the next phases will focus on refining the physics model to include more complex interactions such as orbital resonances and perhaps collisions. Additionally, enhancing the visual aesthetics and introducing more interactive features are key priorities.

 

Leave a Reply

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