Compare commits

..

No commits in common. "main" and "rapier" have entirely different histories.
main ... rapier

2 changed files with 73 additions and 81 deletions

View File

@ -1,5 +1,6 @@
mod drawable; mod drawable;
mod engine; mod engine;
mod particle;
use drawable::DrawShape; use drawable::DrawShape;
use engine::{PhysicsEngine, PhysicsState}; use engine::{PhysicsEngine, PhysicsState};
@ -7,49 +8,33 @@ use engine::{PhysicsEngine, PhysicsState};
use nalgebra::vector; use nalgebra::vector;
use nannou::prelude::*; use nannou::prelude::*;
use rapier2d::{ use rapier2d::{
dynamics::{RigidBodyBuilder, RigidBodyHandle, RigidBodySet}, dynamics::{RigidBodyBuilder, RigidBodySet},
geometry::{ColliderBuilder, ColliderSet}, geometry::{ColliderBuilder, ColliderSet},
}; };
const WINDOW_WIDTH: u32 = 512; const WINDOW_WIDTH: u32 = 512;
const WINDOW_HEIGHT: u32 = WINDOW_WIDTH; const WINDOW_HEIGHT: u32 = WINDOW_WIDTH;
const PARTICLE_COUNT: u32 = 200; const PARTICLE_COUNT: u32 = 200;
const PARTICLE_SIZE: f32 = 5.; const PARTICLE_SIZE: f32 = 10.0;
struct Model { struct Model {
// Store the window ID so we can refer to this specific window later if needed. // Store the window ID so we can refer to this specific window later if needed.
window: WindowId, _window: WindowId,
// particles: Vec<Particle>, // particles: Vec<Particle>,
engine: PhysicsEngine, engine: PhysicsEngine,
} }
fn random_vec_in_rect(boundary: &Rect) -> nalgebra::Vector2<f32> { fn fill_particles(_app: &App, colliders: &mut ColliderSet, bodies: &mut RigidBodySet) {
let x = random_range(-100., 100.); let boundary = _app.window_rect();
let y = random_range(-150., boundary.top());
vector![x, y]
}
fn fill_particles(boundary: &Rect, colliders: &mut ColliderSet, bodies: &mut RigidBodySet) {
// Keeping track of already placed balls to avoid overlap
// Need to look into a way to do this with rapier directly
let mut positions: Vec<nalgebra::Vector2<f32>> = Vec::new();
for _ in 0..PARTICLE_COUNT { for _ in 0..PARTICLE_COUNT {
let mut xy = random_vec_in_rect(boundary); let x = random_range(-100., 100.);
while !positions let y = random_range(-150., boundary.top());
.iter()
.all(|pos| pos.metric_distance(&xy) > PARTICLE_SIZE * 2.)
{
xy = random_vec_in_rect(boundary)
}
positions.push(xy);
/* Create the bouncing ball. */ /* Create the bouncing ball. */
let rigid_body = RigidBodyBuilder::dynamic().translation(xy).build(); let rigid_body = RigidBodyBuilder::dynamic()
let collider = ColliderBuilder::ball(PARTICLE_SIZE) .translation(vector![x, y])
.restitution(0.1)
.build(); .build();
let collider = ColliderBuilder::ball(5.).restitution(0.1).build();
let ball_body_handle = bodies.insert(rigid_body); let ball_body_handle = bodies.insert(rigid_body);
colliders.insert_with_parent(collider, ball_body_handle, bodies); colliders.insert_with_parent(collider, ball_body_handle, bodies);
} }
@ -61,7 +46,7 @@ fn model(app: &App) -> Model {
// per app // per app
// Create a new window! Store the ID so we can refer to it later. // Create a new window! Store the ID so we can refer to it later.
let window = app let _window = app
.new_window() .new_window()
.size(WINDOW_WIDTH, WINDOW_HEIGHT) .size(WINDOW_WIDTH, WINDOW_HEIGHT)
.title("nannou") .title("nannou")
@ -72,79 +57,43 @@ fn model(app: &App) -> Model {
let mut engine = PhysicsEngine { let mut engine = PhysicsEngine {
state: PhysicsState { state: PhysicsState {
gravity: vector![0., -9.81 * 10.], gravity: vector![0.0, -9.81 * 10.0],
..Default::default() ..Default::default()
}, },
..Default::default() ..Default::default()
}; };
let boundary = app.window(window).unwrap().rect();
/* Create the ground. */ /* Create the ground. */
let collider = ColliderBuilder::cuboid(boundary.w(), 4.) let collider = ColliderBuilder::cuboid(100.0, 10.0)
.translation(vector![0., boundary.bottom()]) .translation(vector![0.0, -200.0])
.build(); .build();
engine.state.colliders.insert(collider); engine.state.colliders.insert(collider);
/* Create the walls. */ // let mut particles = Vec::new();
let collider = ColliderBuilder::cuboid(4., boundary.h())
.translation(vector![boundary.left(), 0.])
.build();
engine.state.colliders.insert(collider);
let collider = ColliderBuilder::cuboid(4., boundary.h())
.translation(vector![boundary.right(), 0.])
.build();
engine.state.colliders.insert(collider);
/* Create the ceiling. */ // fill_particles(app, &mut particles);
let collider = ColliderBuilder::cuboid(boundary.w(), 4.) fill_particles(app, &mut engine.state.colliders, &mut engine.state.bodies);
.translation(vector![0., boundary.top()])
.build();
engine.state.colliders.insert(collider);
fill_particles( Model {
&boundary, _window,
&mut engine.state.colliders, // particles,
&mut engine.state.bodies, engine,
); }
Model { window, engine }
} }
// Handle events related to the window and update the model if necessary // Handle events related to the window and update the model if necessary
fn event(app: &App, model: &mut Model, event: WindowEvent) { fn event(app: &App, _model: &mut Model, event: WindowEvent) {
if let KeyReleased(Key::Escape) = event { if let KeyReleased(Key::Escape) = event {
app.quit() app.quit()
} }
if let Resized(_) = event { // if let Resized(_) = event {
// Rust borrowing rules means I need to first gather a list of handles, // model.particles.clear();
// then delete them all //
let handles: Vec<RigidBodyHandle> = model // fill_particles(app, &mut model.particles);
.engine // }
.state
.bodies
.iter()
.map(|(handle, _)| handle)
.collect();
for handle in handles { // println!("{:?}", event);
model.engine.state.bodies.remove(
handle,
&mut model.engine.state.islands,
&mut model.engine.state.colliders,
&mut model.engine.state.joints,
&mut model.engine.state.multibody_joints,
true,
);
}
fill_particles(
&app.window(model.window).unwrap().rect(),
&mut model.engine.state.colliders,
&mut model.engine.state.bodies,
);
}
} }
// Update the state of your application here. By default, this gets called right before `view`. // Update the state of your application here. By default, this gets called right before `view`.

43
src/particle.rs Normal file
View File

@ -0,0 +1,43 @@
use crate::drawable::Drawable;
use crate::PARTICLE_SIZE;
use nannou::prelude::*;
#[derive(Debug)]
pub struct Particle {
pub pos: Vec2,
pub start_pos: Vec2,
pub radius: f32,
pub time_offset: f32,
}
impl Particle {
pub fn new(pos: Vec2) -> Self {
Self {
pos,
start_pos: pos,
..Default::default()
}
}
}
impl Default for Particle {
fn default() -> Self {
Self {
pos: Default::default(),
radius: PARTICLE_SIZE,
start_pos: Default::default(),
time_offset: random_range(-PI, PI),
}
}
}
impl Drawable for Particle {
fn draw(&self, draw: &Draw) {
draw.ellipse()
.color(RED)
.stroke_weight(1.0)
.radius(self.radius)
.xy(self.pos);
}
}