Skip to content

Commit

Permalink
Added Simple Physics Simulation (Confetti)
Browse files Browse the repository at this point in the history
A super simple 2D simulation where balls fall and bounce off each other.
Click to spawn new balls.
  • Loading branch information
Andrew-McCall authored Dec 31, 2024
1 parent 2f7f3c8 commit 6f371d5
Showing 1 changed file with 146 additions and 0 deletions.
146 changes: 146 additions & 0 deletions examples/confetti
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
use std::u8;
use macroquad::prelude::*;

#[derive(Debug, Clone, Copy)]
pub struct Ball {
id: usize,
x: f32,
y: f32,
x_vel: f32,
y_vel: f32,
color: Color,
}

// Customizable
const FLOOR_LOSS: f32 = 0.98;
const DRAG: f32 = 0.998;
const GRAVITY: f32 = 1.0;

const BALL_RADIUS: f32 = 6.0;

// Please, don't change
static mut BALL_ID : usize = 0;
const BALL_RADIUS_SQR: f32= BALL_RADIUS * BALL_RADIUS;

impl Ball {
fn new(x: f32, y:f32, seed:usize) -> Ball{
let id;
unsafe {
id = BALL_ID;
BALL_ID += 1;
}

let seed = seed % (usize::MAX/64);
let random = (32_1239 * seed*seed*seed* 17 + id)% 1000 ;
let x_vel = random % 9;
let x_vel = (x_vel as f32 - 4.0) / 2.0;

return Ball{id, x, y, x_vel, y_vel:0.0, color:Color::from_rgba((random as usize*47%255) as u8, (random as usize*29%255) as u8, (random as usize*101%255) as u8, u8::MAX)}
}

fn tick(&mut self){
self.x_vel *= DRAG;
self.y_vel *= DRAG;

self.x += self.x_vel;
self.y += self.y_vel;

if self.y > screen_height(){
// self.y = screen_height();
self.y_vel = -self.y_vel * FLOOR_LOSS;
}else{
self.y_vel += GRAVITY;
}

if self.x < 0.0 || self.x > screen_width(){
self.x_vel = -self.x_vel * FLOOR_LOSS;
}
}

fn draw(&self){
draw_circle(self.x, self.y-BALL_RADIUS, BALL_RADIUS, self.color);
}

fn collide(&mut self, balls: &[Ball]) {
for other in balls {
if other.id == self.id {
continue;
}

let dx = self.x - other.x;
let dy = self.y - other.y;
let distance_sqr = dx * dx + dy * dy;

if distance_sqr > BALL_RADIUS_SQR {
continue;
}

let distance = distance_sqr.sqrt();
if distance == 0.0 {
continue;
}
let nx = dx / distance;
let ny = dy / distance;

let relative_velocity_x = self.x_vel - other.x_vel;
let relative_velocity_y = self.y_vel - other.y_vel;
let relative_velocity_normal = relative_velocity_x * nx + relative_velocity_y * ny;

if relative_velocity_normal > 0.0 {
continue;
}

let impulse = (2.0 * relative_velocity_normal) / 2.0 * FLOOR_LOSS;

self.x_vel -= impulse * nx;
self.y_vel -= impulse * ny;
}
}

}

#[macroquad::main("AM - Confetti")]
async fn main() {

let mut balls: Vec<Ball> = Vec::new();
let mut frame_count: usize = 0;
loop {
// Loop start
frame_count += 1;
clear_background(Color { r: 0.95, g: 0.9, b: 0.9, a: 1.0 });

// Handle Inputs
if is_mouse_button_down(MouseButton::Left) || is_mouse_button_pressed(MouseButton::Right) {
let (mouse_x,mouse_y) = mouse_position();
balls.push(Ball::new(mouse_x, mouse_y ,frame_count))
}

if is_key_pressed(KeyCode::Space) {
unsafe {
BALL_ID = 0;
balls.clear();
}
}

// Handle Tick
let balls_prev = balls.to_vec();
for ball in &mut balls {
ball.collide(&balls_prev);
ball.tick();
ball.draw();
}

unsafe {
if BALL_ID == 0 {
draw_text("Click anywhere to begin!", screen_width()/2.0 - 240.0, screen_height()/2.0, 48.0, RED);
}else{
draw_text(&format!("Balls{}: {}", if BALL_ID > 999 {" (Press Space to Reset)"} else {""}, BALL_ID), 15.0, 25.0, 32.0, BLACK);
}
}

next_frame().await
}
}

// Andrew McCall <3
// https://github.com/Andrew-McCall/MacroquadConfetti

0 comments on commit 6f371d5

Please sign in to comment.