An Interactive Game: Celestial Body Simulation (Part 3)

Welcome back to the third installment of my celestial body simulation project! This time, I've transformed the simulation into an interactive game that lets you play with the cosmos right in your browser. Let's dive into how I built it, the challenges I faced, and the math that makes it all possible.

1. Bringing the Simulation to Life

My initial simulations were built using Python and Matplotlib, which were great for plotting orbits and visualizing gravitational interactions. However, I wanted to make the simulation more interactive and accessible. So, I decided to bring it to the web using HTML5 Canvas and JavaScript.

The first step was setting up the basic HTML structure and creating a canvas element where the simulation would be drawn:


<canvas id="simulation-canvas"></canvas>
            

Then, I initialized the canvas in JavaScript and set up the animation loop:


// Initialize canvas
const canvas = document.getElementById('simulation-canvas');
const ctx = canvas.getContext('2d');

// Animation loop
function animate() {
    updateBodies();
    drawBodies();
    requestAnimationFrame(animate);
}

animate();
            

2. Adding Interactivity with JavaScript

To make the simulation interactive, I created a user interface where you can add celestial bodies, set their initial positions and velocities, and even click on the canvas to place them. The interface includes input fields and buttons, all tied together with event listeners in JavaScript:


// Event listener for adding bodies
document.getElementById('add-body-button').addEventListener('click', addBody);

// Function to add a new body
function addBody() {
    // Code to create input fields and update the simulation
}
            

Clicking on the canvas updates the position of the selected body, making it intuitive and fun to set up initial conditions.

3. The Math Behind the Simulation

At the heart of the simulation is Newton's Law of Universal Gravitation, which calculates the gravitational force between two bodies:

\[ \vec{F} = G \frac{m_1 m_2}{r^2} \]

Where:

  • \( \vec{F} \) is the gravitational force vector.
  • \( G \) is the gravitational constant.
  • \( m_1 \) and \( m_2 \) are the masses of the two bodies.
  • \( r \) is the distance between the centers of the two bodies.
  • \( \hat{r} \) is the unit vector pointing from one body to the other.

The acceleration of each body is then calculated using Newton's Second Law:

\[ \vec{a} = \frac{\vec{F}}{m} \]

With the acceleration known, I updated the velocities and positions using simple kinematic equations:

\[ \vec{v}_{\text{new}} = \vec{v}_{\text{old}} + \vec{a} \Delta t \]
\[ \vec{r}_{\text{new}} = \vec{r}_{\text{old}} + \vec{v}_{\text{new}} \Delta t \]

Here's a snippet of the code handling the physics calculations:


// Constants
const G = 1; // Gravitational constant
const timeStep = 0.01; // Simulation time step

// Function to update bodies
function updateBodies() {
    bodies.forEach(body => {
        // Reset acceleration
        body.acceleration = { x: 0, y: 0 };

        // Calculate net force on the body
        bodies.forEach(otherBody => {
            if (body !== otherBody) {
                const dx = otherBody.position.x - body.position.x;
                const dy = otherBody.position.y - body.position.y;
                const distance = Math.sqrt(dx * dx + dy * dy) + 1e-6;
                const force = (G * body.mass * otherBody.mass) / (distance * distance);

                // Update acceleration
                body.acceleration.x += (force * dx) / (distance * body.mass);
                body.acceleration.y += (force * dy) / (distance * body.mass);
            }
        });

        // Update velocity and position
        body.velocity.x += body.acceleration.x * timeStep;
        body.velocity.y += body.acceleration.y * timeStep;
        body.position.x += body.velocity.x * timeStep;
        body.position.y += body.velocity.y * timeStep;
    });
}
            

4. Handling Collisions and Boundaries

To make the simulation more realistic (and entertaining), I added options for edge collisions and body collisions. For edge collisions, when a body hits the edge of the simulation canvas, it bounces back by reversing its velocity component:


// Handle edge collisions
if (body.position.x < 0 || body.position.x > canvas.width) {
    body.velocity.x *= -1;
}
if (body.position.y < 0 || body.position.y > canvas.height) {
    body.velocity.y *= -1;
}
            

For body collisions, I implemented elastic collision equations to update the velocities of colliding bodies. The math involves conserving momentum and energy, and the implementation looks like this:


// Handle body collisions
function handleBodyCollision(bodyA, bodyB) {
    const dx = bodyB.position.x - bodyA.position.x;
    const dy = bodyB.position.y - bodyA.position.y;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance < bodyA.radius + bodyB.radius) {
        // Swap velocities for simplicity (elastic collision)
        [bodyA.velocity, bodyB.velocity] = [bodyB.velocity, bodyA.velocity];
    }
}
            

5. Designing the User Interface

The user interface was styled to be clean and modern, matching the aesthetic of my website. I used CSS Flexbox and Grid to layout the controls and the canvas neatly. Here's an excerpt of the CSS:


/* Main Content */
.main-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
}

/* Canvas */
#simulation-canvas {
    background-color: #000;
    border: 2px solid #45A29E;
    border-radius: 8px;
    width: 800px;
    height: 600px;
}

/* Controls */
#controls {
    background-color: #1F2833;
    padding: 20px;
    border-radius: 8px;
    margin-bottom: 20px;
}
            

The end result is an interactive simulation where you can add multiple bodies, set their properties, and watch as they orbit, collide, and dance across the screen!

6. Try It Yourself!

I've hosted the simulation online so you can play with it yourself. Click the link below to explore the cosmos:

🚀 Launch the Celestial Simulation 🚀

In Conclusion...

Building this interactive simulation was a rewarding experience that combined physics, programming, and user interface design. It was exciting to see the math come to life and to create something that others can enjoy and learn from. Stay tuned for future updates, where I plan to add features like zooming, panning, and maybe even a 3D mode!

As always, the code is open-source and available on my GitHub repository. Feel free to explore, contribute, or use it as inspiration for your own projects.