New tiles
This commit is contained in:
parent
86b9134156
commit
dea1b8599a
5 changed files with 144 additions and 38 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::MAX_FLUID_AMOUNT;
|
use crate::MAX_FLUID_AMOUNT;
|
||||||
|
|
||||||
#[derive(Default,Clone,Copy)]
|
#[derive(Default,Clone,Copy)]
|
||||||
|
|
@ -6,9 +8,20 @@ pub enum GridElement{
|
||||||
Air,
|
Air,
|
||||||
Water{amount: u32},
|
Water{amount: u32},
|
||||||
Solid,
|
Solid,
|
||||||
|
Drain,
|
||||||
|
Source{source_amount: u32},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GridElement {
|
impl GridElement {
|
||||||
|
pub fn can_fill(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
GridElement::Air => true,
|
||||||
|
GridElement::Water { amount: _ } => true,
|
||||||
|
GridElement::Solid => false,
|
||||||
|
GridElement::Drain => true,
|
||||||
|
GridElement::Source { source_amount: _ } => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn try_fill(&self, fill_amount: u32) -> Option<u32> {
|
pub fn try_fill(&self, fill_amount: u32) -> Option<u32> {
|
||||||
return match self {
|
return match self {
|
||||||
GridElement::Water { amount } => {
|
GridElement::Water { amount } => {
|
||||||
|
|
@ -23,7 +36,20 @@ impl GridElement {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GridElement::Air => Some(fill_amount),
|
GridElement::Air => Some(fill_amount),
|
||||||
|
GridElement::Drain => Some(fill_amount),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for GridElement {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f,"{}",match self {
|
||||||
|
GridElement::Air => "Air",
|
||||||
|
GridElement::Water { amount: _ } => "Water",
|
||||||
|
GridElement::Solid => "Solid",
|
||||||
|
GridElement::Drain => "Drain",
|
||||||
|
GridElement::Source { source_amount: _ } => "Source",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,10 +53,11 @@ impl Grid {
|
||||||
let to_new_value;
|
let to_new_value;
|
||||||
|
|
||||||
match (self.data[to],self.data[from]) {
|
match (self.data[to],self.data[from]) {
|
||||||
(GridElement::Air,GridElement::Water { amount: mut water_amount }) => {
|
(GridElement::Air,GridElement::Water { amount: water_amount }) => {
|
||||||
to_new_value = Some(GridElement::Water { amount: transfer_amount });
|
let moved_amount = water_amount.min(transfer_amount);
|
||||||
water_amount = water_amount.checked_sub(transfer_amount).unwrap_or(0);
|
let remaining_amount = water_amount-moved_amount;
|
||||||
from_new_value = if water_amount == 0 {Some(GridElement::Air)} else {Some(GridElement::Water { amount: water_amount })};
|
to_new_value = Some(GridElement::Water { amount: moved_amount });
|
||||||
|
from_new_value = if remaining_amount == 0 {Some(GridElement::Air)} else {Some(GridElement::Water { amount: remaining_amount })};
|
||||||
},
|
},
|
||||||
(GridElement::Water { amount: mut to_amount }, GridElement::Water { amount: mut from_amount }) => {
|
(GridElement::Water { amount: mut to_amount }, GridElement::Water { amount: mut from_amount }) => {
|
||||||
let transfer_amount = from_amount.min(transfer_amount);
|
let transfer_amount = from_amount.min(transfer_amount);
|
||||||
|
|
@ -71,7 +72,13 @@ impl Grid {
|
||||||
}
|
}
|
||||||
to_new_value = Some(GridElement::Water { amount: to_amount });
|
to_new_value = Some(GridElement::Water { amount: to_amount });
|
||||||
from_new_value = if from_amount == 0 {Some(GridElement::Air)} else {Some(GridElement::Water { amount: from_amount })};
|
from_new_value = if from_amount == 0 {Some(GridElement::Air)} else {Some(GridElement::Water { amount: from_amount })};
|
||||||
}
|
},
|
||||||
|
(GridElement::Drain, GridElement::Water { amount: from_amount }) => {
|
||||||
|
let transfer_amount = from_amount.min(transfer_amount);
|
||||||
|
let new_amount = from_amount - transfer_amount;
|
||||||
|
from_new_value = if new_amount == 0 {Some(GridElement::Air)} else {Some(GridElement::Water { amount: new_amount })};
|
||||||
|
to_new_value = None;
|
||||||
|
},
|
||||||
_ => {return;},
|
_ => {return;},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -84,6 +91,28 @@ impl Grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
pub fn fill(&mut self, at: usize, amount: u32) -> u32 {
|
||||||
|
let transformed_value;
|
||||||
|
let return_amount;
|
||||||
|
match self.data[at] {
|
||||||
|
GridElement::Air => {
|
||||||
|
transformed_value = GridElement::Water { amount };
|
||||||
|
return_amount = 0;
|
||||||
|
},
|
||||||
|
GridElement::Water { amount: water_amount } => {
|
||||||
|
let diff = MAX_FLUID_AMOUNT - water_amount;
|
||||||
|
let fill_amount = diff.min(amount);
|
||||||
|
return_amount = amount - fill_amount;
|
||||||
|
transformed_value = GridElement::Water { amount: water_amount + fill_amount };
|
||||||
|
},
|
||||||
|
GridElement::Drain => { return 0; },
|
||||||
|
_ => { return amount; }
|
||||||
|
}
|
||||||
|
|
||||||
|
self.data[at] = transformed_value;
|
||||||
|
|
||||||
|
return return_amount;
|
||||||
|
}
|
||||||
pub fn manipulate<'a>(&'a mut self) -> GridManipulationTools<'a> {
|
pub fn manipulate<'a>(&'a mut self) -> GridManipulationTools<'a> {
|
||||||
GridManipulationTools::new(self)
|
GridManipulationTools::new(self)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ enum GridAction{
|
||||||
from: UVec3,
|
from: UVec3,
|
||||||
to: UVec3,
|
to: UVec3,
|
||||||
amount: u32,
|
amount: u32,
|
||||||
|
},
|
||||||
|
SpawnLiquid {
|
||||||
|
at: UVec3,
|
||||||
|
amount: u32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,29 +56,41 @@ pub fn tick(mut grid: ResMut<Grid>) {
|
||||||
|
|
||||||
transfer_amount = transfer_amount.min(MAX_HORIZONTAL_FLOW) / 4;
|
transfer_amount = transfer_amount.min(MAX_HORIZONTAL_FLOW) / 4;
|
||||||
if transfer_amount > 0 {
|
if transfer_amount > 0 {
|
||||||
for lookup_vector in [UVec3::new(1,0,0),UVec3::new(0,0,1)] {
|
for lookup_vector in [IVec3::new(1,0,0),IVec3::new(0,0,1),IVec3::new(-1,0,0),IVec3::new(0,0,-1)] {
|
||||||
if let Some(toward_vector) = vector.checked_add(lookup_vector) {
|
let push_vector = (vector.as_ivec3() + lookup_vector).max(IVec3::ZERO).as_uvec3();
|
||||||
if let Some(index) = grid.indexify(toward_vector) {
|
if push_vector == vector {
|
||||||
if let Some(toward_amount) = grid.data
|
continue;
|
||||||
[index]
|
|
||||||
.try_fill(transfer_amount.min(MAX_VERTICAL_FLOW)) {
|
|
||||||
stack.push(GridAction::MoveLiquid { from: vector, to: toward_vector, amount: toward_amount });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let Some(push_index) = grid.indexify(push_vector) else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(toward_vector) = vector.checked_sub(lookup_vector) {
|
let Some(push_amount) = grid.data[push_index].try_fill(transfer_amount) else {
|
||||||
if let Some(index) = grid.indexify(toward_vector) {
|
continue;
|
||||||
if let Some(toward_amount) = grid.data
|
};
|
||||||
[index]
|
stack.push(GridAction::MoveLiquid { from: vector, to: push_vector, amount: push_amount });
|
||||||
.try_fill(transfer_amount.min(MAX_VERTICAL_FLOW)) {
|
|
||||||
stack.push(GridAction::MoveLiquid { from: vector, to: toward_vector, amount: toward_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 });
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +104,10 @@ pub fn tick(mut grid: ResMut<Grid>) {
|
||||||
let (from_index, to_index) = (grid.indexify(from).unwrap(), grid.indexify(to).unwrap());
|
let (from_index, to_index) = (grid.indexify(from).unwrap(), grid.indexify(to).unwrap());
|
||||||
grid.tranfer_fluid(from_index, to_index, amount);
|
grid.tranfer_fluid(from_index, to_index, amount);
|
||||||
},
|
},
|
||||||
|
GridAction::SpawnLiquid { at, amount } => {
|
||||||
|
let at_index = grid.indexify(at).unwrap();
|
||||||
|
grid.fill(at_index, amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use crate::grid::Grid;
|
use crate::grid::{Grid,GridElement};
|
||||||
use crate::MAX_FLUID_AMOUNT;
|
use crate::MAX_FLUID_AMOUNT;
|
||||||
|
|
||||||
const FLUID_FULLNES_STAGES: usize = 7;
|
const FLUID_FULLNES_STAGES: usize = 7;
|
||||||
|
|
@ -26,6 +26,8 @@ pub struct TileWatch(pub usize);
|
||||||
pub struct TileMaterials {
|
pub struct TileMaterials {
|
||||||
pub solid: Handle<StandardMaterial>,
|
pub solid: Handle<StandardMaterial>,
|
||||||
pub water: Handle<StandardMaterial>,
|
pub water: Handle<StandardMaterial>,
|
||||||
|
pub drain: Handle<StandardMaterial>,
|
||||||
|
pub source: Handle<StandardMaterial>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn debug_setup_grid(mut grid: ResMut<Grid>) {
|
pub fn debug_setup_grid(mut grid: ResMut<Grid>) {
|
||||||
|
|
@ -33,6 +35,8 @@ pub fn debug_setup_grid(mut grid: ResMut<Grid>) {
|
||||||
let mut tool = grid.manipulate();
|
let mut tool = grid.manipulate();
|
||||||
tool.fill_xyz(5, 0, 1, 5, 0, 14, GridElement::Solid);
|
tool.fill_xyz(5, 0, 1, 5, 0, 14, GridElement::Solid);
|
||||||
tool.fill_xyz(0, 0, 0, 4, 0, 15, GridElement::Water { amount: MAX_FLUID_AMOUNT });
|
tool.fill_xyz(0, 0, 0, 4, 0, 15, GridElement::Water { amount: MAX_FLUID_AMOUNT });
|
||||||
|
//tool.set_xyz(0, 0, 6, GridElement::Source { source_amount: MAX_FLUID_AMOUNT });
|
||||||
|
tool.set_xyz(15,0, 6, GridElement::Drain);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn setup_view_cubes(
|
pub fn setup_view_cubes(
|
||||||
|
|
@ -47,17 +51,26 @@ pub fn setup_view_cubes(
|
||||||
let mesh = meshes.add(Cuboid::new(1., tile_height, 1.));
|
let mesh = meshes.add(Cuboid::new(1., tile_height, 1.));
|
||||||
stages.0.push(mesh);
|
stages.0.push(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
tile_materials.water = materials.add(StandardMaterial {
|
*tile_materials = TileMaterials {
|
||||||
base_color: Color::hsl(172.,0.502,0.571),
|
solid: materials.add(StandardMaterial {
|
||||||
..default()
|
|
||||||
});
|
|
||||||
|
|
||||||
tile_materials.solid = materials.add(StandardMaterial {
|
|
||||||
base_color: Color::hsl(268., 0.778, 0.499),
|
base_color: Color::hsl(268., 0.778, 0.499),
|
||||||
..default()
|
..default()
|
||||||
});
|
}),
|
||||||
|
water: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::hsl(172.,0.502,0.571),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
drain: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::hsl(342., 0.628, 0.685),
|
||||||
|
..default()
|
||||||
|
}),
|
||||||
|
source: materials.add(StandardMaterial {
|
||||||
|
base_color: Color::hsl(172., 0.502, 0.371),
|
||||||
|
..default()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let mesh = stages.0[FLUID_FULLNES_STAGES-1].clone();
|
let mesh = stages.0[FLUID_FULLNES_STAGES-1].clone();
|
||||||
|
|
||||||
for i in 0..grid.cell_amount() {
|
for i in 0..grid.cell_amount() {
|
||||||
|
|
@ -123,10 +136,10 @@ pub fn update_cubes(query: Query<(&mut Mesh3d,&mut Visibility,&mut MeshMaterial3
|
||||||
let state = grid.data[index.0];
|
let state = grid.data[index.0];
|
||||||
|
|
||||||
match state {
|
match state {
|
||||||
crate::grid::GridElement::Air => {
|
GridElement::Air => {
|
||||||
*visibility = Visibility::Hidden;
|
*visibility = Visibility::Hidden;
|
||||||
},
|
},
|
||||||
crate::grid::GridElement::Water { amount } => {
|
GridElement::Water { amount } => {
|
||||||
*visibility = Visibility::Visible;
|
*visibility = Visibility::Visible;
|
||||||
material.0 = materials.water.clone();
|
material.0 = materials.water.clone();
|
||||||
let stage = ((amount as f32)/(MAX_FLUID_AMOUNT as f32) * (FLUID_FULLNES_STAGES-1) as f32).ceil() as usize;
|
let stage = ((amount as f32)/(MAX_FLUID_AMOUNT as f32) * (FLUID_FULLNES_STAGES-1) as f32).ceil() as usize;
|
||||||
|
|
@ -135,11 +148,26 @@ pub fn update_cubes(query: Query<(&mut Mesh3d,&mut Visibility,&mut MeshMaterial3
|
||||||
|
|
||||||
mesh.0 = stages.0[stage].clone();
|
mesh.0 = stages.0[stage].clone();
|
||||||
},
|
},
|
||||||
crate::grid::GridElement::Solid => {
|
GridElement::Solid => {
|
||||||
*visibility = Visibility::Visible;
|
*visibility = Visibility::Visible;
|
||||||
material.0 = materials.solid.clone();
|
material.0 = materials.solid.clone();
|
||||||
mesh.0 = stages.0[FLUID_FULLNES_STAGES-1].clone();
|
mesh.0 = stages.0[FLUID_FULLNES_STAGES-1].clone();
|
||||||
},
|
},
|
||||||
|
GridElement::Drain => {
|
||||||
|
*visibility = Visibility::Visible;
|
||||||
|
material.0 = materials.drain.clone();
|
||||||
|
mesh.0 = stages.0[FLUID_FULLNES_STAGES-1].clone();
|
||||||
|
},
|
||||||
|
GridElement::Source { source_amount } => {
|
||||||
|
*visibility = Visibility::Visible;
|
||||||
|
material.0 = materials.source.clone();
|
||||||
|
let stage = ((source_amount as f32)/(MAX_FLUID_AMOUNT as f32) * (FLUID_FULLNES_STAGES-1) as f32).ceil() as usize;
|
||||||
|
|
||||||
|
transform.translation = grid.deindexify(index.0 as u32).as_vec3() - vec3(0.,((FLUID_FULLNES_STAGES-1-stage) as f32 / (FLUID_FULLNES_STAGES as f32))/2.,0.);
|
||||||
|
|
||||||
|
mesh.0 = stages.0[stage].clone();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy::feathers::{FeathersPlugins, containers::*, controls::*, dark_theme::create_dark_theme, display::*, palette, rounded_corners::RoundedCorners, theme::UiTheme};
|
use bevy::feathers::{FeathersPlugins, containers::*, controls::*, dark_theme::create_dark_theme, display::*, theme::UiTheme};
|
||||||
use bevy::ui_widgets::{Activate};
|
use bevy::ui_widgets::{Activate};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
|
|
@ -22,6 +22,9 @@ struct WaterLabel;
|
||||||
#[derive(Component, Clone, Default)]
|
#[derive(Component, Clone, Default)]
|
||||||
struct SpeedLabel;
|
struct SpeedLabel;
|
||||||
|
|
||||||
|
const MAX_FREQUENCY: u32 = 512;
|
||||||
|
const MIN_FREQUENCY: u32 = 1;
|
||||||
|
|
||||||
fn count_water_amount(grid: Res<Grid>, text: Single<&mut Text, With<WaterLabel>>) {
|
fn count_water_amount(grid: Res<Grid>, text: Single<&mut Text, With<WaterLabel>>) {
|
||||||
let mut sum: u32 = 0;
|
let mut sum: u32 = 0;
|
||||||
for i in 0..grid.cell_amount() {
|
for i in 0..grid.cell_amount() {
|
||||||
|
|
@ -119,7 +122,7 @@ fn simulation_speed() -> impl Scene {
|
||||||
}
|
}
|
||||||
on(|_activate: On<Activate>, mut time: ResMut<Time<Fixed>>, mut label: Single<&mut Text, With<SpeedLabel>>|{
|
on(|_activate: On<Activate>, mut time: ResMut<Time<Fixed>>, mut label: Single<&mut Text, With<SpeedLabel>>|{
|
||||||
let mut current_frequency = (1./time.timestep().as_secs_f64()) as u32;
|
let mut current_frequency = (1./time.timestep().as_secs_f64()) as u32;
|
||||||
current_frequency = if current_frequency == 1 {1} else {current_frequency / 2};
|
current_frequency = if current_frequency <= MIN_FREQUENCY {MIN_FREQUENCY} else {current_frequency / 2};
|
||||||
time.set_timestep_hz(current_frequency as f64);
|
time.set_timestep_hz(current_frequency as f64);
|
||||||
label.0 = format!("{} hz", current_frequency);
|
label.0 = format!("{} hz", current_frequency);
|
||||||
})
|
})
|
||||||
|
|
@ -134,7 +137,7 @@ fn simulation_speed() -> impl Scene {
|
||||||
}
|
}
|
||||||
on(|_activate: On<Activate>, mut time: ResMut<Time<Fixed>>, mut label: Single<&mut Text, With<SpeedLabel>>|{
|
on(|_activate: On<Activate>, mut time: ResMut<Time<Fixed>>, mut label: Single<&mut Text, With<SpeedLabel>>|{
|
||||||
let mut current_frequency = (1./time.timestep().as_secs_f64()) as u32;
|
let mut current_frequency = (1./time.timestep().as_secs_f64()) as u32;
|
||||||
current_frequency = if current_frequency >= 128 {128} else {current_frequency * 2};
|
current_frequency = if current_frequency >= MAX_FREQUENCY {MAX_FREQUENCY} else {current_frequency * 2};
|
||||||
time.set_timestep_hz(current_frequency as f64);
|
time.set_timestep_hz(current_frequency as f64);
|
||||||
label.0 = format!("{} hz", current_frequency);
|
label.0 = format!("{} hz", current_frequency);
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue