This commit is contained in:
Rendo 2026-08-02 21:35:19 +05:00
commit 86b9134156
5 changed files with 172 additions and 8 deletions

View file

@ -1,6 +1,6 @@
use bevy::prelude::*;
use crate::grid::Grid;
use crate::simulation::tick;
use crate::simulation::SimulationPlugin;
use crate::view::ViewPlugin;
@ -12,9 +12,8 @@ fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(ViewPlugin)
.add_plugins(SimulationPlugin)
.insert_resource(Grid::cube(16))
.insert_resource(Time::<Fixed>::from_hz(20.))
.add_systems(FixedUpdate, tick)
.run();
}

View file

@ -1,6 +1,16 @@
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,
@ -9,6 +19,13 @@ enum GridAction{
}
}
#[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();

View file

@ -31,7 +31,7 @@ pub struct TileMaterials {
pub fn debug_setup_grid(mut grid: ResMut<Grid>) {
use crate::grid::GridElement;
let mut tool = grid.manipulate();
tool.fill_xyz(5, 0, 0, 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 });
}
@ -116,10 +116,10 @@ pub fn cube(position: Vec3,index: usize,mesh: Handle<Mesh>) -> impl Scene {
}
}
pub fn update_cubes(query: Query<(&mut Mesh3d,&mut Visibility,&mut MeshMaterial3d<StandardMaterial>,&TileWatch)>, materials: Res<TileMaterials>, stages: Res<CubeStages>, grid: Res<Grid>) {
pub fn update_cubes(query: Query<(&mut Mesh3d,&mut Visibility,&mut MeshMaterial3d<StandardMaterial>,&TileWatch, &mut Transform)>, materials: Res<TileMaterials>, stages: Res<CubeStages>, grid: Res<Grid>) {
if grid.is_changed() == false { return; }
for (mut mesh,mut visibility, mut material, index) in query {
for (mut mesh,mut visibility, mut material, index, mut transform) in query {
let state = grid.data[index.0];
match state {
@ -129,7 +129,10 @@ pub fn update_cubes(query: Query<(&mut Mesh3d,&mut Visibility,&mut MeshMaterial3
crate::grid::GridElement::Water { amount } => {
*visibility = Visibility::Visible;
material.0 = materials.water.clone();
let stage = ((amount as f32)/(MAX_FLUID_AMOUNT as f32) * (FLUID_FULLNES_STAGES-1) as f32).round() as usize;
let stage = ((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();
},
crate::grid::GridElement::Solid => {

View file

@ -2,6 +2,8 @@ use bevy::prelude::*;
use game::GameViewPlugin;
use crate::view::ui::UIPlugin;
pub mod ui;
pub mod game;
@ -9,6 +11,6 @@ pub struct ViewPlugin;
impl Plugin for ViewPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(GameViewPlugin);
app.add_plugins((GameViewPlugin,UIPlugin));
}
}

View file

@ -0,0 +1,143 @@
use bevy::feathers::{FeathersPlugins, containers::*, controls::*, dark_theme::create_dark_theme, display::*, palette, rounded_corners::RoundedCorners, theme::UiTheme};
use bevy::ui_widgets::{Activate};
use bevy::prelude::*;
use crate::grid::{Grid, GridElement};
use crate::simulation::SimulationStatus;
pub struct UIPlugin;
impl Plugin for UIPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(FeathersPlugins)
.insert_resource(UiTheme(create_dark_theme()))
.add_systems(Startup, ui.spawn())
.add_systems(Update, count_water_amount);
}
}
#[derive(Component, Clone, Default)]
struct WaterLabel;
#[derive(Component, Clone, Default)]
struct SpeedLabel;
fn count_water_amount(grid: Res<Grid>, text: Single<&mut Text, With<WaterLabel>>) {
let mut sum: u32 = 0;
for i in 0..grid.cell_amount() {
let GridElement::Water { amount: water_amount } = grid.data[i as usize] else {
continue;
};
sum += water_amount;
}
let mut label = text.into_inner();
label.0 = format!("Water amount: {} liters",sum);
}
fn ui() -> impl Scene {
bsn! {
Node {
width: percent(100),
height: percent(100),
align_items: AlignItems::Start,
justify_content: JustifyContent::Start,
display: Display::Flex,
flex_direction: FlexDirection::Row,
column_gap: px(8)
}
Children [
debug_column()
]
}
}
fn debug_column() -> impl Scene {
bsn! {
Node {
display: Display::Flex,
flex_direction: FlexDirection::Column,
align_items: AlignItems::Stretch,
justify_content: JustifyContent::Start,
padding: px(8),
row_gap: px(8),
width: px(256),
min_width: px(256),
}
pane()
pane_header()
pane_body()
Children [
water_amount_label(),
pause_button(),
simulation_speed(),
]
}
}
fn water_amount_label() -> impl Scene {
bsn! {
Node {
width: percent(100),
height: px(32),
}
Children [
label("")
WaterLabel
]
}
}
fn pause_button() -> impl Scene {
bsn!{
@FeathersButton {
@caption: bsn! { label("Toggle simulation") }
}
on(|_activate: On<Activate>, current_state: Res<State<SimulationStatus>>, mut next_state: ResMut<NextState<SimulationStatus>>| {
next_state.set(match current_state.get() {
SimulationStatus::Paused => SimulationStatus::Continued,
SimulationStatus::Continued => SimulationStatus::Paused,
});
})
}
}
fn simulation_speed() -> impl Scene {
bsn! {
Node {
display: Display::Flex,
align_items: AlignItems::Stretch,
justify_content: JustifyContent::Start,
width: percent(100),
height: px(32),
}
Children [
@FeathersButton {
@caption: bsn! { label("<<") }
}
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;
current_frequency = if current_frequency == 1 {1} else {current_frequency / 2};
time.set_timestep_hz(current_frequency as f64);
label.0 = format!("{} hz", current_frequency);
})
,
label("")
SpeedLabel
Node {
justify_self: JustifySelf::Stretch
},
@FeathersButton {
@caption: bsn! { label(">>") }
}
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;
current_frequency = if current_frequency >= 128 {128} else {current_frequency * 2};
time.set_timestep_hz(current_frequency as f64);
label.0 = format!("{} hz", current_frequency);
}),
]
}
}