From 86be0bf2dda5580ce384ad4a1de6b248ca572bb6 Mon Sep 17 00:00:00 2001 From: Toby Vincent Date: Thu, 3 Aug 2023 10:38:15 -0500 Subject: wip --- src/entity/player.rs | 19 +++++++--- src/error.rs | 3 ++ src/game.rs | 43 ++++++++++++++++++---- src/lib.rs | 28 +++------------ src/main.rs | 2 +- src/physics.rs | 92 +++++++++++++++++++++++++---------------------- src/physics/error.rs | 20 +++++++++++ src/physics/point.rs | 44 +++++++++++++++++++++++ src/physics/vector.rs | 25 +++++++++++++ src/structure.rs | 7 ++-- src/structure/building.rs | 21 ++++++++++- 11 files changed, 222 insertions(+), 82 deletions(-) create mode 100644 src/physics/error.rs create mode 100644 src/physics/point.rs create mode 100644 src/physics/vector.rs diff --git a/src/entity/player.rs b/src/entity/player.rs index 45f3e13..e1961df 100644 --- a/src/entity/player.rs +++ b/src/entity/player.rs @@ -1,3 +1,4 @@ +use core::fmt; use std::{ collections::HashMap, fmt::{Display, Formatter}, @@ -7,8 +8,8 @@ use termion::event::Key; use crate::{ game::Command, - physics::{Point, Vector}, - Position, Render, Velocity, + physics::{Collidable, Collider, Point, Position, Vector, Velocity}, + Render, }; use crate::entity::Controllable; @@ -31,7 +32,7 @@ impl Player { } impl Display for Player { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { return write!( f, "{}@", @@ -64,7 +65,7 @@ impl Position for Player { self.position } - fn set_position>(&mut self, position: P) -> crate::Result<()> { + fn set_position>(&mut self, position: P) -> crate::physics::Result<()> { self.position = position.into(); Ok(()) } @@ -75,8 +76,16 @@ impl Velocity for Player { self.velocity } - fn set_velocity>(&mut self, velocity: V) -> crate::Result<()> { + fn set_velocity>(&mut self, velocity: V) -> crate::physics::Result<()> { self.velocity = velocity.into(); Ok(()) } } + +impl Collider for Player { + fn collision_map(&self) -> &Vec { + &vec![self.position] + } +} + +impl Collidable for Player {} diff --git a/src/error.rs b/src/error.rs index 81dd4fa..fb73c8d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,9 @@ pub type Result = std::result::Result; #[derive(Debug, thiserror::Error)] pub enum Error { + #[error("Failed to parse key input: {0:?}")] + Physics(#[from] crate::physics::Error), + #[error("Failed to parse key input: {0:?}")] IO(#[from] std::io::Error), diff --git a/src/game.rs b/src/game.rs index 0358638..b93799d 100644 --- a/src/game.rs +++ b/src/game.rs @@ -7,9 +7,9 @@ use termion::{ use crate::{ entity::{Controllable, Player}, error::Result, - physics::Vector, + physics::{Physics, Vector, Velocity}, structure::Building, - Render, Velocity, + Engine, Render, }; #[derive(Debug)] @@ -32,7 +32,7 @@ impl Game { for key in reader.keys() { match self.handle_input(key?) { Some(Command::Quit) => break, - Some(Command::UpdatePlayer) => &mut self.update()?, + Some(Command::UpdatePlayer) => &mut self.tick_time()?, None => continue, }; self.write_screen(&mut screen)?; @@ -60,9 +60,17 @@ impl Game { } } - fn update(&mut self) -> Result<()> { - self.player.tick_time()?; - self.player.set_velocity(Vector::default()) + fn tick_time(&mut self) -> Result<()> { + self.player.tick_time(self)?; + self.player + .set_velocity(Vector::default()) + .map_err(From::from) + } +} + +impl Engine for Game { + fn get_colliders(&self) -> Vec { + self.structures } } @@ -70,7 +78,7 @@ impl Game { mod tests { use std::io::stdout; - use crate::{structure::Building, Game, Position}; + use crate::{physics::Position, structure::Building, Game}; #[test] fn run_game() { @@ -95,4 +103,25 @@ mod tests { eprintln!("{}", err) } } + + #[test] + fn collisions() { + let stdin = "sssdddq".as_bytes(); + let stdout = stdout(); + + let mut game = Game::default(); + + let building = Building::builder() + .width(50) + .height(50) + .position((10, 10)) + .build(); + + game.player.set_position((5, 5)).unwrap(); + game.structures.push(building); + + if let Err(err) = game.run_loop(stdin, stdout) { + eprintln!("{}", err) + } + } } diff --git a/src/lib.rs b/src/lib.rs index aed9bcc..f949411 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,11 +2,15 @@ pub use crate::error::{Error, Result}; pub use crate::game::Game; pub mod entity; +pub mod physics; pub mod structure; mod error; mod game; -mod physics; + +pub trait Engine { + fn get_colliders(&self) -> Vec; +} pub trait Render { fn render_map(&self) -> &std::collections::HashMap; @@ -33,25 +37,3 @@ impl Derender for T { self.render_map() } } - -pub trait Collision { - fn collision_map(&self) -> &Vec; - fn is_collision>(&self, point: P) -> bool { - self.collision_map().contains(&point.into()) - } -} - -pub trait Position { - fn get_position(&self) -> crate::physics::Point; - fn set_position>(&mut self, position: P) -> crate::Result<()>; -} - -pub trait Velocity: Position { - fn get_velocity(&self) -> crate::physics::Vector; - - fn set_velocity>(&mut self, velocity: V) -> crate::Result<()>; - - fn tick_time(&mut self) -> Result<()> { - self.set_position(self.get_position() + self.get_velocity()) - } -} diff --git a/src/main.rs b/src/main.rs index 95b6ea3..9b49ea6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,6 @@ use std::io::{stdin, stdout}; -use rustic_adventure::{structure::Building, Game, Position}; +use rustic_adventure::{physics::Position, structure::Building, Game}; fn main() { let stdin = stdin(); diff --git a/src/physics.rs b/src/physics.rs index de09a2f..458f1e7 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,64 +1,70 @@ -use std::ops::Add; +pub(crate) use error::{Error, Result}; +pub use point::Point; +pub use vector::Vector; -#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)] -pub struct Point { - pub x: u16, - pub y: u16, +mod error; +mod point; +mod vector; + +pub trait Physics { + fn tick_time(&mut self, engine: E) -> Result<()>; +} + +pub trait Position { + fn get_position(&self) -> Point; + fn set_position>(&mut self, position: P) -> Result<()>; } -impl Point { - pub fn new(x: u16, y: u16) -> Self { - Self { x, y } +pub trait Velocity: Position { + fn get_velocity(&self) -> Vector; + + fn set_velocity>(&mut self, velocity: V) -> Result<()>; + + fn apply_velocity(&mut self) -> Result<()> { + self.set_position(self.get_position() + self.get_velocity()) } - pub fn add_velocity(&mut self, velocity: Vector) { - self.x += velocity.x; - self.y += velocity.y; + fn reset_velocity(&mut self) -> Result<()> { + self.set_velocity(Vector::default()) } } -impl From<(u16, u16)> for Point { - fn from((x, y): (u16, u16)) -> Self { - Self { x, y } - } +pub trait Collider { + fn collision_map(&self) -> &Vec; } -impl From for (u16, u16) { - fn from(point: Point) -> Self { - (point.x, point.y) +pub trait Collidable: Collider + Velocity { + fn next_collision_map(&self) -> Vec { + let velocity = self.get_velocity(); + self.collision_map().iter().map(|p| *p + velocity).collect() } -} -impl Add for Point { - type Output = Self; + fn check_collision(&self, colliders: C) -> Result<()> { + let collision = self + .next_collision_map() + .iter() + .zip(colliders.collision_map()) + .filter_map(|(p1, p2)| p1.eq(p2).then_some(*p1)) + .collect::>(); - fn add(self, rhs: Vector) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, + if !collision.is_empty() { + Ok(()) + } else { + Err(Error::Collision(collision)) } } -} - -#[derive(Debug, Default, Clone, Copy)] -pub struct Vector { - pub x: u16, - pub y: u16, -} -impl Vector { - pub fn new(x: u16, y: u16) -> Self { - Self { x, y } + fn check_colliders(&self, colliders: Vec) -> Result<()> { + for collidable in colliders { + self.check_collision(collidable)? + } + Ok(()) } } -impl Add for Vector { - type Output = Self; - - fn add(self, rhs: Vector) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - } +impl Physics for T { + fn tick_time(&mut self, engine: E) -> Result<()> { + self.check_colliders(engine.get_colliders())?; + self.apply_velocity() } } diff --git a/src/physics/error.rs b/src/physics/error.rs new file mode 100644 index 0000000..4ceb325 --- /dev/null +++ b/src/physics/error.rs @@ -0,0 +1,20 @@ +use std::fmt::Display; + +use super::Point; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum Error { + Collision(Vec), +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Collision(v) => write!(f, "Collision with collidable at: {:?}", v), + } + } +} diff --git a/src/physics/point.rs b/src/physics/point.rs new file mode 100644 index 0000000..75bccb4 --- /dev/null +++ b/src/physics/point.rs @@ -0,0 +1,44 @@ +use std::ops::Add; + +use super::vector::Vector; + +#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)] +pub struct Point { + pub x: u16, + pub y: u16, +} + +impl Point { + pub fn new(x: u16, y: u16) -> Self { + Self { x, y } + } + + pub fn add_velocity(&mut self, velocity: Vector) { + self.x += velocity.x; + self.y += velocity.y; + } +} + +impl From<(u16, u16)> for Point { + fn from((x, y): (u16, u16)) -> Self { + Self { x, y } + } +} + +impl From for (u16, u16) { + fn from(point: Point) -> Self { + (point.x, point.y) + } +} + +impl Add for Point { + type Output = Self; + + fn add(self, rhs: Vector) -> Self::Output { + Self { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + diff --git a/src/physics/vector.rs b/src/physics/vector.rs new file mode 100644 index 0000000..48e02e8 --- /dev/null +++ b/src/physics/vector.rs @@ -0,0 +1,25 @@ +use std::ops::Add; + +#[derive(Debug, Default, Clone, Copy)] +pub struct Vector { + pub x: u16, + pub y: u16, +} + +impl Vector { + pub fn new(x: u16, y: u16) -> Self { + Self { x, y } + } +} + +impl Add for Vector { + type Output = Self; + + fn add(self, rhs: Vector) -> Self::Output { + Self { + x: self.x + rhs.x, + y: self.y + rhs.y, + } + } +} + diff --git a/src/structure.rs b/src/structure.rs index 2137766..f8575b1 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -2,7 +2,10 @@ use std::collections::HashMap; pub use building::Building; -use crate::{physics::Point, Collision, Render}; +use crate::{ + physics::{Collider, Point}, + Render, +}; mod building; @@ -17,7 +20,7 @@ impl Render for Structure { } } -impl Collision for Structure { +impl Collider for Structure { fn collision_map(&self) -> &Vec { &self.collision_map } diff --git a/src/structure/building.rs b/src/structure/building.rs index b6c6346..55961dd 100644 --- a/src/structure/building.rs +++ b/src/structure/building.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; -use crate::{physics::Point, Render}; +use crate::{ + physics::{Collider, Point}, + Render, +}; #[derive(Debug, PartialEq, Eq)] pub struct Building { @@ -78,6 +81,22 @@ impl Render for Building { &self.render_map } } + +impl Collider for Building { + fn collision_map(&self) -> &Vec { + let collision_map = Vec::new(); + for x in self.position.x..self.width { + collision_map.push((x, self.position.y).into()); + collision_map.push((x, self.height).into()); + } + for y in self.position.y..self.height { + collision_map.push((self.position.x, y).into()); + collision_map.push((self.width, y).into()); + } + &collision_map + } +} + #[cfg(test)] mod tests { use std::collections::HashMap; -- cgit v1.2.3-70-g09d2