diff --git a/README.md b/README.md index 54b8d36..d4e7177 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This game was written with hope to be a good example of game development in Rust Download binary (64-bit Windows and Linux) here: https://github.com/juchiast/boxcrash/releases -This code should be compiled with the latest stable version of Rust (1.15.1 as of this writing). +This code should be compiled with the latest stable version of Rust (1.16.0 as of this writing). Almost all game's constants are configurable via `resources/config.json`. You should edit the screen size details to match your monitor. @@ -38,7 +38,7 @@ This seem to be a piston\_window's bug. - Write an article about the writing of this code. - Fix some known bugs. - Test game on more machines. -- Write a GUI to configure and restart game. +- ~~Write a GUI to configure and restart game~~ (Done). - Draw more details of box and the road. - Add crashing animations. - Add some sounds. diff --git a/src/main.rs b/src/main.rs index ac154cc..a73b0f5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,8 @@ mod bot; mod game; mod ui; +type Rendered = Vec<([cgmath::Vector2; 2], color::Color)>; + // Pixel present a point in the window and window's size #[derive(Clone, Serialize, Deserialize)] pub struct Pixel { diff --git a/src/tunel.rs b/src/tunel.rs index c1437f4..82fcc63 100644 --- a/src/tunel.rs +++ b/src/tunel.rs @@ -1,4 +1,4 @@ -use cgmath::{Vector2, Vector3}; +use cgmath::{Vector2, Vector3, vec3}; use color::*; use camera::Camera; @@ -8,13 +8,23 @@ pub struct Tunel { pub size: Vector3, // Color to draw tunel pub color: Color, + // Road's dividers + pub divider: Vector2, + pub divider_state: f64, + // Tunel's decorations + pub decor_distance: f64, + pub decor_state: f64, } impl Tunel { - pub fn new(size: [f64; 3]) -> Tunel { + pub fn new(config: &::game::GameConfig) -> Tunel { Tunel { - size: size.into(), + size: config.tunel_size.into(), color: BLUE, + divider: config.divider_size.into(), + divider_state: config.divider_size[1], + decor_distance: config.decor_distance, + decor_state: config.decor_distance, } } @@ -25,6 +35,66 @@ impl Tunel { ((0., self.size.y, 0.), (0., self.size.y, self.size.z)), ((self.size.x, self.size.y, 0.), (self.size.x, self.size.y, self.size.z)), ].into_iter().map(|(a, b)| camera.render_line(&a.into(), &b.into())) - .filter_map(|x| x.map(|x| (x, self.color))).collect() + .filter_map(|x| x.map(|x| (x, self.color))) + .chain(self.divider_render(camera)) + .chain(self.decor_render(camera)) + .collect() } + + pub fn update(&mut self, dt: f64, speed: f64) { + self.divider_state -= dt*speed; + if self.divider_state < 0. { + self.divider_state += 2.*self.divider.y; + } + self.decor_state -= dt*speed; + if self.decor_state < 0. { + self.decor_state += self.decor_distance; + } + } + + fn divider_render(&self, camera: &Camera) -> ::Rendered { + let mut points = [vec3(self.size.x/2., 0., self.divider_state); 4]; + points[2].z -= self.divider.y; points[3].z -= self.divider.y; + points[0].x -= self.divider.x/2.; points[3].x -= self.divider.x/2.; + points[1].x += self.divider.x/2.; points[2].x += self.divider.x/2.; + + let mut ret = Vec::new(); + { + let mut r = |p: &[Vector3; 4]| { + let iter = p.iter().zip(p.iter().cycle().skip(1)) + .map(|(x, y)| camera.render_line(x, y)) + .filter_map(|x| x.map(|x| (x, self.color))); + ret.append(&mut iter.collect()); + }; + while points[0].z <= self.size.z { + r(&points); + for p in &mut points { + p.z += 2.*self.divider.y; + } + } + r(&points); + } + ret + } + fn decor_render(&self, camera: &Camera) -> ::Rendered { + let mut data = [ + vec3(0., 0., self.decor_state), + vec3(0., self.size.y, self.decor_state), + vec3(self.size.x, self.size.y, self.decor_state), + vec3(self.size.x, 0., self.decor_state), + ]; + let mut ret = Vec::new(); + while data[0].z <= self.size.z { + for (x, y) in data.iter().zip(data.iter().skip(1)) { + if let Some(rendered) = camera.render_line(x, y) { + ret.push((rendered, self.color)); + } + } + for x in &mut data { + x.z += self.decor_distance; + } + } + ret + } + } diff --git a/src/world.rs b/src/world.rs index 02de854..121b9cb 100644 --- a/src/world.rs +++ b/src/world.rs @@ -1,7 +1,7 @@ use tunel::Tunel; use car::*; use color::*; -use cgmath::{Vector2, Vector3, vec3}; +use cgmath::{Vector3, vec3}; use cgmath::prelude::*; use game::GameConfig; use camera::Camera; @@ -11,64 +11,9 @@ pub struct World { pub tunel: Tunel, pub player: BoxCar, pub bots: Vec, - pub divider: Vector2, - pub decor_distance: f64, - pub divider_state: f64, - pub decor_state: f64, pub bullets: Vec<[Vector3; 3]>, } -type Rendered = Vec<([Vector2; 2], Color)>; impl World { - fn divider_render(&self, camera: &Camera) -> Rendered { - let mut points = [vec3(self.tunel.size.x/2., 0., self.divider_state); 4]; - points[2].z -= self.divider.y; points[3].z -= self.divider.y; - points[0].x -= self.divider.x/2.; points[3].x -= self.divider.x/2.; - points[1].x += self.divider.x/2.; points[2].x += self.divider.x/2.; - - let mut ret = Vec::new(); - { - let mut r = |p: &[Vector3; 4]| { - let iter = p.iter().zip(p.iter().cycle().skip(1)) - .map(|(x, y)| camera.render_line(x, y)) - .filter_map(|x| x.map(|x| (x, self.tunel.color))); - ret.append(&mut iter.collect()); - }; - while points[0].z <= self.tunel.size.z { - r(&points); - for p in &mut points { - p.z += 2.*self.divider.y; - } - } - r(&points); - } - ret - } - fn decor_render(&self, camera: &Camera) -> Rendered { - let mut data = [ - vec3(0., 0., self.decor_state), - vec3(0., self.tunel.size.y, self.decor_state), - vec3(self.tunel.size.x, self.tunel.size.y, self.decor_state), - vec3(self.tunel.size.x, 0., self.decor_state), - ]; - let mut ret = Vec::new(); - while data[0].z <= self.tunel.size.z { - for (x, y) in data.iter().zip(data.iter().skip(1)) { - if let Some(rendered) = camera.render_line(x, y) { - ret.push((rendered, self.tunel.color)); - } - } - for x in &mut data { - x.z += self.decor_distance; - } - } - ret - } - fn bullets_render(&self, camera: &Camera) -> Rendered { - self.bullets.iter().filter_map(|x| { - camera.render_line(&x[0], &(x[0]+x[1])).map(|x| (x, self.player.color)) - }).collect() - } - pub fn new(config: &GameConfig) -> World { let player = BoxCar { size: config.player_size.into(), @@ -84,38 +29,25 @@ impl World { }; World { - tunel: Tunel::new(config.tunel_size), + tunel: Tunel::new(&config), player: player, bots: Vec::new(), - divider: config.divider_size.into(), - divider_state: config.divider_size[1], - decor_distance: config.decor_distance, - decor_state: config.decor_distance, bullets: Vec::new(), } } - pub fn render(&self, camera: &Camera) -> Rendered { + pub fn render(&self, camera: &Camera) -> ::Rendered { Vec::new().into_iter() .chain(self.tunel.render(camera)) - .chain(self.divider_render(camera)) - .chain(self.decor_render(camera)) .chain(self.player.render(camera)) .chain(self.bots.iter().flat_map(|x| x.render(camera))) .chain(self.bullets_render(camera)) .collect() } pub fn update(&mut self, dt: f64, game_speed: f64) { - self.player.update_jump(dt); let speed = game_speed + self.player.speed; - self.divider_state -= dt*speed; - if self.divider_state < 0. { - self.divider_state += 2.*self.divider.y; - } - self.decor_state -= dt*speed; - if self.decor_state < 0. { - self.decor_state += self.decor_distance; - } + self.player.update_jump(dt); + self.tunel.update(dt, speed); for x in &mut self.bots { x.drive(dt); x.forward(dt, speed); @@ -168,4 +100,10 @@ impl World { direction, ]); } + + fn bullets_render(&self, camera: &Camera) -> ::Rendered { + self.bullets.iter().filter_map(|x| { + camera.render_line(&x[0], &(x[0]+x[1])).map(|x| (x, self.player.color)) + }).collect() + } }