From f5f52e7e75362928468848f60ec515cad251cbdd Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 20 Dec 2023 19:05:12 -0800 Subject: [PATCH] Added basic working code --- Cargo.lock | 404 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ src/doodad.rs | 74 +++++++++ src/inputstatus.rs | 48 ++++++ src/main.rs | 175 ++++++++++++++++++++ src/ship.rs | 75 +++++++++ src/spriteatlas.rs | 73 ++++++++ 7 files changed, 861 insertions(+) create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/doodad.rs create mode 100644 src/inputstatus.rs create mode 100644 src/main.rs create mode 100644 src/ship.rs create mode 100644 src/spriteatlas.rs diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..42f05b2 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,404 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "exr" +version = "1.71.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "832a761f35ab3e6664babfbdc6cef35a4860e816ec3916dcfd0882954e98a8a8" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fdeflate" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d6dafc854908ff5da46ff3f8f473c6984119a2876a383a860246dd7841a868" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "game" +version = "0.1.0" +dependencies = [ + "image", + "sdl2", +] + +[[package]] +name = "gif" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80792593675e051cf94a4b111980da2ba60d4a83e43e0048c5693baab3977045" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "half" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b4af3693f1b705df946e9fe5631932443781d0aabb423b62fcd4d73f6d2fd0" +dependencies = [ + "crunchy", +] + +[[package]] +name = "image" +version = "0.24.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "exr", + "gif", + "jpeg-decoder", + "num-rational", + "num-traits", + "png", + "qoi", + "tiff", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" +dependencies = [ + "rayon", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libc" +version = "0.2.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "png" +version = "0.17.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd75bf2d8dd3702b9707cdbc56a5b9ef42cec752eb8b3bafc01234558442aa64" +dependencies = [ + "bitflags", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sdl2" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8356b2697d1ead5a34f40bcc3c5d3620205fe0c7be0a14656223bfeec0258891" +dependencies = [ + "bitflags", + "lazy_static", + "libc", + "sdl2-sys", +] + +[[package]] +name = "sdl2-sys" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bcacfdd45d539fb5785049feb0038a63931aa896c7763a2a12e125ec58bd29" +dependencies = [ + "cfg-if", + "libc", + "version-compare", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "smallvec" +version = "1.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "tiff" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + +[[package]] +name = "weezl" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9193164d4de03a926d909d3bc7c30543cecb35400c02114792c2cae20d5e2dbb" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f7fadcd --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "game" +version = "0.1.0" +edition = "2021" + +[dependencies] +image = "0.24.7" + +[dependencies.sdl2] +version = "0.36" +default-features = false +#features = ["ttf"] diff --git a/src/doodad.rs b/src/doodad.rs new file mode 100644 index 0000000..1ab67f1 --- /dev/null +++ b/src/doodad.rs @@ -0,0 +1,74 @@ +use sdl2::rect::{Point, Rect}; +use sdl2::render::Canvas; +use sdl2::video::Window; + +use crate::physics::PhysVec; +use crate::Camera; +use crate::Drawable; +use crate::SpriteAtlas; + +pub struct Doodad { + sprite: String, + pos: PhysVec, + scale: u32, +} + +impl Doodad { + pub fn new(pos: PhysVec) -> Self { + Doodad { + sprite: "a0.png".to_owned(), + pos, + scale: 1, + } + } +} + +impl Drawable for Doodad { + fn position(&self) -> PhysVec { + self.pos + } + + fn draw( + &self, + canvas: &mut Canvas, + 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 sprite = sa.get(&self.sprite); + + let mut dest_rect_0 = Rect::new(0, 0, 112 / self.scale, 112 / self.scale); + dest_rect_0.center_on(Point::new( + 112 / (2 * self.scale) as i32, + 112 / (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), + 0.0, // angle + Point::new(120 / (2 * self.scale) as i32, 270 / (2 * self.scale) as i32), // center + false, + false, + )?; + + return Ok(()); + } +} diff --git a/src/inputstatus.rs b/src/inputstatus.rs new file mode 100644 index 0000000..ec9e1fb --- /dev/null +++ b/src/inputstatus.rs @@ -0,0 +1,48 @@ +use sdl2::{event::Event, keyboard::Keycode}; + +// TODO: no boolean modification (no pub) +pub struct InputStatus { + pub key_left: bool, + pub key_right: bool, + pub key_thrust: bool, +} + +impl InputStatus { + pub fn new() -> Self { + InputStatus { + key_left: false, + key_right: false, + key_thrust: false, + } + } + + fn handle_keyup(&mut self, keycode: Keycode) { + match keycode { + Keycode::Left => self.key_left = false, + Keycode::Right => self.key_right = false, + Keycode::Up => self.key_thrust = false, + _ => {} + } + } + + fn handle_keydown(&mut self, keycode: Keycode) { + match keycode { + Keycode::Left => self.key_left = true, + Keycode::Right => self.key_right = true, + Keycode::Up => self.key_thrust = true, + _ => {} + } + } + + pub fn update(&mut self, event: Event) { + match event { + Event::KeyDown { + keycode: Some(key), .. + } => self.handle_keydown(key), + Event::KeyUp { + keycode: Some(key), .. + } => self.handle_keyup(key), + _ => {} + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..6dd3e5f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,175 @@ +use sdl2::{event::Event, keyboard::Keycode, render::Canvas, video::Window}; +use std::{time::Duration, time::Instant}; + +mod doodad; +mod inputstatus; +mod physics; +mod ship; +mod spriteatlas; + +use crate::doodad::Doodad; +use crate::inputstatus::InputStatus; +use crate::physics::PhysVec; +use crate::ship::Ship; +use crate::spriteatlas::SpriteAtlas; + +trait Drawable { + /// Return the world position of this object + fn position(&self) -> PhysVec; + + /// Get the position of this drawable on the screen + /// (0, 0) is at top-left corner. + /// + /// Returned position is this object's center. + fn screen_position(&self, canvas: &mut Canvas, c: &Camera) -> PhysVec { + let win_size = PhysVec::from(canvas.window().size()); + let h = win_size / 2.0; + return self.position() - c.pos + h; + } + + // Draw this item on the screen + fn draw(&self, canvas: &mut Canvas, sa: &SpriteAtlas, c: &Camera) + -> Result<(), String>; +} + +enum ShipKind { + Gypsum, +} + +impl ShipKind { + fn sprite(&self) -> &'static str { + match self { + Self::Gypsum => "gypsum.png", + } + } +} + +struct Camera { + pos: PhysVec, +} + +impl Camera { + fn new() -> Self { + Camera { + pos: PhysVec::zero(), + } + } +} + +static FTL: f64 = 1.0 / 140.0; // frame time limit + +struct System { + decor: Vec>, +} + +impl System { + fn new() -> Self { + let mut s = System { decor: Vec::new() }; + + s.decor.push(Box::new(Doodad::new(PhysVec::zero()))); + s.decor + .push(Box::new(Doodad::new(PhysVec { x: 100.0, y: 23.0 }))); + + return s; + } + + fn draw( + &self, + canvas: &mut Canvas, + sa: &SpriteAtlas, + c: &Camera, + ) -> Result<(), String> { + for d in &self.decor { + d.draw(canvas, sa, c)? + } + + return Ok(()); + } +} + +fn main() -> Result<(), String> { + let sdl_context = sdl2::init()?; + let video_subsystem = sdl_context.video()?; + + let window = video_subsystem + .window("SDL2", 640, 480) + .position_centered() + .resizable() + .build() + .map_err(|e| e.to_string())?; + + let mut canvas = window + .into_canvas() + .accelerated() + .build() + .map_err(|e| e.to_string())?; + let texture_creator = canvas.texture_creator(); + + let sa = SpriteAtlas::new(&texture_creator)?; + let mut event_pump = sdl_context.event_pump()?; + + let system = System::new(); + + let mut i = InputStatus::new(); + let mut c = Camera::new(); + + let mut s = Ship::new(ShipKind::Gypsum); + + //let mut last_frame_time = 0f64; + let mut frame_start; + + let mut running = true; + while running { + frame_start = Instant::now(); + + for event in event_pump.poll_iter() { + match event { + Event::Quit { .. } + | Event::KeyDown { + keycode: Some(Keycode::Escape), + .. + } => { + running = false; + } + _ => i.update(event), + } + } + + c.pos = s.body.pos; + + // Draw + canvas.clear(); + system.draw(&mut canvas, &sa, &c)?; + s.draw(&mut canvas, &sa, &c)?; + canvas.present(); + + let frame_time = frame_start.elapsed().as_secs_f64(); + + // Wait + // (limit frame rate) + if frame_time < FTL { + std::thread::sleep(Duration::from_secs_f64(FTL - frame_time)); + } + + // Apply input + + let frame_time = frame_start.elapsed().as_secs_f64(); + //last_frame_time = frame_time; + + s.body.tick(frame_time); + + if i.key_thrust { + s.body.thrust(50.0 * frame_time); + } + + if i.key_right { + s.body.rot(-1.0 * frame_time); + } + + if i.key_left { + s.body.rot(1.0 * frame_time); + } + } + + Ok(()) +} diff --git a/src/ship.rs b/src/ship.rs new file mode 100644 index 0000000..9d7e978 --- /dev/null +++ b/src/ship.rs @@ -0,0 +1,75 @@ +use sdl2::rect::{Point, Rect}; +use sdl2::render::Canvas; +use sdl2::video::Window; + +use crate::physics::PhysBody; +use crate::physics::PhysVec; +use crate::Camera; +use crate::Drawable; +use crate::ShipKind; +use crate::SpriteAtlas; + +pub struct Ship { + pub body: PhysBody, + kind: ShipKind, + scale: u32, +} + +impl Ship { + pub fn new(kind: ShipKind) -> Self { + Ship { + body: PhysBody::new(), + kind, + scale: 2, + } + } +} + +impl Drawable for Ship { + fn position(&self) -> PhysVec { + return self.body.pos; + } + + fn draw( + &self, + canvas: &mut Canvas, + 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 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, + )?; + + return Ok(()); + } +} diff --git a/src/spriteatlas.rs b/src/spriteatlas.rs new file mode 100644 index 0000000..4409435 --- /dev/null +++ b/src/spriteatlas.rs @@ -0,0 +1,73 @@ +use image::io::Reader as ImageReader; +use sdl2::{ + rect::Rect, + render::{Texture, TextureCreator}, + video::WindowContext, +}; + +use std::collections::HashMap; + +/// A handle for a sprite inside a SpriteAtlas +pub struct Sprite<'a> { + pub texture: &'a Texture<'a>, + pub rect: Rect, +} + +/// 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)>, +} + +impl<'a> SpriteAtlas<'a> { + pub fn new(texture_creator: &'a TextureCreator) -> Result { + let mut b = Self { + data: HashMap::new(), + }; + + b.load_one(texture_creator, "gypsum.png")?; + b.load_one(texture_creator, "a0.png")?; + + return Ok(b); + } + + pub fn get(&'a self, name: &str) -> Sprite<'a> { + let (texture, rect) = self.data.get(name).unwrap(); + return Sprite { + texture, + rect: rect.clone(), + }; + } + + fn load_one( + &mut self, + texture_creator: &'a TextureCreator, + s: &str, + ) -> Result<(), String> { + let im = ImageReader::open(format!("assets/{s}")) + .unwrap() + .decode() + .unwrap(); + let width = im.width(); + let height = im.height(); + let mut im = im.as_bytes().to_vec(); + + let surface = sdl2::surface::Surface::from_data( + &mut im, + width, + height, + width * 4, + sdl2::pixels::PixelFormatEnum::RGBA32, + )?; + + let texture = texture_creator + .create_texture_from_surface(&surface) + .map_err(|e| e.to_string())?; + + self.data + .insert(s.to_owned(), (texture, Rect::new(0, 0, width, height))); + + return Ok(()); + } +}