216 lines
7 KiB
Rust
216 lines
7 KiB
Rust
|
use bevy::prelude::*;
|
||
|
use crate::*;
|
||
|
use bevy_prototype_lyon::prelude::*;
|
||
|
|
||
|
pub fn create_sys(
|
||
|
mut coms: Commands,
|
||
|
state: Res<UiState>,
|
||
|
mouse: Res<Input<MouseButton>>,
|
||
|
wnds: Res<Windows>,
|
||
|
q_cam: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
|
||
|
mut first_point: Local<Option<ShapeData>>,
|
||
|
paths: Query<&mut Path>,
|
||
|
spoints: Query<&SPoint>,
|
||
|
) {
|
||
|
let mouse_pos = get_mouse_pos(&q_cam, &wnds);
|
||
|
|
||
|
if let Some(mouse_pos) = mouse_pos {
|
||
|
|
||
|
if let Some(sd) = &mut *first_point {
|
||
|
update_main_shape_creation(paths, spoints, sd, mouse_pos);
|
||
|
|
||
|
if mouse.just_released(MouseButton::Left) {
|
||
|
let done = insert_edge_to_shape_creation(sd, mouse_pos, &mut coms);
|
||
|
|
||
|
if done {
|
||
|
coms.spawn()
|
||
|
.insert(first_point.take().unwrap());
|
||
|
|
||
|
*first_point = None;
|
||
|
}
|
||
|
}
|
||
|
else if mouse.just_released(MouseButton::Right) {
|
||
|
if let Some(e) = &sd.center {
|
||
|
coms.entity(*e).despawn();
|
||
|
}
|
||
|
coms.entity(sd.main_shape).despawn();
|
||
|
sd.edges.iter().for_each(|e| coms.entity(*e).despawn());
|
||
|
|
||
|
*first_point = None;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
else if mouse.just_released(MouseButton::Left) {
|
||
|
// We can now spawn a shape in the current mouse position...
|
||
|
// Spawn the first point
|
||
|
*first_point = Some(create_new_shape(&mut coms, mouse_pos, state.create_shape));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// Inserts a new edge/point to the currently created shape, return if the shape is complete
|
||
|
fn insert_edge_to_shape_creation(
|
||
|
sd: &mut ShapeData,
|
||
|
mpos: Vec2,
|
||
|
coms: &mut Commands,
|
||
|
) -> bool {
|
||
|
// Spawn the new point
|
||
|
// Spawn the first point(where the user just clicked)
|
||
|
let shape = shapes::Circle {
|
||
|
radius: 3.0,
|
||
|
center: mpos,
|
||
|
};
|
||
|
let np = coms.spawn_bundle(GeometryBuilder::build_as(
|
||
|
&shape,
|
||
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||
|
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
||
|
))
|
||
|
.insert(SPoint(mpos))
|
||
|
.id();
|
||
|
|
||
|
match sd.shape {
|
||
|
CreateShape::Triangle => {
|
||
|
sd.edges.push(np);
|
||
|
sd.edges.len() == 3
|
||
|
},
|
||
|
CreateShape::Square => {
|
||
|
sd.edges.push(np);
|
||
|
sd.edges.len() == 2
|
||
|
},
|
||
|
CreateShape::SquareCenter | CreateShape::Circle => {
|
||
|
sd.edges.push(np);
|
||
|
sd.edges.len() == 1
|
||
|
},
|
||
|
CreateShape::Capsule => {
|
||
|
if sd.edges.len() == 1 {
|
||
|
sd.edges.push(np);
|
||
|
false
|
||
|
}
|
||
|
else if sd.edges.len() == 2 {
|
||
|
sd.center = Some(np);
|
||
|
true
|
||
|
}
|
||
|
else {
|
||
|
panic!("Capsule was started without any edges... WHAT!");
|
||
|
}
|
||
|
},
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn update_main_shape_creation(
|
||
|
mut paths: Query<&mut Path>,
|
||
|
spoints: Query<&SPoint>,
|
||
|
sd: &ShapeData,
|
||
|
mpos: Vec2,
|
||
|
) {
|
||
|
let path = match sd.shape {
|
||
|
CreateShape::Triangle => {
|
||
|
if sd.edges.len() == 1 {
|
||
|
let first_point = spoints.get(sd.edges[0]).unwrap().0;
|
||
|
|
||
|
let shape = shapes::Line(first_point, mpos);
|
||
|
ShapePath::build_as(&shape)
|
||
|
}
|
||
|
else if sd.edges.len() == 2 {
|
||
|
let fp = spoints.get(sd.edges[0]).unwrap().0;
|
||
|
let sp = spoints.get(sd.edges[1]).unwrap().0;
|
||
|
|
||
|
let shape = shapes::Polygon {
|
||
|
points: Vec::from([fp, sp, mpos]),
|
||
|
closed: true,
|
||
|
};
|
||
|
ShapePath::build_as(&shape)
|
||
|
}
|
||
|
else {
|
||
|
panic!("Triangle cannot have less than 1 edges or more than 2 during creation!: {:?}", sd);
|
||
|
}
|
||
|
},
|
||
|
CreateShape::Square => {
|
||
|
assert!(sd.edges.len() == 1);
|
||
|
let opposite_point = spoints.get(sd.edges[0]).unwrap().0;
|
||
|
let ext = (mpos - opposite_point).abs();
|
||
|
let center = mpos.min(opposite_point) + ext * 0.5;
|
||
|
|
||
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::CustomCenter(center) };
|
||
|
ShapePath::build_as(&shape)
|
||
|
},
|
||
|
CreateShape::SquareCenter => {
|
||
|
assert!(sd.center.is_some());
|
||
|
let center = spoints.get(sd.center.unwrap()).unwrap().0;
|
||
|
let ext = (mpos - center).abs() * 2.0;
|
||
|
|
||
|
let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::CustomCenter(center) };
|
||
|
ShapePath::build_as(&shape)
|
||
|
},
|
||
|
CreateShape::Circle => {
|
||
|
assert!(sd.center.is_some());
|
||
|
let center= spoints.get(sd.center.unwrap()).unwrap().0;
|
||
|
|
||
|
let shape = shapes::Circle { radius: (mpos - center).length(), center };
|
||
|
ShapePath::build_as(&shape)
|
||
|
},
|
||
|
CreateShape::Capsule => {
|
||
|
panic!("Capsule creation not implemented yet!");
|
||
|
},
|
||
|
};
|
||
|
|
||
|
if let Ok(mut p) = paths.get_mut(sd.main_shape) {
|
||
|
*p = path;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn create_new_shape(coms: &mut Commands, pos: Vec2, create_shape: CreateShape) -> ShapeData {
|
||
|
// Shape draw mode...
|
||
|
let draw_mode = DrawMode::Outlined {
|
||
|
fill_mode: FillMode::color(Color::rgba(0.0, 0.5, 0.5, 0.4)),
|
||
|
outline_mode: StrokeMode::new(Color::rgba(0.0, 0.5, 0.5, 0.6), 3.0),
|
||
|
};
|
||
|
|
||
|
// Spawn the first point(where the user just clicked)
|
||
|
let shape = shapes::Circle {
|
||
|
radius: 3.0,
|
||
|
center: pos,
|
||
|
};
|
||
|
let fp = coms.spawn_bundle(GeometryBuilder::build_as(
|
||
|
&shape,
|
||
|
DrawMode::Fill(FillMode::color(Color::RED)),
|
||
|
Transform::from_translation(Vec3::new(0.0, 0.0, 1.0))
|
||
|
))
|
||
|
.insert(SPoint(pos))
|
||
|
.id();
|
||
|
// Spawn main shape!
|
||
|
let main_shape = match create_shape {
|
||
|
CreateShape::Triangle | CreateShape::Capsule => {
|
||
|
let shape = shapes::Line(pos, pos);
|
||
|
coms.spawn_bundle(GeometryBuilder::build_as(
|
||
|
&shape,
|
||
|
draw_mode,
|
||
|
Transform::from_translation(Vec3::ZERO)
|
||
|
)).id()
|
||
|
},
|
||
|
CreateShape::Square | CreateShape::SquareCenter => {
|
||
|
let shape = shapes::Rectangle { extents: Vec2::ZERO, origin: RectangleOrigin::CustomCenter(pos)};
|
||
|
coms.spawn_bundle(GeometryBuilder::build_as(
|
||
|
&shape,
|
||
|
draw_mode,
|
||
|
Transform::from_translation(Vec3::ZERO)
|
||
|
)).id()
|
||
|
},
|
||
|
CreateShape::Circle => {
|
||
|
let shape = shapes::Circle { radius: 0.0, center: pos };
|
||
|
coms.spawn_bundle(GeometryBuilder::build_as(
|
||
|
&shape,
|
||
|
draw_mode,
|
||
|
Transform::from_translation(Vec3::ZERO)
|
||
|
)).id()
|
||
|
},
|
||
|
};
|
||
|
// Get center point(if exists)
|
||
|
let center = match create_shape {
|
||
|
CreateShape::SquareCenter | CreateShape::Circle => Some(fp),
|
||
|
_ => None,
|
||
|
};
|
||
|
let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() };
|
||
|
|
||
|
ShapeData { shape: create_shape, main_shape, edges, center }
|
||
|
}
|