From ffd257fc7bddc882a4687f622c0415d1d4b0bff1 Mon Sep 17 00:00:00 2001 From: gallant Date: Tue, 25 Apr 2023 09:21:59 -0500 Subject: [PATCH] orgranization for my evil plans --- examples/example_1.rs | 2 +- src/lib.rs | 322 +--------------------------------- src/sprite/mod.rs | 2 + src/{ => sprite}/physics.rs | 0 src/sprite/sprite.rs | 332 ++++++++++++++++++++++++++++++++++++ 5 files changed, 338 insertions(+), 320 deletions(-) create mode 100644 src/sprite/mod.rs rename src/{ => sprite}/physics.rs (100%) create mode 100644 src/sprite/sprite.rs diff --git a/examples/example_1.rs b/examples/example_1.rs index 03fbddf..45bb367 100644 --- a/examples/example_1.rs +++ b/examples/example_1.rs @@ -84,7 +84,7 @@ fn main() { } } - if !cat_box::physics::check_for_collision_with_collection(&s2, &coll).is_empty() { + if !cat_box::check_for_collision_with_collection(&s2, &coll).is_empty() { println!("Sprites collided! {i}"); } diff --git a/src/lib.rs b/src/lib.rs index 3c9ff7f..4306030 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,26 +93,23 @@ #![cfg_attr(docsrs, feature(doc_cfg))] pub mod math; -pub mod physics; +pub mod sprite; +pub use sprite::sprite::{Sprite,SpriteCollection}; +pub use sprite::physics::*; #[cfg(feature = "audio")] use rodio::{self, source::Source, Decoder, OutputStream}; use sdl2::{ - image::ImageRWops, mouse::MouseButton, rect::Rect, render::{Canvas, TextureCreator, TextureValueError}, - rwops::RWops, - surface::Surface, ttf::{FontError, InitError, Sdl2TtfContext}, video::{Window, WindowBuildError, WindowContext}, EventPump, IntegerOrSdlError, }; use std::{ cell::Cell, - ops::{Deref, DerefMut}, path::Path, - slice::IterMut, time::Instant, }; @@ -205,319 +202,6 @@ impl Iterator for Events { } } -/// Representation of a sprite. -pub struct Sprite { - pub rect: Rect, - surf: Surface<'static>, - angle: f64, -} - -impl Sprite { - /// Create a new Sprite. The `path` is relative to the current directory while running. - /// - /// Don't forget to call [`draw()`](Self::draw()) after this. - /// ``` - /// # use cat_box::*; - /// let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// ``` - pub fn new>(path: P, x: i32, y: i32) -> Result { - let ops = RWops::from_file(path, "r")?; - let surf = ops.load()?; - - let srect = surf.rect(); - let dest_rect: Rect = Rect::from_center((x, y), srect.width(), srect.height()); - - Ok(Self { - rect: dest_rect, - surf, - angle: 0.0, - }) - } - - /// Create a new sprite using a slice of bytes, like what is returned from `include_bytes!` - /// - /// Don't forget to call [`draw()`](Self::draw()) after this. - /// ``` - /// # use cat_box::*; - /// let bytes = include_bytes!("../duck.png"); - /// let s = Sprite::from_bytes(bytes, 500, 400).unwrap(); - /// ``` - pub fn from_bytes>(bytes: B, x: i32, y: i32) -> Result { - let ops = RWops::from_bytes(bytes.as_ref())?; - let surf = ops.load()?; - - let srect = surf.rect(); - let dest_rect: Rect = Rect::from_center((x, y), srect.width(), srect.height()); - - Ok(Self { - rect: dest_rect, - surf, - angle: 0.0, - }) - } - - /// Draws the sprite to the window. This should only be called inside your main event loop. - /// - /// ```no_run - /// # use cat_box::*; - /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); - /// # let game = Game::new("sprite demo", 1000, 1000); - /// # game.run(|ctx| { - /// s.draw(ctx); - /// # }); - /// ``` - pub fn draw(&mut self, ctx: &mut Context) -> Result<()> { - let (creator, canvas, _) = ctx.inner(); - let text = creator.create_texture_from_surface(&self.surf)?; - - canvas.copy_ex(&text, None, self.rect, self.angle, None, false, false)?; - - Ok(()) - } - - /// Translate the sprite, in the form of (delta x, delta y) - /// - /// ``` - /// # use cat_box::*; - /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); - /// s.translate((5, 10)); - /// ``` - pub fn translate>(&mut self, position: I) { - let position = position.into(); - let new_x = self.rect.x() + position.x; - let new_y = self.rect.y() - position.y; - - self.rect.set_x(new_x); - self.rect.set_y(new_y); - } - - /// Reposition the center of the sprite in the form of (x, y) - /// - /// ``` - /// # use cat_box::*; - /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); - /// s.set_position((5, 10)); - /// ``` - pub fn set_position>(&mut self, position: I) { - let position = position.into(); - self.rect.center_on((position.x, position.y)); - } - - /// Set the angle of the sprite, in degrees of clockwise rotation. - /// - /// ``` - /// # use cat_box::*; - /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); - /// s.set_angle(45.0); - /// ``` - pub fn set_angle(&mut self, angle: f64) { - self.angle = angle; - } - - /// Get the angle of the sprite, in degrees of clockwise rotation. - /// - /// ``` - /// # use cat_box::*; - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// let angle = s.angle(); - /// ``` - #[must_use] - pub fn angle(&self) -> f64 { - self.angle - } - - /// Get the x and y coordinates of the center of the sprite, in the form of (x, y). - /// - /// ``` - /// # use cat_box::*; - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// let (x, y) = s.position().into(); - /// ``` - #[must_use] - pub fn position(&self) -> Vec2Int { - self.rect.center().into() - } -} - -/// Manages a collection of [`Sprite`]s. -/// -/// Technically, this is a thin wrapper around a simple [`Vec`] of sprites, -/// although with some convenience methods. -#[derive(Default)] -pub struct SpriteCollection { - v: Vec, -} - -impl SpriteCollection { - /// Creates a new [`SpriteCollection`]. - /// - /// See [`Vec::new()`] for more information. - /// ``` - /// # use cat_box::*; - /// let sprites = SpriteCollection::new(); - /// ``` - #[must_use] - pub fn new() -> Self { - Self { v: Vec::new() } - } - - /// Creates a new [`SpriteCollection`] with the specified capacity. - /// - /// The collection will be able to hold exactly `capacity` items without reallocating. - /// ``` - /// # use cat_box::*; - /// let sprites = SpriteCollection::with_capacity(10); - /// ``` - #[must_use] - pub fn with_capacity(cap: usize) -> Self { - Self { - v: Vec::with_capacity(cap), - } - } - - /// Draw all the sprites in this collection to the window. - /// This should only be called inside the main event loop. - /// ```no_run - /// # use cat_box::*; - /// # let mut sprites = SpriteCollection::new(); - /// # let mut game = Game::new("asjdfhalksjdf", 1, 1); - /// # game.run(|ctx| { - /// sprites.draw(ctx); - /// # }); - /// ``` - pub fn draw(&mut self, ctx: &mut Context) -> Result<()> { - for s in &mut self.v { - s.draw(ctx)?; - } - - Ok(()) - } - - /// Add a new [`Sprite`] to the end of this collection. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// sprites.push(s); - /// ``` - pub fn push(&mut self, s: Sprite) { - self.v.push(s); - } - - /// Inserts an element at position `index` within the collection. - /// Shifts all elements after it to the right. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// sprites.insert(s, 0); - /// ``` - pub fn insert(&mut self, s: Sprite, index: usize) { - self.v.insert(index, s); - } - - /// Removes and returns the last element, or `None` if the collection is empty. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// let s = sprites.pop(); - /// ``` - pub fn pop(&mut self) -> Option { - self.v.pop() - } - - /// Removes and returns the element at `index`. - /// Shifts all elements after it to the left. - /// This method will panic if the index is out of bounds. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// # sprites.push(s); - /// sprites.remove(0); - /// ``` - pub fn remove(&mut self, index: usize) -> Sprite { - self.v.remove(index) - } - - /// Return an iterator over the sprites in this collection. - /// Use this to modify the sprites themselves, for example to set their position or angle. - pub fn iter(&mut self) -> IterMut<'_, Sprite> { - self.v.iter_mut() - } - - /// Clears the collection, without touching the allocated capacity. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// # sprites.push(s); - /// sprites.clear(); - /// ``` - pub fn clear(&mut self) { - self.v.clear(); - } - - /// Move all the elements of `other` into `Self`. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// let mut sprites2 = SpriteCollection::new(); - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// # let s2 = Sprite::new("duck.png", 400, 500).unwrap(); - /// # sprites.push(s); - /// # sprites2.push(s2); - /// sprites.concat(sprites2); - /// ``` - pub fn concat(&mut self, mut other: SpriteCollection) { - self.v.append(&mut *other); - } - - /// Returns the length of this vector. - #[must_use] - pub fn len(&self) -> usize { - self.v.len() - } - - /// Get a reference to the element at `index`, or `None` if it doesn't exist. - /// ``` - /// # use cat_box::*; - /// let mut sprites = SpriteCollection::new(); - /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); - /// # sprites.push(s); - /// let s = sprites.get(0); - /// ``` - #[must_use] - 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. - #[must_use] - pub fn inner(&self) -> &Vec { - &self.v - } - - #[must_use] - pub fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -impl Deref for SpriteCollection { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.v - } -} - -impl DerefMut for SpriteCollection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.v - } -} - /// Game context. /// /// In most cases, this should never actually be used; instead, just pass it around to the various cat-box functions such as [`Sprite::draw()`]. diff --git a/src/sprite/mod.rs b/src/sprite/mod.rs new file mode 100644 index 0000000..cd7a3a6 --- /dev/null +++ b/src/sprite/mod.rs @@ -0,0 +1,2 @@ +pub mod sprite; +pub mod physics; \ No newline at end of file diff --git a/src/physics.rs b/src/sprite/physics.rs similarity index 100% rename from src/physics.rs rename to src/sprite/physics.rs diff --git a/src/sprite/sprite.rs b/src/sprite/sprite.rs new file mode 100644 index 0000000..a66b223 --- /dev/null +++ b/src/sprite/sprite.rs @@ -0,0 +1,332 @@ +use sdl2::{ + image::ImageRWops, + rect::Rect, + rwops::RWops, + surface::Surface, +}; +use std::{ + ops::{Deref, DerefMut}, + path::Path, + slice::IterMut, +}; + +use crate::math::vec2::Vec2Int; + +use crate::{ + Context, + Result +}; + + +/// Representation of a sprite. +pub struct Sprite { + pub rect: Rect, + surf: Surface<'static>, + angle: f64, +} + +impl Sprite { + /// Create a new Sprite. The `path` is relative to the current directory while running. + /// + /// Don't forget to call [`draw()`](Self::draw()) after this. + /// ``` + /// # use cat_box::*; + /// let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// ``` + pub fn new>(path: P, x: i32, y: i32) -> Result { + let ops = RWops::from_file(path, "r")?; + let surf = ops.load()?; + + let srect = surf.rect(); + let dest_rect: Rect = Rect::from_center((x, y), srect.width(), srect.height()); + + Ok(Self { + rect: dest_rect, + surf, + angle: 0.0, + }) + } + + /// Create a new sprite using a slice of bytes, like what is returned from `include_bytes!` + /// + /// Don't forget to call [`draw()`](Self::draw()) after this. + /// ``` + /// # use cat_box::*; + /// let bytes = include_bytes!("../../duck.png"); + /// let s = Sprite::from_bytes(bytes, 500, 400).unwrap(); + /// ``` + pub fn from_bytes>(bytes: B, x: i32, y: i32) -> Result { + let ops = RWops::from_bytes(bytes.as_ref())?; + let surf = ops.load()?; + + let srect = surf.rect(); + let dest_rect: Rect = Rect::from_center((x, y), srect.width(), srect.height()); + + Ok(Self { + rect: dest_rect, + surf, + angle: 0.0, + }) + } + + /// Draws the sprite to the window. This should only be called inside your main event loop. + /// + /// ```no_run + /// # use cat_box::*; + /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); + /// # let game = Game::new("sprite demo", 1000, 1000); + /// # game.run(|ctx| { + /// s.draw(ctx); + /// # }); + /// ``` + pub fn draw(&mut self, ctx: &mut Context) -> Result<()> { + let (creator, canvas, _) = ctx.inner(); + let text = creator.create_texture_from_surface(&self.surf)?; + + canvas.copy_ex(&text, None, self.rect, self.angle, None, false, false)?; + + Ok(()) + } + + /// Translate the sprite, in the form of (delta x, delta y) + /// + /// ``` + /// # use cat_box::*; + /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); + /// s.translate((5, 10)); + /// ``` + pub fn translate>(&mut self, position: I) { + let position = position.into(); + let new_x = self.rect.x() + position.x; + let new_y = self.rect.y() - position.y; + + self.rect.set_x(new_x); + self.rect.set_y(new_y); + } + + /// Reposition the center of the sprite in the form of (x, y) + /// + /// ``` + /// # use cat_box::*; + /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); + /// s.set_position((5, 10)); + /// ``` + pub fn set_position>(&mut self, position: I) { + let position = position.into(); + self.rect.center_on((position.x, position.y)); + } + + /// Set the angle of the sprite, in degrees of clockwise rotation. + /// + /// ``` + /// # use cat_box::*; + /// # let mut s = Sprite::new("duck.png", 500, 400).unwrap(); + /// s.set_angle(45.0); + /// ``` + pub fn set_angle(&mut self, angle: f64) { + self.angle = angle; + } + + /// Get the angle of the sprite, in degrees of clockwise rotation. + /// + /// ``` + /// # use cat_box::*; + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// let angle = s.angle(); + /// ``` + #[must_use] + pub fn angle(&self) -> f64 { + self.angle + } + + /// Get the x and y coordinates of the center of the sprite, in the form of (x, y). + /// + /// ``` + /// # use cat_box::*; + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// let (x, y) = s.position().into(); + /// ``` + #[must_use] + pub fn position(&self) -> Vec2Int { + self.rect.center().into() + } +} + +/// Manages a collection of [`Sprite`]s. +/// +/// Technically, this is a thin wrapper around a simple [`Vec`] of sprites, +/// although with some convenience methods. +#[derive(Default)] +pub struct SpriteCollection { + v: Vec, +} + +impl SpriteCollection { + /// Creates a new [`SpriteCollection`]. + /// + /// See [`Vec::new()`] for more information. + /// ``` + /// # use cat_box::*; + /// let sprites = SpriteCollection::new(); + /// ``` + #[must_use] + pub fn new() -> Self { + Self { v: Vec::new() } + } + + /// Creates a new [`SpriteCollection`] with the specified capacity. + /// + /// The collection will be able to hold exactly `capacity` items without reallocating. + /// ``` + /// # use cat_box::*; + /// let sprites = SpriteCollection::with_capacity(10); + /// ``` + #[must_use] + pub fn with_capacity(cap: usize) -> Self { + Self { + v: Vec::with_capacity(cap), + } + } + + /// Draw all the sprites in this collection to the window. + /// This should only be called inside the main event loop. + /// ```no_run + /// # use cat_box::*; + /// # let mut sprites = SpriteCollection::new(); + /// # let mut game = Game::new("asjdfhalksjdf", 1, 1); + /// # game.run(|ctx| { + /// sprites.draw(ctx); + /// # }); + /// ``` + pub fn draw(&mut self, ctx: &mut Context) -> Result<()> { + for s in &mut self.v { + s.draw(ctx)?; + } + + Ok(()) + } + + /// Add a new [`Sprite`] to the end of this collection. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// sprites.push(s); + /// ``` + pub fn push(&mut self, s: Sprite) { + self.v.push(s); + } + + /// Inserts an element at position `index` within the collection. + /// Shifts all elements after it to the right. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// sprites.insert(s, 0); + /// ``` + pub fn insert(&mut self, s: Sprite, index: usize) { + self.v.insert(index, s); + } + + /// Removes and returns the last element, or `None` if the collection is empty. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// let s = sprites.pop(); + /// ``` + pub fn pop(&mut self) -> Option { + self.v.pop() + } + + /// Removes and returns the element at `index`. + /// Shifts all elements after it to the left. + /// This method will panic if the index is out of bounds. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// # sprites.push(s); + /// sprites.remove(0); + /// ``` + pub fn remove(&mut self, index: usize) -> Sprite { + self.v.remove(index) + } + + /// Return an iterator over the sprites in this collection. + /// Use this to modify the sprites themselves, for example to set their position or angle. + pub fn iter(&mut self) -> IterMut<'_, Sprite> { + self.v.iter_mut() + } + + /// Clears the collection, without touching the allocated capacity. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// # sprites.push(s); + /// sprites.clear(); + /// ``` + pub fn clear(&mut self) { + self.v.clear(); + } + + /// Move all the elements of `other` into `Self`. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// let mut sprites2 = SpriteCollection::new(); + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// # let s2 = Sprite::new("duck.png", 400, 500).unwrap(); + /// # sprites.push(s); + /// # sprites2.push(s2); + /// sprites.concat(sprites2); + /// ``` + pub fn concat(&mut self, mut other: SpriteCollection) { + self.v.append(&mut *other); + } + + /// Returns the length of this vector. + #[must_use] + pub fn len(&self) -> usize { + self.v.len() + } + + /// Get a reference to the element at `index`, or `None` if it doesn't exist. + /// ``` + /// # use cat_box::*; + /// let mut sprites = SpriteCollection::new(); + /// # let s = Sprite::new("duck.png", 500, 400).unwrap(); + /// # sprites.push(s); + /// let s = sprites.get(0); + /// ``` + #[must_use] + 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. + #[must_use] + pub fn inner(&self) -> &Vec { + &self.v + } + + #[must_use] + pub fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +impl Deref for SpriteCollection { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.v + } +} + +impl DerefMut for SpriteCollection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.v + } +}