diff --git a/src/asteroids.rs b/src/asteroids.rs index ec23b4e..bc8b6f7 100644 --- a/src/asteroids.rs +++ b/src/asteroids.rs @@ -17,6 +17,7 @@ pub struct Asteroid { rot: f32, omega: f32, pub alive: bool, + pub color: Color, } impl Asteroid { @@ -47,6 +48,7 @@ impl Asteroid { omega: gen_range(0.8, 3.5) * if gen_range(0., 1.) > 0.5 { -1. } else { 1. }, rot: 0., alive: true, + color: Color::new(1., 1., 1., 0.2), } } @@ -91,8 +93,7 @@ impl Asteroid { AsteroidSize::Medium => 1.2, AsteroidSize::Small => 0.8, }, - // WHITE, - Color::new(1., 1., 1., 0.4), + self.color, ); } } diff --git a/src/main.rs b/src/main.rs index b9c029a..6b3498a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -128,7 +128,9 @@ async fn main() { set_camera(&gamecam); if is_key_pressed(KeyCode::S) { speedup = (speedup * 10) % 9999; - println!("Speedup: {}", speedup); + } + if is_key_pressed(KeyCode::P) { + paused = !paused; } if !paused { for _ in 0..speedup { @@ -165,6 +167,20 @@ async fn main() { screen_width() - WIDTH - 3. * th, (screen_height() - 7. * th) * 0.5 - 2. * ui_thick, ); + if is_mouse_button_pressed(MouseButton::Left) && mouse_position().0 < WIDTH + th { + let (x, y) = mouse_position(); + for i in 0..pop.worlds.len() { + if (pop.worlds[i].player.pos - vec2(x - th - WIDTH * 0.5, y - th - HEIGHT * 0.5)) + .length_squared() + < 256. + { + pop.worlds.swap(0, i); + pop.worlds[0].track(true); + pop.worlds[i].track(false); + break; + } + } + } let ui_width = screen_width() - WIDTH - 3. * th + 1.; let ui_height = (screen_height() - 3. * th) * 0.5; @@ -216,20 +232,22 @@ async fn main() { widgets::Group::new(hash!(), Vec2::new(100., ui_thick)) .position(Vec2::new(140., 0.)) .ui(ui, |ui| { - ui.drag(hash!(), "", Some((1, 500)), &mut size); + ui.drag(hash!(), "", Some((1, 300)), &mut size); }); ui.same_line(307.); - widgets::Button::new("Debug").ui(ui); + if widgets::Button::new("Debug").ui(ui) { + pop.debug = !pop.debug; + }; ui.same_line(0.); if widgets::Button::new(if bias { "Hide Bias" } else { "Show Bias" }).ui(ui) { bias = !bias; }; ui.same_line(0.); - if widgets::Button::new(if !pop.best { "Show Best" } else { "Show All " }) + if widgets::Button::new(if !pop.focus { "Show Best" } else { "Show All " }) .ui(ui) { - pop.best = !pop.best; + pop.focus = !pop.focus; }; ui.same_line(0.); if widgets::Button::new(restart).ui(ui) { diff --git a/src/nn.rs b/src/nn.rs index 44b9365..f3e9b7e 100644 --- a/src/nn.rs +++ b/src/nn.rs @@ -184,10 +184,15 @@ impl NN { ); } } - draw_rectangle(width * 0.45, height * 0.45, 10., 10., RED); - draw_text("-ve", width * 0.45 + 20., height * 0.45 + 10., 20., WHITE); - draw_rectangle(width * 0.45, height * 0.45 + 20., 10., 10., WHITE); - draw_text("+ve", width * 0.45 + 20., height * 0.45 + 30., 20., WHITE); + draw_rectangle(width * 0.47, height * 0.47, 10., 10., RED); + let params = TextParams { + font_size: 40, + font_scale: 0.5, + ..Default::default() + }; + draw_text_ex("-ve", width * 0.47 + 20., height * 0.47 + 10., params); + draw_rectangle(width * 0.47, height * 0.47 + 20., 10., 10., WHITE); + draw_text_ex("+ve", width * 0.47 + 20., height * 0.47 + 30., params); } pub fn export(&self) -> String { diff --git a/src/player.rs b/src/player.rs index 60f0e93..cdbb7f0 100644 --- a/src/player.rs +++ b/src/player.rs @@ -19,7 +19,6 @@ pub struct Player { last_shot: u8, shot_interval: u8, pub brain: Option, - debug: bool, alive: bool, pub color: Option, pub lifespan: u32, @@ -36,7 +35,6 @@ impl Player { drag: 0.001, shot_interval: 18, alive: true, - debug: false, shots: 4, outputs: vec![0.; 4], @@ -147,18 +145,21 @@ impl Player { } } let keys: Vec = self.outputs.iter().map(|&x| x > 0.).collect(); - if is_key_down(KeyCode::Right) && self.debug || keys[0] { + if keys[0] { + // RIGHT self.rot = (self.rot + 0.1 + TAU as f32) % TAU as f32; self.dir = vec2(self.rot.cos(), self.rot.sin()); } - if is_key_down(KeyCode::Left) && self.debug || keys[1] { + if keys[1] { + // LEFT self.rot = (self.rot - 0.1 + TAU as f32) % TAU as f32; self.dir = vec2(self.rot.cos(), self.rot.sin()); } - if is_key_down(KeyCode::Up) && self.debug || keys[2] { + if is_key_down(KeyCode::Up) || keys[2] { + // THROTTLE self.acc = 0.14; } - if is_key_down(KeyCode::Space) && self.debug || keys[3] { + if is_key_down(KeyCode::Space) || keys[3] { if self.last_shot > self.shot_interval { self.last_shot = 0; self.shots += 1; @@ -170,12 +171,12 @@ impl Player { } } - if is_key_pressed(KeyCode::D) { - self.debug = !self.debug; - } - if is_key_pressed(KeyCode::S) { - self.debug = false; - } + // if is_key_pressed(KeyCode::D) { + // self.debug = !self.debug; + // } + // if is_key_pressed(KeyCode::S) { + // self.debug = false; + // } self.vel += self.acc * self.dir - self.drag * self.vel.length() * self.vel; self.pos += self.vel; @@ -191,14 +192,11 @@ impl Player { } self.bullets .retain(|b| b.alive && b.pos.x.abs() * 2. < WIDTH && b.pos.y.abs() * 2. < HEIGHT); - if self.debug { - self.draw(); - } self.asteroid = None; // self.asteroid_data.clear(); } - pub fn draw(&self) { + pub fn draw(&self, debug: bool) { let color = match self.color { Some(c) => c, // None => WHITE, @@ -218,14 +216,14 @@ impl Player { if self.acc > 0. && gen_range(0., 1.) < 0.4 { draw_triangle_lines(p6, p7, p8, 2., color); } - if self.debug { + if debug { if let Some(ast) = self.asteroid.as_ref() { - draw_circle_lines(ast.pos.x, ast.pos.y, ast.radius, 1., GRAY); + draw_circle_lines(ast.pos.x, ast.pos.y, ast.radius, 1., DARKBLUE); // let p = self.pos // + self.dir.rotate(Vec2::from_angle(self.asteroid_data[0].1)) // * self.asteroid_data[0].0 // * WIDTH; - draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., GRAY); + draw_line(self.pos.x, self.pos.y, ast.pos.x, ast.pos.y, 1., DARKBLUE); } // Draw raycasts @@ -244,7 +242,7 @@ impl Player { } for bullet in &self.bullets { - bullet.draw(); + bullet.draw(color); } } @@ -265,7 +263,7 @@ impl Bullet { fn update(&mut self) { self.pos += self.vel; } - fn draw(&self) { - draw_circle(self.pos.x, self.pos.y, 2., WHITE); + fn draw(&self, color: Color) { + draw_circle(self.pos.x, self.pos.y, 2., color); } } diff --git a/src/population.rs b/src/population.rs index d5e2cf9..81cd710 100644 --- a/src/population.rs +++ b/src/population.rs @@ -6,7 +6,8 @@ use crate::{nn::NN, world::World, HEIGHT, WIDTH}; pub struct Population { size: usize, pub gen: i32, - pub best: bool, + pub focus: bool, + pub debug: bool, pub worlds: Vec, } @@ -32,27 +33,23 @@ impl Population { self.next_gen(); } if is_key_pressed(KeyCode::Z) { - self.best = !self.best; + self.focus = !self.focus; + } + if is_key_pressed(KeyCode::D) { + self.debug = !self.debug; } } pub fn draw(&self) { for world in self.worlds.iter().rev() { - if self.best { - if world.player.color.is_some() { - world.draw(); + if self.focus { + if world.track { + world.draw(self.debug); } } else if !world.over { - world.draw(); + world.draw(self.debug); } } - // draw_text( - // &format!("Gen: {}", self.gen), - // -150. + WIDTH * 0.5, - // 30. - HEIGHT * 0.5, - // 32., - // WHITE, - // ); // draw black background outside the screen let th = (screen_height() - HEIGHT) * 0.5; @@ -85,8 +82,7 @@ impl Population { let mut new_worlds = (0..std::cmp::max(1, self.size / 20)) .map(|i| World::simulate(Some(self.worlds[i].see_brain().to_owned()))) .collect::>(); - new_worlds[0].set_best(); - // new_worlds[0].export_brian(); + new_worlds[0].track(true); while new_worlds.len() < self.size { let rands = (gen_range(0., total), gen_range(0., total)); let mut sum = 0.; diff --git a/src/world.rs b/src/world.rs index c7944f7..315fa93 100644 --- a/src/world.rs +++ b/src/world.rs @@ -12,6 +12,7 @@ pub struct World { pub score: f32, pub over: bool, pub fitness: f32, + pub track: bool, } impl World { @@ -30,8 +31,15 @@ impl World { } } - pub fn set_best(&mut self) { - self.player.color = Some(RED); + pub fn track(&mut self, track: bool) { + self.player.color = if track { Some(RED) } else { None }; + for asteroid in &mut self.asteroids { + asteroid.color = if track { + Color::new(1., 0., 0., 0.8) + } else { + Color::new(1., 1., 1., 0.2) + }; + } } pub fn see_brain(&self) -> &NN { @@ -44,6 +52,7 @@ impl World { } pub fn update(&mut self) { + self.player.update(); let mut to_add: Vec = Vec::new(); for asteroid in &mut self.asteroids { asteroid.update(); @@ -85,7 +94,6 @@ impl World { } self.fitness = (self.score / self.player.shots as f32).powi(2) * self.player.lifespan as f32; - self.player.update(); self.asteroids.append(&mut to_add); self.asteroids.retain(|asteroid| asteroid.alive); // if self.asteroids.iter().fold(0, |acc, x| { @@ -103,8 +111,8 @@ impl World { } } - pub fn draw(&self) { - self.player.draw(); + pub fn draw(&self, debug: bool) { + self.player.draw(debug); for asteroid in &self.asteroids { asteroid.draw(); } @@ -156,33 +164,38 @@ impl World { draw_circle(l1.x, l1.y, 5., WHITE); draw_circle(l1.x, l1.y, 3.5, BLACK); } - draw_text( + let params = TextParams { + font_size: 48, + font_scale: 0.5, + ..Default::default() + }; + draw_text_ex( if self.over { "DEAD" } else { "ALIVE" }, -width * 0.5 + 20., 70., - 24., - if self.over { RED } else { GREEN }, + { + let mut p = params.clone(); + p.color = if self.over { RED } else { GREEN }; + p + }, ); - draw_text( + draw_text_ex( &format!("Hits: {}", self.score), -width * 0.5 + 20., 90., - 24., - WHITE, + params, ); - draw_text( + draw_text_ex( &format!("Fired: {}", self.player.shots), -width * 0.5 + 20., 110., - 24., - WHITE, + params, ); - draw_text( + draw_text_ex( &format!("Fitness: {:.2}", self.fitness), -width * 0.5 + 20., 130., - 24., - WHITE, + params, ); } }