use tiny_game_framework::{lerp, rand_betw, EventLoop, Renderer}; use tiny_game_framework::Circle; use tiny_game_framework::glam::*; use tiny_game_framework::gl; static GRAVITY: Vec3 = Vec3 { x: 0.0, y: -5.0, z: 0.0, }; fn main() { let mut el = EventLoop::new(500, 500); let mut renderer = Renderer::new(); let mut world = World::new(&mut renderer); let mut dt = 0.0; while !el.window.should_close() { let now = std::time::Instant::now(); el.update(); world.update(&mut renderer, dt, &el); unsafe { gl::Clear(gl::COLOR_BUFFER_BIT); renderer.draw(&el); } dt = now.elapsed().as_secs_f32(); } } struct World { particles: Vec, } impl World { pub fn new(renderer: &mut Renderer) -> Self { let mut particles = vec![]; for i in 0..63 { let mut p1 = Particle::new(Vec3::ZERO, &i.to_string(), renderer, 10.0); p1.p = vec3(rand_betw(-250.0, 250.0), rand_betw(-250.0, 250.0), 0.0); p1.op = p1.p - vec3(rand_betw(-1.0, 1.0), rand_betw(-1.0, 1.0), 0.0); particles.push(p1); } Self { particles, } } pub fn update(&mut self, renderer: &mut Renderer, dt: f32, el: &EventLoop) { let mut collision_pairs: Vec<[usize; 2]> = vec![]; for i in 0..self.particles.len() { for j in 0..self.particles.len() { if Self::detect_collision(&self.particles[i], &self.particles[j]) { collision_pairs.push([i, j]); } } } for pair in &collision_pairs { Self::resolve_collision(&mut self.particles, pair[0], pair[1]); } for particle in self.particles.iter_mut() { particle.update(dt); particle.update_mesh(renderer); particle.constrain(el); } } pub fn detect_collision(collider: &Particle, collide: &Particle) -> bool { collider.check_with(collide) } pub fn resolve_collision(particles: &mut Vec, i: usize, j: usize) { if i == j { return; } let (left, right) = if i < j { particles.split_at_mut(j) } else { particles.split_at_mut(i) }; let (p1, p2) = if i < j { (&mut left[i], &mut right[0]) } else { (&mut right[0], &mut left[j]) }; let delta = p2.p - p1.p; let distance = delta.length(); let overlap = (p1.r + p2.r) - distance; if overlap > 0.0 { let delta_norm = delta / distance; let adjustment = delta_norm * (overlap / 2.0); p1.p -= adjustment; p2.p += adjustment; std::mem::swap(&mut p1.v, &mut p2.v); } } } struct Particle { op: Vec3, p: Vec3, v: Vec3, r: f32, name: String, } impl Particle { pub fn new(p: Vec3, name: &str, renderer: &mut Renderer, radius: f32) -> Self { let n = Vec3::ZERO; let circle = Circle::new(7, radius / 250.0, vec4(rand_betw(0.0, 1.0), rand_betw(0.0, 1.0), rand_betw(0.0, 1.0), 1.0)); renderer.add_mesh(name, circle.mesh()).unwrap(); renderer.get_mesh_mut(name).unwrap().rotation = Quat::from_euler(EulerRot::XYZ, 0.0, 0.0, rand_betw(0.0, 2.0*std::f32::consts::PI)); Self { p, op: p, v: n, r: radius, name: name.to_string(), } } pub fn update(&mut self, dt: f32) { self.v = self.p - self.op; self.op = self.p; self.p += self.v + GRAVITY * dt; } pub fn check_with(&self, particle: &Particle) -> bool { if self.p.distance(particle.p) < self.r * 2.0 { true } else { false } } pub fn constrain(&mut self, el: &EventLoop) { let (w, h) = el.window.get_framebuffer_size(); let (hw, hh) = (w as f32 / 2.0, h as f32 / 2.0); if self.p.x >= hw - self.r || self.p.x <= -hw + self.r { self.p.x = self.p.x.clamp(-hw + self.r, hw - self.r); self.v.x = -self.v.x * 0.8; self.op.x = self.p.x - self.v.x; } if self.p.y >= hh - self.r || self.p.y <= -hh + self.r { self.p.y = self.p.y.clamp(-hh + self.r, hh - self.r); self.v.y = -self.v.y * 0.8; self.op.y = self.p.y - self.v.y; } } pub fn update_mesh(&self, renderer: &mut Renderer) { if let Some(mesh) = renderer.get_mesh_mut(&self.name) { mesh.position.x = lerp(mesh.position.x, self.p.x, 0.5); mesh.position.y = lerp(mesh.position.y, self.p.y, 0.5); } } }