115 lines
4.5 KiB
Rust
115 lines
4.5 KiB
Rust
use bevy::{prelude::*,math::UVec3};
|
|
use crate::{MAX_VERTICAL_FLOW,MAX_HORIZONTAL_FLOW,grid::{Grid,GridElement}};
|
|
|
|
pub struct SimulationPlugin;
|
|
|
|
impl Plugin for SimulationPlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_state::<SimulationStatus>()
|
|
.insert_resource(Time::<Fixed>::from_hz(32.))
|
|
.add_systems(FixedUpdate, tick.run_if(in_state(SimulationStatus::Continued)));
|
|
}
|
|
}
|
|
|
|
enum GridAction{
|
|
MoveLiquid{
|
|
from: UVec3,
|
|
to: UVec3,
|
|
amount: u32,
|
|
},
|
|
SpawnLiquid {
|
|
at: UVec3,
|
|
amount: u32,
|
|
}
|
|
}
|
|
|
|
#[derive(States,Default,Hash,Eq,PartialEq,Clone,Debug)]
|
|
pub enum SimulationStatus {
|
|
#[default]
|
|
Paused,
|
|
Continued,
|
|
}
|
|
|
|
pub fn tick(mut grid: ResMut<Grid>) {
|
|
let mut stack: Vec<GridAction> = Vec::new();
|
|
|
|
for x in 0..grid.size.x {
|
|
for y in 0..grid.size.y {
|
|
for z in 0..grid.size.z {
|
|
let vector = UVec3::new(x,y,z);
|
|
let Some(index) = grid.indexify(vector) else {
|
|
continue;
|
|
};
|
|
|
|
match grid.data[index as usize] {
|
|
GridElement::Water { amount } => {
|
|
let mut transfer_amount = amount.clone();
|
|
|
|
if let Some(gravity_vector) = vector.checked_sub(UVec3::new(0,1,0)) {
|
|
if let Some(gravity_amount) = grid.data
|
|
[grid.indexify(gravity_vector).unwrap()]
|
|
.try_fill(transfer_amount.min(MAX_VERTICAL_FLOW)) {
|
|
stack.push(GridAction::MoveLiquid { from: vector, to: gravity_vector, amount: gravity_amount });
|
|
transfer_amount -= gravity_amount;
|
|
}
|
|
}
|
|
|
|
transfer_amount = transfer_amount.min(MAX_HORIZONTAL_FLOW) / 4;
|
|
if transfer_amount > 0 {
|
|
for lookup_vector in [IVec3::new(1,0,0),IVec3::new(0,0,1),IVec3::new(-1,0,0),IVec3::new(0,0,-1)] {
|
|
let push_vector = (vector.as_ivec3() + lookup_vector).max(IVec3::ZERO).as_uvec3();
|
|
if push_vector == vector {
|
|
continue;
|
|
}
|
|
let Some(push_index) = grid.indexify(push_vector) else {
|
|
continue;
|
|
};
|
|
|
|
let Some(push_amount) = grid.data[push_index].try_fill(transfer_amount) else {
|
|
continue;
|
|
};
|
|
stack.push(GridAction::MoveLiquid { from: vector, to: push_vector, amount: push_amount });
|
|
}
|
|
}
|
|
},
|
|
GridElement::Source { source_amount } => {
|
|
if let Some(gravity_vector) = vector.checked_sub(UVec3::new(0,1,0)) {
|
|
if grid.data[grid.indexify(gravity_vector).unwrap()].can_fill() {
|
|
stack.push(GridAction::SpawnLiquid { at: gravity_vector, amount: source_amount });
|
|
}
|
|
}
|
|
|
|
for lookup_vector in [IVec3::new(1,0,0),IVec3::new(0,0,1),IVec3::new(-1,0,0),IVec3::new(0,0,-1)] {
|
|
let push_vector = (vector.as_ivec3() + lookup_vector).max(IVec3::ZERO).as_uvec3();
|
|
let Some(push_index) = grid.indexify(push_vector) else {
|
|
continue;
|
|
};
|
|
|
|
if grid.data[push_index].can_fill() == false {
|
|
continue;
|
|
}
|
|
stack.push(GridAction::SpawnLiquid { at: push_vector, amount: source_amount });
|
|
}
|
|
},
|
|
_ => {},
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
for action in stack {
|
|
match action {
|
|
GridAction::MoveLiquid { from, to, amount } => {
|
|
let (from_index, to_index) = (grid.indexify(from).unwrap(), grid.indexify(to).unwrap());
|
|
grid.tranfer_fluid(from_index, to_index, amount);
|
|
},
|
|
GridAction::SpawnLiquid { at, amount } => {
|
|
let at_index = grid.indexify(at).unwrap();
|
|
grid.fill(at_index, amount);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|