Add collision detection methods

This commit is contained in:
Yash Karandikar 2022-04-12 13:09:28 -05:00
parent 3eb772cbd5
commit 49619bd141
3 changed files with 109 additions and 38 deletions

View file

@ -83,17 +83,26 @@
//! }
//! ```
use std::{cell::Cell, path::Path, ops::{DerefMut, Deref}, slice::IterMut};
pub mod physics;
use std::{
cell::Cell,
ops::{Deref, DerefMut},
path::Path,
slice::IterMut,
};
use sdl2::{
image::ImageRWops,
keyboard::Scancode,
mouse::MouseButton,
rect::Rect,
render::{Canvas, TextureCreator, TextureValueError},
rwops::RWops,
surface::Surface,
ttf::{FontError, Sdl2TtfContext},
video::{Window, WindowBuildError, WindowContext},
EventPump, IntegerOrSdlError, mouse::MouseButton, keyboard::Scancode,
EventPump, IntegerOrSdlError,
};
#[doc(no_inline)]
@ -292,9 +301,7 @@ impl SpriteCollection {
/// let sprites = SpriteCollection::new();
/// ```
pub fn new() -> Self {
Self {
v: Vec::new()
}
Self { v: Vec::new() }
}
/// Creates a new [`SpriteCollection`] with the specified capacity.
@ -306,7 +313,7 @@ impl SpriteCollection {
/// ```
pub fn with_capacity(cap: usize) -> Self {
Self {
v: Vec::with_capacity(cap)
v: Vec::with_capacity(cap),
}
}
@ -424,6 +431,11 @@ impl SpriteCollection {
pub fn get(&self, index: usize) -> Option<&Sprite> {
self.v.get(index)
}
/// Return the inner Vec. Only use this method if you know what you're doing.
pub fn inner(&self) -> &Vec<Sprite> {
&self.v
}
}
impl Deref for SpriteCollection {
@ -464,8 +476,18 @@ impl Context {
/// Get the inner [`Canvas`](sdl2::render::Canvas) and [`TextureCreator`](sdl2::render::TextureCreator).
///
/// Only use this method if you know what you're doing.
pub fn inner(&mut self) -> (&TextureCreator<WindowContext>, &mut Canvas<Window>, &mut EventPump) {
(&self.texture_creator, &mut self.canvas, &mut self.event_pump)
pub fn inner(
&mut self,
) -> (
&TextureCreator<WindowContext>,
&mut Canvas<Window>,
&mut EventPump,
) {
(
&self.texture_creator,
&mut self.canvas,
&mut self.event_pump,
)
}
fn update(&mut self) {
@ -560,12 +582,12 @@ pub fn draw_text<S: AsRef<str>>(
pub struct MouseRepr {
pub buttons: Vec<MouseButton>,
pub x: i32,
pub y: i32
pub y: i32,
}
/// Representation of the keyboard state.
pub struct KeyboardRepr {
pub keys: Vec<Scancode>
pub keys: Vec<Scancode>,
}
/// Get the mouse state.
@ -604,7 +626,7 @@ pub fn get_keyboard_state(ctx: &mut Context) -> KeyboardRepr {
let keyboard = pump.keyboard_state();
KeyboardRepr {
keys: keyboard.pressed_scancodes().collect()
keys: keyboard.pressed_scancodes().collect(),
}
}

View file

@ -1,4 +1,4 @@
use cat_box::{draw_text, Game, Sprite, SpriteCollection, get_mouse_state, get_keyboard_state};
use cat_box::{draw_text, get_keyboard_state, get_mouse_state, Game, Sprite, SpriteCollection};
use sdl2::keyboard::Scancode;
fn main() {
@ -57,7 +57,7 @@ fn main() {
Scancode::Escape => {
game.terminate();
(0, 0)
},
}
Scancode::W | Scancode::Up => (0, 5),
Scancode::S | Scancode::Down => (0, -5),
Scancode::A | Scancode::Left => (-5, 0),
@ -72,6 +72,10 @@ fn main() {
}
}
if !cat_box::physics::check_for_collision_with_collection(&s2, &coll).is_empty() {
println!("Sprites collided! {}", i);
}
s2.draw(ctx).unwrap();
s.draw(ctx).unwrap();
coll.draw(ctx).unwrap();

45
src/physics.rs Normal file
View file

@ -0,0 +1,45 @@
use crate::{Sprite, SpriteCollection};
use std::cmp::max;
// https://github.com/pythonarcade/arcade/blob/d2ce45a9b965020cde57a2a88536311e04504e6e/arcade/sprite_list/spatial_hash.py#L356
fn collided(sprite1: &Sprite, sprite2: &Sprite) -> bool {
let coll_rad1 = max(sprite1.rect.width(), sprite1.rect.height()) as i32;
let coll_rad2 = max(sprite2.rect.width(), sprite2.rect.height()) as i32;
let collision_radius = coll_rad1 + coll_rad2;
let collision_diameter = collision_radius * collision_radius;
let diff_x = sprite1.position().0 - sprite2.position().0;
let diff_x2 = diff_x * diff_x;
if diff_x2 > collision_diameter {
return false;
}
let diff_y = sprite1.position().1 - sprite2.position().1;
let diff_y2 = diff_y * diff_y;
if diff_y2 > collision_diameter {
return false;
}
return sprite1.rect.has_intersection(sprite2.rect);
}
/// Check if two sprites are touching or overlapping.
pub fn check_for_collision(sprite1: &Sprite, sprite2: &Sprite) -> bool {
collided(sprite1, sprite2)
}
/// Check if the sprite is colliding with any sprite in the collection, and return a list of
/// references to the sprites which are colliding
pub fn check_for_collision_with_collection<'a>(
sprite: &Sprite,
list: &'a SpriteCollection,
) -> Vec<&'a Sprite> {
list.inner()
.iter()
.filter(|s| check_for_collision(sprite, s))
.collect()
}