rotate + shape_tree start
This commit is contained in:
parent
f52c7b9057
commit
7a3d51a626
6 changed files with 175 additions and 75 deletions
11
README.md
11
README.md
|
@ -1,3 +1,14 @@
|
||||||
# shape_maker
|
# shape_maker
|
||||||
|
|
||||||
Eventually, this will be a level editor... But until then, I guess it's just fun?
|
Eventually, this will be a level editor... But until then, I guess it's just fun?
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
[ ] Items tree view showing all shapes with their child nodes and purposes(maybe location and such as well?)
|
||||||
|
[ ] Delete shapes
|
||||||
|
[ ] Import images
|
||||||
|
[ ] Drag camera around
|
||||||
|
[ ] Zome in/out
|
||||||
|
[ ] Export
|
||||||
|
[ ] Import
|
||||||
|
[ ] Save? (maybe just import and export directly?)
|
||||||
|
|
|
@ -7,8 +7,12 @@ use bevy_egui::egui;
|
||||||
mod create;
|
mod create;
|
||||||
mod helpers;
|
mod helpers;
|
||||||
mod modify;
|
mod modify;
|
||||||
|
mod rotate;
|
||||||
|
mod ui;
|
||||||
|
pub use ui::{action_bar_sys, shape_tree_sys};
|
||||||
pub use modify::modify_sys;
|
pub use modify::modify_sys;
|
||||||
pub use create::create_sys;
|
pub use create::create_sys;
|
||||||
|
pub use rotate::rotate_sys;
|
||||||
pub use helpers::*;
|
pub use helpers::*;
|
||||||
|
|
||||||
|
|
||||||
|
|
75
src/main.rs
75
src/main.rs
|
@ -1,5 +1,4 @@
|
||||||
use bevy::ecs::schedule::ShouldRun;
|
use bevy::ecs::schedule::ShouldRun;
|
||||||
use bevy::math::Vec3Swizzles;
|
|
||||||
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
use bevy::{prelude::*, window::PresentMode, winit::WinitSettings};
|
||||||
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
use bevy_egui::{egui, EguiContext, EguiPlugin};
|
||||||
use bevy_prototype_lyon::prelude::*;
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
@ -38,7 +37,11 @@ fn main() {
|
||||||
.add_system(modify_sys.with_run_criteria(|state: Res<UiState>, mut ec: ResMut<EguiContext>|
|
.add_system(modify_sys.with_run_criteria(|state: Res<UiState>, mut ec: ResMut<EguiContext>|
|
||||||
if !ec.ctx_mut().is_pointer_over_area() && state.current_action == Action::Modify { ShouldRun::Yes } else { ShouldRun::No }
|
if !ec.ctx_mut().is_pointer_over_area() && state.current_action == Action::Modify { ShouldRun::Yes } else { ShouldRun::No }
|
||||||
))
|
))
|
||||||
|
.add_system(rotate_sys.with_run_criteria(|state: Res<UiState>, mut ec: ResMut<EguiContext>|
|
||||||
|
if !ec.ctx_mut().is_pointer_over_area() && state.current_action == Action::Rotate { ShouldRun::Yes } else { ShouldRun::No }
|
||||||
|
))
|
||||||
.add_system(action_bar_sys)
|
.add_system(action_bar_sys)
|
||||||
|
.add_system(shape_tree_sys)
|
||||||
;
|
;
|
||||||
|
|
||||||
app.run();
|
app.run();
|
||||||
|
@ -56,72 +59,4 @@ fn configure_visuals(mut egui_ctx: ResMut<EguiContext>) {
|
||||||
window_rounding: 0.0.into(),
|
window_rounding: 0.0.into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn action_bar_sys(
|
|
||||||
mut egui_ctx: ResMut<EguiContext>,
|
|
||||||
mut state: ResMut<UiState>,
|
|
||||||
colors: Res<ButtonsColors>,
|
|
||||||
) {
|
|
||||||
egui::Window::new("buttons_float")
|
|
||||||
.default_pos((50.0, 20.0))
|
|
||||||
.title_bar(false)
|
|
||||||
.resizable(false)
|
|
||||||
.show(egui_ctx.ctx_mut(), |ui| {
|
|
||||||
ui.horizontal(|hui| {
|
|
||||||
let m = hui.button(egui::RichText::new("M").color(state.current_action_color(&colors, Action::Modify)))
|
|
||||||
.on_hover_text("Modify");
|
|
||||||
if m.clicked() {
|
|
||||||
state.current_action = Action::Modify;
|
|
||||||
}
|
|
||||||
let r = hui.button(egui::RichText::new("R").color(state.current_action_color(&colors, Action::Rotate)))
|
|
||||||
.on_hover_text("Rotate");
|
|
||||||
if r.clicked() {
|
|
||||||
state.current_action = Action::Rotate;
|
|
||||||
}
|
|
||||||
let c = hui.button(egui::RichText::new("C").color(state.current_action_color(&colors, Action::Create)))
|
|
||||||
.on_hover_text("Create");
|
|
||||||
if c.clicked() {
|
|
||||||
state.current_action = Action::Create;
|
|
||||||
}
|
|
||||||
let d = hui.button(egui::RichText::new("D").color(state.current_action_color(&colors, Action::Delete)))
|
|
||||||
.on_hover_text("Delete");
|
|
||||||
if d.clicked() {
|
|
||||||
state.current_action = Action::Delete;
|
|
||||||
}
|
|
||||||
hui.label(" | ");
|
|
||||||
|
|
||||||
if hui.button(" I ").on_hover_text("Import Image").clicked() {
|
|
||||||
println!("Importing Images is still not supported!");
|
|
||||||
}
|
|
||||||
|
|
||||||
hui.label(": :");
|
|
||||||
});
|
|
||||||
|
|
||||||
if state.current_action == Action::Create {
|
|
||||||
ui.horizontal(|hui| {
|
|
||||||
let tri = hui.button(egui::RichText::new("Tri").color(state.create_shape_color(&colors, CreateShape::Triangle)))
|
|
||||||
.on_hover_text("Triangle - from 3 edges");
|
|
||||||
if tri.clicked() {
|
|
||||||
state.create_shape = CreateShape::Triangle;
|
|
||||||
}
|
|
||||||
let squ = hui.button(egui::RichText::new("Squ").color(state.create_shape_color(&colors, CreateShape::Square)))
|
|
||||||
.on_hover_text("Square - from 2 opposing edges");
|
|
||||||
if squ.clicked() {
|
|
||||||
state.create_shape = CreateShape::Square;
|
|
||||||
}
|
|
||||||
let cir = hui.button(egui::RichText::new("Cir").color(state.create_shape_color(&colors, CreateShape::Circle)))
|
|
||||||
.on_hover_text("Circle - center point and radius");
|
|
||||||
if cir.clicked() {
|
|
||||||
state.create_shape = CreateShape::Circle;
|
|
||||||
}
|
|
||||||
// let cap = hui.button(egui::RichText::new("Cap").color(state.create_shape_color(&colors, CreateShape::Capsule)))
|
|
||||||
// .on_hover_text("Capsule - from 2 center points and a radius");
|
|
||||||
// if cap.clicked() {
|
|
||||||
// state.create_shape = CreateShape::Capsule;
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy::math::Vec3Swizzles;
|
use bevy::math::{Vec3Swizzles, Mat2};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use bevy_prototype_lyon::prelude::*;
|
use bevy_prototype_lyon::prelude::*;
|
||||||
|
@ -54,18 +54,20 @@ pub fn modify_sys(
|
||||||
}
|
}
|
||||||
else if let Ok(mut t) = transforms.get_mut(pe) {
|
else if let Ok(mut t) = transforms.get_mut(pe) {
|
||||||
// Update the dot position
|
// Update the dot position
|
||||||
let delta = mouse_pos - gtransforms.get(pe).unwrap().translation.xy();
|
let gt = gtransforms.get(pe).unwrap();
|
||||||
|
let ang = gt.rotation.to_euler(EulerRot::XYZ).2;
|
||||||
|
let delta = Mat2::from_angle(-ang) * (mouse_pos - gt.translation.xy());
|
||||||
t.translation += delta.extend(0.0);
|
t.translation += delta.extend(0.0);
|
||||||
// We need to recalculate the center, and update the points to be the new relevant point from the center
|
// We need to recalculate the center, and update the points to be the new relevant point from the center
|
||||||
let center_offset = calc_shape_center_offset(&transforms, sd).extend(0.0);
|
let center_offset = calc_shape_center_offset(&transforms, sd);
|
||||||
// Update each edge's offset, and then move the main shape's translation
|
// Update each edge's offset, and then move the main shape's translation
|
||||||
for edge in sd.edges.iter() {
|
for edge in sd.edges.iter() {
|
||||||
if let Ok(mut t) = transforms.get_mut(*edge) {
|
if let Ok(mut t) = transforms.get_mut(*edge) {
|
||||||
t.translation -= center_offset;
|
t.translation -= center_offset.extend(0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
t.translation += center_offset;
|
t.translation += (Mat2::from_angle(ang) * center_offset).extend(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we need to update the shape itself
|
// Now we need to update the shape itself
|
||||||
|
|
44
src/rotate.rs
Normal file
44
src/rotate.rs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::math::Vec3Swizzles;
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub fn rotate_sys(
|
||||||
|
mut holding: Local<Option<(Entity, f32)>>, // main_shape we hold and the angle offset
|
||||||
|
mouse: Res<Input<MouseButton>>,
|
||||||
|
wnds: Res<Windows>,
|
||||||
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||||||
|
p_size: Res<PointSize>,
|
||||||
|
mut transforms: Query<&mut Transform>,
|
||||||
|
gtransforms: Query<&GlobalTransform>,
|
||||||
|
shapes: Query<&ShapeData>,
|
||||||
|
) {
|
||||||
|
if let Some(mouse_pos) = get_mouse_pos(&q_cam, &wnds) {
|
||||||
|
if mouse.just_pressed(MouseButton::Left) && holding.is_none() {
|
||||||
|
for sd in shapes.iter().filter(|x| x.shape != CreateShape::Circle /* no reason to rotate circles ;) */) {
|
||||||
|
for edge in sd.edges.iter() {
|
||||||
|
if let Ok(gt) = gtransforms.get(*edge) {
|
||||||
|
if (mouse_pos - gt.translation.xy()).length_squared() < p_size.0.powi(2) {
|
||||||
|
// We grabbed an entity, we now need an angle offset
|
||||||
|
let center = gtransforms.get(sd.main_shape).unwrap().translation.xy();
|
||||||
|
let angle_offset = (mouse_pos - center).angle_between(Vec2::X);
|
||||||
|
let angle_offset = transforms.get(sd.main_shape).unwrap().rotation.to_euler(EulerRot::XYZ).2 + angle_offset;
|
||||||
|
|
||||||
|
*holding = Some((sd.main_shape, angle_offset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if mouse.just_released(MouseButton::Left) {
|
||||||
|
*holding = None;
|
||||||
|
}
|
||||||
|
else if let Some((en, ang_offset)) = *holding {
|
||||||
|
let center = gtransforms.get(en).unwrap().translation.xy();
|
||||||
|
let ang_curr = (mouse_pos - center).angle_between(Vec2::X);
|
||||||
|
|
||||||
|
if let Ok(mut t) = transforms.get_mut(en) {
|
||||||
|
t.rotation = Quat::from_rotation_z(ang_offset - ang_curr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
src/ui.rs
Normal file
104
src/ui.rs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_egui::{egui, EguiContext};
|
||||||
|
use crate::*;
|
||||||
|
|
||||||
|
pub fn action_bar_sys(
|
||||||
|
mut egui_ctx: ResMut<EguiContext>,
|
||||||
|
mut state: ResMut<UiState>,
|
||||||
|
colors: Res<ButtonsColors>,
|
||||||
|
) {
|
||||||
|
egui::Window::new("buttons_float")
|
||||||
|
.default_pos((20.0, 20.0))
|
||||||
|
.title_bar(false)
|
||||||
|
.resizable(false)
|
||||||
|
.show(egui_ctx.ctx_mut(), |ui| {
|
||||||
|
ui.horizontal(|hui| {
|
||||||
|
let m = hui.button(egui::RichText::new("M").color(state.current_action_color(&colors, Action::Modify)))
|
||||||
|
.on_hover_text("Modify");
|
||||||
|
if m.clicked() {
|
||||||
|
state.current_action = Action::Modify;
|
||||||
|
}
|
||||||
|
let r = hui.button(egui::RichText::new("R").color(state.current_action_color(&colors, Action::Rotate)))
|
||||||
|
.on_hover_text("Rotate");
|
||||||
|
if r.clicked() {
|
||||||
|
state.current_action = Action::Rotate;
|
||||||
|
}
|
||||||
|
let c = hui.button(egui::RichText::new("C").color(state.current_action_color(&colors, Action::Create)))
|
||||||
|
.on_hover_text("Create");
|
||||||
|
if c.clicked() {
|
||||||
|
state.current_action = Action::Create;
|
||||||
|
}
|
||||||
|
let d = hui.button(egui::RichText::new("D").color(state.current_action_color(&colors, Action::Delete)))
|
||||||
|
.on_hover_text("Delete");
|
||||||
|
if d.clicked() {
|
||||||
|
state.current_action = Action::Delete;
|
||||||
|
}
|
||||||
|
hui.label(" | ");
|
||||||
|
|
||||||
|
if hui.button(" I ").on_hover_text("Import Image").clicked() {
|
||||||
|
println!("Importing Images is still not supported!");
|
||||||
|
}
|
||||||
|
|
||||||
|
hui.label(": :");
|
||||||
|
});
|
||||||
|
|
||||||
|
if state.current_action == Action::Create {
|
||||||
|
ui.horizontal(|hui| {
|
||||||
|
let tri = hui.button(egui::RichText::new("Tri").color(state.create_shape_color(&colors, CreateShape::Triangle)))
|
||||||
|
.on_hover_text("Triangle - from 3 edges");
|
||||||
|
if tri.clicked() {
|
||||||
|
state.create_shape = CreateShape::Triangle;
|
||||||
|
}
|
||||||
|
let squ = hui.button(egui::RichText::new("Squ").color(state.create_shape_color(&colors, CreateShape::Square)))
|
||||||
|
.on_hover_text("Square - from 2 opposing edges");
|
||||||
|
if squ.clicked() {
|
||||||
|
state.create_shape = CreateShape::Square;
|
||||||
|
}
|
||||||
|
let cir = hui.button(egui::RichText::new("Cir").color(state.create_shape_color(&colors, CreateShape::Circle)))
|
||||||
|
.on_hover_text("Circle - center point and radius");
|
||||||
|
if cir.clicked() {
|
||||||
|
state.create_shape = CreateShape::Circle;
|
||||||
|
}
|
||||||
|
// let cap = hui.button(egui::RichText::new("Cap").color(state.create_shape_color(&colors, CreateShape::Capsule)))
|
||||||
|
// .on_hover_text("Capsule - from 2 center points and a radius");
|
||||||
|
// if cap.clicked() {
|
||||||
|
// state.create_shape = CreateShape::Capsule;
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shape_tree_sys(
|
||||||
|
mut egui_ctx: ResMut<EguiContext>,
|
||||||
|
shapes: Query<&ShapeData>,
|
||||||
|
mut transforms: Query<&mut Transform>,
|
||||||
|
) {
|
||||||
|
if !shapes.is_empty() {
|
||||||
|
egui::Window::new("Shape Tree")
|
||||||
|
.default_pos((10.0, 100.0))
|
||||||
|
.title_bar(true)
|
||||||
|
.resizable(false)
|
||||||
|
.show(egui_ctx.ctx_mut(), |ui| {
|
||||||
|
for sd in shapes.iter() {
|
||||||
|
ui.collapsing(format!("{:?}", sd.shape), |ui| {
|
||||||
|
|
||||||
|
if let Ok(mut t) = transforms.get_mut(sd.main_shape) {
|
||||||
|
ui.horizontal(|hui| {
|
||||||
|
hui.label("Translation:");
|
||||||
|
hui.add(egui::DragValue::new(&mut t.translation.x));
|
||||||
|
hui.add(egui::DragValue::new(&mut t.translation.y));
|
||||||
|
});
|
||||||
|
ui.horizontal(|hui| {
|
||||||
|
hui.label("Rotation:");
|
||||||
|
let mut rot = t.rotation.to_euler(EulerRot::XYZ).2.to_degrees();
|
||||||
|
if hui.add(egui::DragValue::new(&mut rot).suffix("°")).changed() {
|
||||||
|
t.rotation = Quat::from_rotation_z(rot.to_radians());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue