From 0f5da721eda5579fe7f70e35aa77650529f1c01b Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 20 Dec 2023 20:31:09 -0800 Subject: [PATCH] Cleaned up drawing --- src/doodad.rs | 45 +---------------------- src/ship.rs | 38 +------------------ src/spriteatlas.rs | 92 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 83 insertions(+), 92 deletions(-) diff --git a/src/doodad.rs b/src/doodad.rs index 2341001..8c73c1c 100644 --- a/src/doodad.rs +++ b/src/doodad.rs @@ -1,4 +1,3 @@ -use sdl2::rect::{Point, Rect}; use sdl2::render::Canvas; use sdl2::video::Window; @@ -26,49 +25,9 @@ impl Drawable for Doodad { sa: &SpriteAtlas, c: &Camera, ) -> Result<(), String> { - let win_size = PhysVec::from(canvas.window().size()); - let draw_pos = self.screen_position(canvas, &c); - - // Don't draw if off screen - if draw_pos.x < 0.0 - || draw_pos.x > win_size.x - || draw_pos.y < 0.0 - || draw_pos.y > win_size.y - { - return Ok(()); - } - + let pos = self.screen_position(canvas, c); let sprite = sa.get(&self.sprite); - - let mut dest_rect_0 = Rect::new( - 0, - 0, - sprite.rect.width() / self.scale, - sprite.rect.height() / self.scale, - ); - dest_rect_0.center_on(Point::new( - sprite.rect.width() as i32 / (2 * self.scale) as i32, - sprite.rect.height() as i32 / (2 * self.scale) as i32, - )); - - // set the current frame for time - dest_rect_0.set_x(draw_pos.x.round() as i32); - dest_rect_0.set_y(draw_pos.y.round() as i32); - - // copy the frame to the canvas - canvas.copy_ex( - &sprite.texture, - Some(sprite.rect), - Some(dest_rect_0), - self.angle.to_degrees(), // angle - Point::new( - sprite.rect.width() as i32 / (2 * self.scale) as i32, - sprite.rect.width() as i32 / (2 * self.scale) as i32, - ), // center - false, - false, - )?; - + sprite.draw(canvas, pos, self.angle)?; return Ok(()); } } diff --git a/src/ship.rs b/src/ship.rs index 9d7e978..5ba4cec 100644 --- a/src/ship.rs +++ b/src/ship.rs @@ -1,4 +1,3 @@ -use sdl2::rect::{Point, Rect}; use sdl2::render::Canvas; use sdl2::video::Window; @@ -12,7 +11,6 @@ use crate::SpriteAtlas; pub struct Ship { pub body: PhysBody, kind: ShipKind, - scale: u32, } impl Ship { @@ -20,7 +18,6 @@ impl Ship { Ship { body: PhysBody::new(), kind, - scale: 2, } } } @@ -36,40 +33,9 @@ impl Drawable for Ship { sa: &SpriteAtlas, c: &Camera, ) -> Result<(), String> { - let win_size = PhysVec::from(canvas.window().size()); - let draw_pos = self.screen_position(canvas, &c); - // Don't draw if off screen - if draw_pos.x < 0.0 - || draw_pos.x > win_size.x - || draw_pos.y < 0.0 - || draw_pos.y > win_size.y - { - return Ok(()); - } - + let pos = self.screen_position(canvas, c); let sprite = sa.get(self.kind.sprite()); - - let mut dest_rect_0 = Rect::new(0, 0, 120 / self.scale, 270 / self.scale); - dest_rect_0.center_on(Point::new( - 120 / (2 * self.scale) as i32, - 270 / (2 * self.scale) as i32, - )); - - // set the current frame for time - dest_rect_0.set_x(draw_pos.x.round() as i32); - dest_rect_0.set_y(draw_pos.y.round() as i32); - - // copy the frame to the canvas - canvas.copy_ex( - &sprite.texture, - Some(sprite.rect), - Some(dest_rect_0), - self.body.angle.to_degrees(), // angle - Point::new(120 / (2 * self.scale) as i32, 270 / (2 * self.scale) as i32), // center - false, - false, - )?; - + sprite.draw(canvas, pos, self.body.angle.to_degrees())?; return Ok(()); } } diff --git a/src/spriteatlas.rs b/src/spriteatlas.rs index 7ac58a9..17be895 100644 --- a/src/spriteatlas.rs +++ b/src/spriteatlas.rs @@ -1,23 +1,85 @@ use image::io::Reader as ImageReader; use sdl2::{ - rect::Rect, - render::{Texture, TextureCreator}, - video::WindowContext, + rect::{Point, Rect}, + render::{Canvas, Texture, TextureCreator}, + video::{Window, WindowContext}, }; use std::collections::HashMap; +use crate::physics::PhysVec; + /// A handle for a sprite inside a SpriteAtlas pub struct Sprite<'a> { - pub texture: &'a Texture<'a>, - pub rect: Rect, + texture: &'a Texture<'a>, + rect: Rect, + scale: f64, +} + +impl<'a> Sprite<'a> { + /// Draw this sprite on the screen. + /// + /// Position represents on-screen position, + /// NOT world position. + pub fn draw( + &self, + canvas: &mut Canvas, + position: PhysVec, + angle: f64, + ) -> Result<(), String> { + let win_size = PhysVec::from(canvas.window().size()); + let width = self.rect.width(); + let height = self.rect.height(); + + // Don't draw if we're not on the screen. + // An offset is included to ensure we're completely + // off the screen. We add the whole width intentionally. + if position.x < -1.0 * (width as f64) + || position.x > win_size.x + width as f64 + || position.y < -1.0 * (height as f64) + || position.y > win_size.y + height as f64 + { + return Ok(()); + } + + let mut dest = Rect::new( + 0, + 0, + (width as f64 / self.scale) as u32, + (height as f64 / self.scale) as u32, + ); + dest.center_on(Point::new( + (width as f64 / (2.0 * self.scale)) as i32, + (height as f64 / (2.0 * self.scale)) as i32, + )); + + // set the current frame for time + dest.set_x(position.x.round() as i32); + dest.set_y(position.y.round() as i32); + + // copy the frame to the canvas + canvas.copy_ex( + &self.texture, + Some(self.rect), + Some(dest), + angle, // angle + Point::new( + (width as f64 / (2.0 * self.scale)) as i32, + (height as f64 / (2.0 * self.scale)) as i32, + ), // center + false, + false, + )?; + + return Ok(()); + } } /// A cache of textures we use when drawing the screen. /// /// This is implemented very carefully, since SDL2 textures have tricky lifetimes. pub struct SpriteAtlas<'a> { - data: HashMap, Rect)>, + data: HashMap, Rect, f64)>, } impl<'a> SpriteAtlas<'a> { @@ -26,18 +88,19 @@ impl<'a> SpriteAtlas<'a> { data: HashMap::new(), }; - b.load_one(texture_creator, "gypsum.png")?; - b.load_one(texture_creator, "a0.png")?; - b.load_one(texture_creator, "small.png")?; - b.load_one(texture_creator, "earth.png")?; + b.load_one(texture_creator, "gypsum.png", 1.5)?; + b.load_one(texture_creator, "a0.png", 1.0)?; + b.load_one(texture_creator, "small.png", 1.0)?; + b.load_one(texture_creator, "earth.png", 1.0)?; return Ok(b); } pub fn get(&'a self, name: &str) -> Sprite<'a> { - let (texture, rect) = self.data.get(name).unwrap(); + let (texture, rect, scale) = self.data.get(name).unwrap(); return Sprite { texture, + scale: scale.clone(), rect: rect.clone(), }; } @@ -46,6 +109,7 @@ impl<'a> SpriteAtlas<'a> { &mut self, texture_creator: &'a TextureCreator, s: &str, + scale: f64, ) -> Result<(), String> { let im = ImageReader::open(format!("assets/{s}")) .unwrap() @@ -67,8 +131,10 @@ impl<'a> SpriteAtlas<'a> { .create_texture_from_surface(&surface) .map_err(|e| e.to_string())?; - self.data - .insert(s.to_owned(), (texture, Rect::new(0, 0, width, height))); + self.data.insert( + s.to_owned(), + (texture, Rect::new(0, 0, width, height), scale), + ); return Ok(()); }