diff --git a/Cargo.toml b/Cargo.toml index 46fc4b3e..2ae9de70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,10 @@ edition = "2018" sfml = "0.14.0" quick-xml = "0.13.2" cgmath = "0.17.0" -simple-stopwatch="0.1.4" \ No newline at end of file +simple-stopwatch="0.1.4" +ncollide2d = "0.17" # For 2D collision detection. +nalgebra = "0.16.13" + + + + diff --git a/src/main.rs b/src/main.rs index 37bdabb0..c70a478e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,32 +15,63 @@ use crate::player::Player; use crate::timer::Timer; use crate::input::Input; +extern crate nalgebra as na; +extern crate ncollide2d; + use sfml::graphics::{ Color, RenderTarget, RenderWindow, - Texture, Sprite, IntRect + Texture, Sprite, Transformable }; use sfml::window::{ Event, Key, Style}; -use sfml::system::Vector2; +use sfml::system::Vector2 as sfVec2; +use ncollide2d::bounding_volume::{self, AABB, BoundingVolumeInterferencesCollector}; +use ncollide2d::partitioning::BVT; +use sfml::graphics::RectangleShape; fn main() { + // Load the spritsheet let spritesheet_desc = util::read_spritesheet(String::from("spritesheet_complete.xml")); let spritesheet_text = Texture::from_file("spritesheet_complete.png") .expect("Couldn't load texture"); + let mut block_sprite = Sprite::new(); + block_sprite.set_texture(&spritesheet_text, false); + block_sprite.set_texture_rect(&util::grab_sheet_rec(String::from("blockBrown.png"), &spritesheet_desc)); + block_sprite.set_position((70.0, 70.0)); + + let mut block_sprite2 = Sprite::new(); + block_sprite2.set_texture(&spritesheet_text, false); + block_sprite2.set_texture_rect(&util::grab_sheet_rec(String::from("blockBrown.png"), &spritesheet_desc)); + block_sprite2.set_position((170.0, 170.0)); + + let idx_and_bounding_spheres: Vec<(&Sprite, AABB)> = vec![ + ( + &block_sprite, + { + let bounds = &block_sprite.local_bounds(); + let pos = &block_sprite.position(); + bounding_volume::AABB::new(na::Point2::new(pos.x as f64, pos.y as f64), + na::Point2::new((pos.x + bounds.width) as f64, (pos.y + bounds.width) as f64)) + }, + ), + ( + &block_sprite2, + { + let bounds = &block_sprite2.local_bounds(); + let pos = &block_sprite2.position(); + bounding_volume::AABB::new(na::Point2::new(pos.x as f64, pos.y as f64), + na::Point2::new((pos.x + bounds.width) as f64, (pos.y + bounds.width) as f64)) + }, + ), + ]; + + let bvt = BVT::new_balanced(idx_and_bounding_spheres); + let mut sprite = Sprite::new(); sprite.set_texture(&spritesheet_text, false); - - println!("{:?}", spritesheet_desc); - let sprite_desc = spritesheet_desc.get("enemyflyingalt_4.png").expect("Can't load sprite"); - - sprite.set_texture_rect(&IntRect::new( - *sprite_desc.get("x").unwrap(), - *sprite_desc.get("y").unwrap(), - *sprite_desc.get("width").unwrap(), - *sprite_desc.get("height").unwrap() - )); + sprite.set_texture_rect(&util::grab_sheet_rec(String::from("playerBlue_stand.png"), &spritesheet_desc)); let mut window = RenderWindow::new( (500, 500), @@ -60,8 +91,6 @@ fn main() { let mut accumulator_time: f32 = 0.0; let mut current_time: f32 = timer.elap_time(); - - while window.is_open() { while let Some(event) = window.poll_event() { @@ -78,16 +107,16 @@ fn main() { } if input.is_held(Key::W) { - player.impulse(&Vector2::new(0.0, -1.0)); + player.impulse(&sfVec2::new(0.0, -1.0)); } if input.is_held(Key::A) { - player.impulse(&Vector2::new(-1.0, 0.0)); + player.impulse(&sfVec2::new(-1.0, 0.0)); } if input.is_held(Key::S) { - player.impulse(&Vector2::new(0.0, 1.0)); + player.impulse(&sfVec2::new(0.0, 1.0)); } if input.is_held(Key::D) { - player.impulse(&Vector2::new(1.0, 0.0)); + player.impulse(&sfVec2::new(1.0, 0.0)); } elapsed_time = timer.elap_time(); @@ -100,13 +129,35 @@ fn main() { while (accumulator_time - step_size) >= step_size { accumulator_time -= step_size; + } - + // intersection test + let mut interferences = Vec::new(); + { + let bv = player.bounding_aabb(); + let mut thing = BoundingVolumeInterferencesCollector::new(&bv, &mut interferences); + bvt.visit(&mut thing); } + + let collision_rect = player.collision(&interferences); player.update(delta_time); + + + let mut collision_sprite = RectangleShape::new(); + collision_sprite.set_position((collision_rect.left, collision_rect.top)); + collision_sprite.set_size((collision_rect.width, collision_rect.height)); + + window.clear(&Color::BLACK); window.draw(&player); + window.draw(&collision_sprite); + + if interferences.len() == 0 { + window.draw(&block_sprite); + window.draw(&block_sprite2); + } + window.display(); } diff --git a/src/player.rs b/src/player.rs index 2e02a9cd..070d65b1 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,42 +1,67 @@ use sfml::system::Vector2; -use sfml::graphics::{CircleShape, - Color, - Drawable, - RenderStates, - RenderTarget}; +use sfml::graphics::{CircleShape, Color, Drawable, + RenderStates, RenderTarget}; use sfml::graphics::Transformable; use sfml::graphics::Shape; -use sfml::graphics::RectangleShape; -use sfml::graphics::Rect; +use sfml::graphics::Sprite; +use ncollide2d::bounding_volume::AABB; +use sfml::graphics::FloatRect; pub struct Player<'s> { head: CircleShape<'s>, delta: Vector2, - pos: Vector2, + pub pos: Vector2, } impl<'s> Player<'s> { pub fn impulse(&mut self, delta_v: &Vector2) { - self.delta.x += delta_v.x; - self.delta.y += delta_v.y; + self.delta.x += delta_v.x * 2.0; + self.delta.y += delta_v.y * 2.0; } - pub fn collision(&mut self, objects: Vec>) { + pub fn collision(&mut self, objects: &Vec<&Sprite>) -> FloatRect { + + let mut collided = FloatRect::new(0.0,0.0,0.0,0.0); for i in objects { + match self.head.global_bounds().intersection(&i.global_bounds()) { + Some(r) => { + let tested = &i.global_bounds(); - match self.head.local_bounds().intersection(&i) { - Some(r) => println!("{:?}", r), +// if r.width > tested.width / 2.0 { +// self.delta.x = 1.0; +// } else if r.width < tested.width / 2.0 { +// self.delta.x = -1.0; +// } +// +// if r.height > tested.height / 2.0 { +// self.delta.y = -1.0; +// } else if r.height < tested.height / 2.0 { +// self.delta.y = 1.0; +// } + //println!("{:?}", r); + collided = r; + }, None => continue } } + + return collided; + } + + pub fn bounding_aabb(&mut self) -> AABB { + let pos = self.pos; + let a = na::Point2::new(pos.x as f64, pos.y as f64); + let b = na::Point2::new((pos.x + 10.0) as f64, (pos.y + 10.0) as f64); + AABB::new(a, b) } pub fn update(&mut self, delta_t: f32) { self.pos.x += self.delta.x * delta_t * 1.0; self.pos.y += self.delta.y * delta_t * 1.0; - self.delta *= 0.999; + let friction = 10.0 * self.delta; + self.delta -= friction * delta_t; self.head.set_position((self.pos.x, self.pos.y)); } diff --git a/src/util.rs b/src/util.rs index 9b0e13f1..5ffd383d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -3,8 +3,10 @@ use quick_xml::events::Event as xmlEvent; use std::collections::HashMap; use std::borrow::Cow; use std::str::FromStr; +use sfml::graphics::IntRect; pub fn read_spritesheet(filename: String) -> HashMap> { + let mut reader = Reader::from_file(filename).unwrap(); reader.trim_text(true); @@ -16,8 +18,6 @@ pub fn read_spritesheet(filename: String) -> HashMap { match e.name() { - b"TextureAtlas" => println!("attributes values: {:?}", - e.attributes().map(|a| a.unwrap().value).collect::>()), _ => (), } }, @@ -41,7 +41,7 @@ pub fn read_spritesheet(filename: String) -> HashMap String::from_utf8_lossy(&r), Cow::Owned(_) => break }; - name = value.to_lowercase() + name = value.to_string(); } else { let value = match attr.value { @@ -64,4 +64,15 @@ pub fn read_spritesheet(filename: String) -> HashMap>) -> IntRect { + + let block_desc = spritesheet.get(&spritename).expect("Can't load sprite"); + IntRect::new( + *block_desc.get("x").unwrap(), + *block_desc.get("y").unwrap(), + *block_desc.get("width").unwrap(), + *block_desc.get("height").unwrap() + ) } \ No newline at end of file