diff options
| author | Kai Stevenson <kai@kaistevenson.com> | 2026-08-16 00:46:57 -0700 |
|---|---|---|
| committer | Kai Stevenson <kai@kaistevenson.com> | 2026-08-16 00:46:57 -0700 |
| commit | 24886c2752548f1c32ed54968a7bfdf2b1fe38ea (patch) | |
| tree | e6ba72311d9c5b39793d3fd1944a4ee4851fd94c /src/sim | |
| parent | d7eccba2055cd7784a0db6d9ee8692a4f3510931 (diff) | |
fire changes + smoke
Diffstat (limited to 'src/sim')
| -rw-r--r-- | src/sim/materials/fire.rs | 46 | ||||
| -rw-r--r-- | src/sim/materials/mod.rs | 13 | ||||
| -rw-r--r-- | src/sim/materials/smoke.rs | 24 | ||||
| -rw-r--r-- | src/sim/materials/water.rs | 20 |
4 files changed, 80 insertions, 23 deletions
diff --git a/src/sim/materials/fire.rs b/src/sim/materials/fire.rs index b155986..3c686fe 100644 --- a/src/sim/materials/fire.rs +++ b/src/sim/materials/fire.rs @@ -21,25 +21,28 @@ impl FireCellView for Cell { } } +// TODO optimize number of rng calls? #[inline] pub fn sim_update(ctx: &mut UpdateCtx) { let ticks_lived = ctx.cell.get_ticks_lived(); // 2 seconds if ticks_lived > 240 { - // kill ourselves, with a chance to turn into ash - if ctx.rng.random_range(0.0..1.0) > 0.8 { - // TODO ash material - ctx.set_cell(0, 0, Cell::from_material(MaterialId::Sand)); - } else { - ctx.set_cell(0, 0, Cell::void()); + // we have a chance to live longer--roughly 50% chance of living an extra second + if ctx.rng.random_range(0.0..1.0) > 0.995 { + // kill ourselves, with a chance to turn into ash + if ctx.rng.random_range(0.0..1.0) > 0.8 { + // TODO ash material + ctx.set_cell(0, 0, Cell::from_material(MaterialId::Sand)); + } else { + ctx.set_cell(0, 0, Cell::void()); + } + return; } - return; } - // 4 times in our lifespan, try to spread in a random direction - // since it's random, fire may die out if there's nothing in that direction - // a 1-thick line of flammable cells has a 31% chance to die each iteration - if ticks_lived % 60 == 0 { + // at an average of 4 times per lifespan, try to spread + // 1/60 * 240 = 4 + if ctx.rng.random_range(0.0..1.0) > (59.0 / 60.0) { let (dx, dy) = (ctx.rng.random_range(-1..=1), ctx.rng.random_range(-1..=1)); if let Some(target) = ctx.get_cell(dx, dy) && target.is_flammable() @@ -48,6 +51,27 @@ pub fn sim_update(ctx: &mut UpdateCtx) { } } + // 8 times in our lifespan, emit smoke + if ticks_lived % 30 == 0 { + if let Some(target) = ctx.get_cell(0, -1) + && target.material == MaterialId::Void + { + for (dx, dy) in [ + (0, -1), + (1 - ctx.seqno_parity as i32 * 2, 0), + (-1 + ctx.seqno_parity as i32 * 2, 0), + (0, 1), + ] { + if let Some(target) = ctx.get_cell(dx, dy) + && target.material == MaterialId::Void + { + ctx.set_cell(dx, dy, Cell::from_material(MaterialId::Smoke)); + break; + } + } + } + } + ctx.cell.set_ticks_lived(ticks_lived + 1); ctx.set_cell(0, 0, *ctx.cell); } diff --git a/src/sim/materials/mod.rs b/src/sim/materials/mod.rs index 764318a..10f0a06 100644 --- a/src/sim/materials/mod.rs +++ b/src/sim/materials/mod.rs @@ -3,6 +3,7 @@ use crate::sim::sim::UpdateCtx; mod fire; mod gas; mod sand; +mod smoke; mod water; #[repr(u8)] @@ -14,6 +15,7 @@ pub enum MaterialId { Water, Gas, Fire, + Smoke, } pub struct MaterialDef { @@ -23,7 +25,7 @@ pub struct MaterialDef { pub sim_update: Option<fn(ctx: &mut UpdateCtx) -> ()>, } -static MATERIALS: [MaterialDef; 6] = [ +static MATERIALS: [MaterialDef; 7] = [ MaterialDef { name: "Void", color: (0x00, 0x00, 0x00, 0x00), @@ -61,16 +63,23 @@ static MATERIALS: [MaterialDef; 6] = [ density: 50, sim_update: Some(fire::sim_update), }, + MaterialDef { + name: "Smoke", + color: (0x32, 0x35, 0x36, 0xAA), + density: 15, + sim_update: Some(smoke::sim_update), + }, ]; impl MaterialId { - pub const ALL: [MaterialId; 6] = [ + pub const ALL: [MaterialId; 7] = [ MaterialId::Void, MaterialId::Sand, MaterialId::Wood, MaterialId::Water, MaterialId::Gas, MaterialId::Fire, + MaterialId::Smoke, ]; #[inline] pub fn def(self) -> &'static MaterialDef { diff --git a/src/sim/materials/smoke.rs b/src/sim/materials/smoke.rs new file mode 100644 index 0000000..68f77ca --- /dev/null +++ b/src/sim/materials/smoke.rs @@ -0,0 +1,24 @@ +use rand::RngExt; + +use crate::sim::{cell::Cell, materials::MaterialId, sim::UpdateCtx}; + +#[inline] +pub fn sim_update(ctx: &mut UpdateCtx) { + // only allow upward movement some of the time to limit movement speed + if ctx.rng.random_range(0.0..1.0) > 0.8 { + if ctx.candidates_swap(&[(0, -1)]) { + return; + } + } + // same for each horizontal direction + if ctx.rng.random_range(0.0..1.0) > 0.8 { + if ctx.candidates_swap(&[(1 - ctx.seqno_parity as i32 * 2, 0)]) { + return; + } + } + if ctx.rng.random_range(0.0..1.0) > 0.8 { + if ctx.candidates_swap(&[(-1 + ctx.seqno_parity as i32 * 2, 0)]) { + return; + } + } +} diff --git a/src/sim/materials/water.rs b/src/sim/materials/water.rs index d76ec5b..1ba8eb4 100644 --- a/src/sim/materials/water.rs +++ b/src/sim/materials/water.rs @@ -62,15 +62,15 @@ pub fn sim_update(ctx: &mut UpdateCtx) { // we didn't find a hole, so just move "randomly" on the same surface // TODO when to settle? - let target_x = if !can_move_left { - 1 - } else if !can_move_right { - -1 - } else if ctx.seqno_parity % 2 == 1 { - 1 - } else { - -1 - }; + // let target_x = if !can_move_left { + // 1 + // } else if !can_move_right { + // -1 + // } else if ctx.seqno_parity % 2 == 1 { + // 1 + // } else { + // -1 + // }; - ctx.candidates_swap(&[(target_x, 0)]); + // ctx.candidates_swap(&[(target_x, 0)]); } |
