feat: editor paint undone

This commit is contained in:
Rendo 2026-08-04 03:33:19 +05:00
commit fb0e374f17
4 changed files with 144 additions and 13 deletions

72
src/view/editor.rs Normal file
View file

@ -0,0 +1,72 @@
use bevy::prelude::*;
use bevy::picking::backend::ray::RayMap;
use crate::grid::{Grid, GridElement};
pub struct EditorPlugin;
impl Plugin for EditorPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<EditorTools>().add_observer(apply_tool).add_systems(Update, calculate_tools);
}
}
#[derive(Default, Clone, PartialEq, Eq,Resource)]
pub enum EditorTools {
#[default]
None,
Paint{ position: UVec3, block: GridElement },
}
#[derive(Component,Default,Clone)]
pub struct ViewCube;
#[derive(Event)]
pub struct ApplyTool(EditorTools);
pub fn calculate_tools(
mut commands: Commands,
mouse_button: Res<ButtonInput<MouseButton>>,
ray_map: Res<RayMap>,
mut raycast: MeshRayCast,
mut tool: ResMut<EditorTools>,
mut gizmos: Gizmos
) {
let new_tool: Option<EditorTools> = match tool.clone() {
EditorTools::None => None,
EditorTools::Paint{position: _, block} => {
let mut new_position: Option<UVec3> = None;
for (_, ray) in ray_map.iter() {
let Some((_, hit)) = raycast.cast_ray(*ray, &MeshRayCastSettings::default()).first() else {continue;};
gizmos.sphere(hit.point.round(), 0.5, Color::BLACK);
new_position = Some(hit.point.floor().as_uvec3());
}
new_position.map(|pos|{
EditorTools::Paint { position: pos , block }}
)
},
};
if let Some(new_tool) = new_tool {
*tool = new_tool;
}
if mouse_button.just_pressed(MouseButton::Left) {
match tool.clone() {
EditorTools::None => {},
EditorTools::Paint { position, block } => {
commands.trigger(ApplyTool(EditorTools::Paint { position, block }));
},
}
}
}
pub fn apply_tool(params: On<ApplyTool>, mut grid: ResMut<Grid>) {
match params.0 {
EditorTools::None => {},
EditorTools::Paint { position, block } => {
let index = grid.indexify(position).unwrap();
grid.data[index] = block;
},
}
}

View file

@ -8,10 +8,10 @@ pub struct GameViewPlugin;
impl Plugin for GameViewPlugin {
fn build(&self, app: &mut App) {
app.add_systems(PreStartup, debug_setup_grid)
app
.init_resource::<CubeStages>()
.init_resource::<TileMaterials>()
.add_systems(Startup, setup_view_cubes)
.add_systems(Startup, (setup_building_planes,setup_view_cubes))
.add_systems(Update, update_cubes);
}
}
@ -33,14 +33,31 @@ pub struct TileMaterials {
pub source: Handle<StandardMaterial>,
}
pub fn debug_setup_grid(mut grid: ResMut<Grid>) {
use crate::grid::GridElement;
let mut tool = grid.manipulate();
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.set_xyz(0, 0, 6, GridElement::Source { source_amount: MAX_FLUID_AMOUNT });
tool.set_xyz(0, 8, 6, GridElement::Source { source_amount: MAX_FLUID_AMOUNT });
//tool.set_xyz(15,0, 6, GridElement::Drain);
pub fn setup_building_planes(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
grid: Res<Grid>
) {
let mut mesh: Mesh = (Cuboid::new(grid.size.x as f32, grid.size.y as f32, grid.size.z as f32).mesh()).into();
let _ = mesh.invert_winding();
let mesh_handle = meshes.add(mesh);
let center = (grid.size.as_vec3() - Vec3::ONE)/2.;
commands.spawn_scene(bsn!{
Mesh3d(mesh_handle)
Transform {
translation: center
}
MeshMaterial3d<StandardMaterial>(asset_value(
StandardMaterial {
base_color: Color::WHITE,
..default()
}
))
Visibility::Visible
});
}
pub fn setup_view_cubes(

View file

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

View file

@ -4,6 +4,7 @@ use bevy::prelude::*;
use crate::grid::{Grid, GridElement};
use crate::simulation::SimulationStatus;
use crate::view::editor::EditorTools;
pub struct UIPlugin;
@ -22,6 +23,9 @@ struct WaterLabel;
#[derive(Component, Clone, Default)]
struct SpeedLabel;
#[derive(Component, Clone, Default)]
struct ToolLabel;
const MAX_FREQUENCY: u32 = 512;
const MIN_FREQUENCY: u32 = 1;
@ -52,6 +56,7 @@ fn ui() -> impl Scene {
}
Children [
debug_column()
editor_column()
]
}
}
@ -79,6 +84,42 @@ fn debug_column() -> impl Scene {
}
}
fn editor_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 [
label("Tools")
ToolLabel,
@FeathersButton {
@caption: bsn!{label("None")}
}
on(|_activate: On<Activate>, mut tool: ResMut<EditorTools>, mut label: Single<&mut Text, With<ToolLabel>>| {
*tool = EditorTools::None;
label.0 = "Current tool: None".to_string();
}),
@FeathersButton {
@caption: bsn!{label("Paint")}
}
on(|_activate: On<Activate>, mut tool: ResMut<EditorTools>, mut label: Single<&mut Text, With<ToolLabel>>| {
*tool = EditorTools::Paint { position: UVec3::default(), block: GridElement::Solid };
label.0 = "Current tool: Paint".to_string();
}),
]
}
}
fn water_amount_label() -> impl Scene {
bsn! {
Node {