summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock33
-rw-r--r--Cargo.toml3
-rw-r--r--assets/sprites/tnt/img.pngbin0 -> 299 bytes
-rw-r--r--assets/sprites/tnt/manifest.toml3
-rw-r--r--src/content/entities/entity_tnt.rs44
-rw-r--r--src/content/entities/mod.rs1
-rw-r--r--src/content/materials/mod.rs21
-rw-r--r--src/input.rs6
-rw-r--r--src/main.rs7
-rw-r--r--src/sprite_loader.rs79
10 files changed, 189 insertions, 8 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 042caee..ba9ddca 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2448,11 +2448,14 @@ dependencies = [
"futures",
"fxhash",
"glam 0.33.3",
+ "png",
"puffin",
"puffin_http",
"rand",
"rapier2d",
"rayon",
+ "serde",
+ "toml",
"wgpu",
"wgpu-types",
"winit",
@@ -2800,6 +2803,15 @@ dependencies = [
]
[[package]]
+name = "serde_spanned"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26"
+dependencies = [
+ "serde_core",
+]
+
+[[package]]
name = "shlex"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3113,6 +3125,21 @@ dependencies = [
]
[[package]]
+name = "toml"
+version = "1.1.4+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5"
+dependencies = [
+ "indexmap",
+ "serde_core",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_parser",
+ "toml_writer",
+ "winnow",
+]
+
+[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3143,6 +3170,12 @@ dependencies = [
]
[[package]]
+name = "toml_writer"
+version = "1.1.2+spec-1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2"
+
+[[package]]
name = "tracing"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index d144c47..e2ba7e4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -33,6 +33,9 @@ bytemuck = "1.25.2"
fxhash = "0.2.1"
rapier2d = { version = "0.35.2", features = ["debug-render"] }
glam = "0.33.3"
+png = "0.18.1"
+toml = "1.1.4"
+serde = "1.0.229"
[features]
profiler = []
diff --git a/assets/sprites/tnt/img.png b/assets/sprites/tnt/img.png
new file mode 100644
index 0000000..b5fafac
--- /dev/null
+++ b/assets/sprites/tnt/img.png
Binary files differ
diff --git a/assets/sprites/tnt/manifest.toml b/assets/sprites/tnt/manifest.toml
new file mode 100644
index 0000000..242756c
--- /dev/null
+++ b/assets/sprites/tnt/manifest.toml
@@ -0,0 +1,3 @@
+[palette]
+3 = { material = "Wood" }
+27 = { material = "Tnt" } \ No newline at end of file
diff --git a/src/content/entities/entity_tnt.rs b/src/content/entities/entity_tnt.rs
new file mode 100644
index 0000000..2e4cef5
--- /dev/null
+++ b/src/content/entities/entity_tnt.rs
@@ -0,0 +1,44 @@
+use glam::{IVec2, Vec2};
+
+use crate::{
+ sim::{
+ entity::{EntityBehaviour, EntityCells, EntityDef, EntityUpdateCtx},
+ lib::force::apply_explosion,
+ sim_manager::SimCtx,
+ },
+ sprite_loader::load_sprite_to_cells,
+};
+
+struct TntEntityBehaviour {
+ pub fuse: f32,
+}
+
+impl EntityBehaviour for TntEntityBehaviour {
+ fn update(&mut self, update_ctx: &mut EntityUpdateCtx, ctx: &mut SimCtx, delta_time: f32) {
+ self.fuse -= delta_time;
+ if self.fuse <= 0.0 {
+ apply_explosion(
+ ctx,
+ update_ctx.entity_data.transform(ctx).unwrap().0,
+ 35,
+ Vec2::new(0.0, -0.6),
+ 400.0,
+ );
+ update_ctx.deferred_destroy(update_ctx.entity_data.id);
+ }
+ }
+}
+
+pub fn entity_tnt_def(position: Vec2) -> EntityDef {
+ let sprite_cells = load_sprite_to_cells("assets/sprites/tnt");
+ let entity_cells = EntityCells {
+ cells: sprite_cells.cells,
+ size: IVec2::new(sprite_cells.width as i32, sprite_cells.height as i32),
+ };
+
+ EntityDef::from_cells(
+ position,
+ entity_cells,
+ Some(Box::new(TntEntityBehaviour { fuse: 3.0 })),
+ )
+}
diff --git a/src/content/entities/mod.rs b/src/content/entities/mod.rs
index 652ee6d..0ec45ce 100644
--- a/src/content/entities/mod.rs
+++ b/src/content/entities/mod.rs
@@ -1,3 +1,4 @@
pub mod entity_bullet_emitter;
pub mod entity_cube;
pub mod entity_grenade;
+pub mod entity_tnt;
diff --git a/src/content/materials/mod.rs b/src/content/materials/mod.rs
index 8116565..819ec2a 100644
--- a/src/content/materials/mod.rs
+++ b/src/content/materials/mod.rs
@@ -1,3 +1,5 @@
+use serde::Deserialize;
+
use crate::sim::cell_manager::sim::{PostUpdateAction, UpdateCtx};
pub mod fire;
@@ -6,7 +8,7 @@ pub mod liquid;
pub mod powder;
#[repr(u8)]
-#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Deserialize)]
pub enum MaterialId {
Void = 0,
Sand,
@@ -15,6 +17,7 @@ pub enum MaterialId {
Fire,
Smoke,
Steel,
+ Tnt,
}
#[repr(u8)]
@@ -35,7 +38,7 @@ pub struct MaterialDef {
pub sim_update: Option<fn(ctx: &mut UpdateCtx) -> PostUpdateAction>,
}
-static MATERIALS: [MaterialDef; 7] = [
+static MATERIALS: [MaterialDef; 8] = [
MaterialDef {
name: "Void",
color: (0x00, 0x00, 0x00, 0x00),
@@ -53,8 +56,8 @@ static MATERIALS: [MaterialDef; 7] = [
},
MaterialDef {
name: "Wood",
- color: (0x85, 0x56, 0x1D, 0xFF),
- density: 50,
+ color: (0x66, 0x39, 0x31, 0xFF),
+ density: 60,
form: MaterialForm::Solid,
sim_update: None,
},
@@ -88,10 +91,17 @@ static MATERIALS: [MaterialDef; 7] = [
form: MaterialForm::Solid,
sim_update: None,
},
+ MaterialDef {
+ name: "TNT",
+ color: (0xA6, 0x34, 0x23, 0xFF),
+ density: 55,
+ form: MaterialForm::Solid,
+ sim_update: None,
+ },
];
impl MaterialId {
- pub const ALL: [MaterialId; 7] = [
+ pub const ALL: [MaterialId; 8] = [
MaterialId::Void,
MaterialId::Sand,
MaterialId::Wood,
@@ -99,6 +109,7 @@ impl MaterialId {
MaterialId::Fire,
MaterialId::Smoke,
MaterialId::Steel,
+ MaterialId::Tnt,
];
#[inline]
pub fn def(self) -> &'static MaterialDef {
diff --git a/src/input.rs b/src/input.rs
index 09a0436..30f3834 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -23,6 +23,7 @@ pub enum Input {
// game controls?
Grenade,
+ Tnt,
// placeholder actions
Action1,
@@ -33,9 +34,9 @@ pub enum Input {
Action6,
}
-const INPUT_VAR_LEN: usize = 16;
+const INPUT_VAR_LEN: usize = 17;
-const KEYMAP: [(KeyCode, Input); 16] = [
+const KEYMAP: [(KeyCode, Input); INPUT_VAR_LEN] = [
(KeyCode::KeyW, Input::Up),
(KeyCode::KeyA, Input::Left),
(KeyCode::KeyS, Input::Down),
@@ -46,6 +47,7 @@ const KEYMAP: [(KeyCode, Input); 16] = [
(KeyCode::KeyV, Input::ClearEntities),
(KeyCode::KeyP, Input::ClearParticles),
(KeyCode::KeyG, Input::Grenade),
+ (KeyCode::KeyT, Input::Tnt),
(KeyCode::Digit1, Input::Action1),
(KeyCode::Digit2, Input::Action2),
(KeyCode::Digit3, Input::Action3),
diff --git a/src/main.rs b/src/main.rs
index 6e6c9d9..00f2cbc 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -4,6 +4,7 @@ mod content;
mod input;
mod renderer;
mod sim;
+mod sprite_loader;
mod vfx;
use futures::executor;
@@ -21,7 +22,7 @@ use crate::{
content::{
entities::{
entity_bullet_emitter::entity_bullet_emitter_def, entity_cube::entity_cube_def,
- entity_grenade::entity_grenade_def,
+ entity_grenade::entity_grenade_def, entity_tnt::entity_tnt_def,
},
materials::MaterialId,
},
@@ -95,6 +96,10 @@ impl App {
sim.create_entity(entity_grenade_def(self.input_manager.world_mouse_pos, 3.0));
}
+ if self.input_manager.pressed(Input::Tnt) {
+ sim.create_entity(entity_tnt_def(self.input_manager.world_mouse_pos));
+ }
+
if self.input_manager.pressed(Input::Action3) {
sim.create_entity(entity_bullet_emitter_def(
self.input_manager.world_mouse_pos,
diff --git a/src/sprite_loader.rs b/src/sprite_loader.rs
new file mode 100644
index 0000000..eccf066
--- /dev/null
+++ b/src/sprite_loader.rs
@@ -0,0 +1,79 @@
+use serde::Deserialize;
+use std::{collections::HashMap, error::Error, fs::File, io::BufReader, path::Path};
+
+use crate::{content::materials::MaterialId, sim::cell::Cell};
+
+fn load_img(path: &Path) -> Result<(Vec<u8>, u32, u32), Box<dyn Error>> {
+ let mut decoder = png::Decoder::new(BufReader::new(File::open(path)?));
+ decoder.set_transformations(png::Transformations::IDENTITY);
+
+ let mut reader = decoder.read_info()?;
+ // only None if it's too big for memory
+ let mut buf = vec![0; reader.output_buffer_size().unwrap()];
+ let info = reader.next_frame(&mut buf)?;
+
+ if info.color_type != png::ColorType::Indexed {
+ return Err(format!("{:#?}: not indexed", path.to_str()).into());
+ }
+ if info.bit_depth != png::BitDepth::Eight {
+ return Err(format!(
+ "{:#?}: expected 8-bit, got {:?}",
+ path.to_str(),
+ info.bit_depth
+ )
+ .into());
+ }
+
+ buf.truncate(info.buffer_size());
+ Ok((buf, info.width, info.height))
+}
+
+#[derive(Deserialize)]
+struct PaletteEntry {
+ material: MaterialId,
+}
+
+#[derive(Deserialize)]
+struct SpriteManifest {
+ palette: HashMap<u8, PaletteEntry>,
+}
+
+fn load_manifest(path: &Path) -> Result<SpriteManifest, Box<dyn Error>> {
+ Ok(toml::from_str(&std::fs::read_to_string(path)?)?)
+}
+
+pub struct SpriteCells {
+ pub cells: Vec<Cell>,
+ pub width: u32,
+ pub height: u32,
+}
+
+pub fn load_sprite_to_cells(path: &str) -> SpriteCells {
+ let img_result = load_img(&Path::join(Path::new(path), Path::new("img.png")));
+ match img_result {
+ Ok((indices, width, height)) => {
+ let manifest_result =
+ load_manifest(&Path::join(Path::new(path), Path::new("manifest.toml")));
+ match manifest_result {
+ Ok(SpriteManifest { palette }) => {
+ let cells: Vec<Cell> = indices
+ .iter()
+ .map(|i| Cell::from_material(palette.get(i).unwrap().material))
+ .collect();
+
+ SpriteCells {
+ cells,
+ width,
+ height,
+ }
+ }
+ Err(e) => {
+ panic!("Couldn't load sprite: {}", e)
+ }
+ }
+ }
+ Err(e) => {
+ panic!("Couldn't load sprite: {}", e)
+ }
+ }
+}