use bevy::math::Vec3Swizzles; use bevy::prelude::*; use crate::*; use bevy_prototype_lyon::prelude::*; pub fn create_sys( mut coms: Commands, p_size: Res, state: Res, mouse: Res>, wnds: Res, mut first_point: Local>, q_cam: Query<(&Camera, &GlobalTransform), With>, mut paths: Query<&mut Path>, mut transforms: Query<&mut Transform>, ) { 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(&mut paths, &transforms, sd, mouse_pos); if mouse.just_released(MouseButton::Left) { let done = insert_edge_to_shape_creation(&mut coms, sd, mouse_pos, p_size.0); if done { let center = add_center_point(&mut coms, sd, &transforms, mouse_pos, p_size.0); // Update each point to be relative to the new center! if let Ok(mut t) = transforms.get_mut(sd.main_shape) { t.translation = center.extend(0.0); } if let Ok(mut t) = transforms.get_mut(sd.center.unwrap()) { t.translation = Vec3::new(0.0, 0.0, 1.0); // Just to make sure the center is centered } for edge in sd.edges.iter() { if let Ok(mut t) = transforms.get_mut(*edge) { t.translation -= center.extend(0.0); } else { // If we dont have a transform in the query for the relevant entity, // then it should be the entity we just inserted, and we can just override its transform coms.entity(*edge) .insert(Transform::from_translation((mouse_pos - center).extend(1.0))); } } finalize_shape_redraw(&mut paths, &transforms, sd, mouse_pos - center); let mut ms = coms.entity(sd.main_shape); ms.add_child(sd.center.unwrap()); for e in sd.edges.iter() { ms.add_child(*e); } 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, p_size.0)); } } } /// lpos - should be in local coordinates! fn finalize_shape_redraw( paths: &mut Query<&mut Path>, transforms: &Query<&mut Transform>, sd: &ShapeData, lpos: Vec2, // Last position(1 we just inserted) ) { let path = match sd.shape { CreateShape::Triangle => { assert!(sd.edges.len() == 3); let fp = transforms.get(sd.edges[0]).unwrap().translation.xy(); let sp = transforms.get(sd.edges[1]).unwrap().translation.xy(); let shape = shapes::Polygon { points: Vec::from([fp, sp, lpos]), closed: true, }; ShapePath::build_as(&shape) }, CreateShape::Square => { assert!(sd.edges.len() == 2); let opposite_point = transforms.get(sd.edges[0]).unwrap().translation.xy(); let ext = (lpos - opposite_point).abs(); let shape = shapes::Rectangle { extents: ext, origin: RectangleOrigin::Center }; ShapePath::build_as(&shape) }, CreateShape::Circle => { assert!(sd.center.is_some()); let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy(); let shape = shapes::Circle { radius: (lpos - center).length(), center: Vec2::ZERO }; 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; } } /// Adds a center point to the shape, returning the center location(due to commands not being run until end of frame) fn add_center_point( coms: &mut Commands, sd: &mut ShapeData, transforms: &Query<&mut Transform>, l_pos: Vec2, // We call this function before commands are executed, so we dont have the last entity YET! p_size: f32, ) -> Vec2 { if sd.center.is_some() { return transforms.get(sd.center.unwrap()).unwrap().translation.xy(); } let center = match sd.shape { CreateShape::Triangle => { assert!(sd.edges.len() == 3); let fp = transforms.get(sd.edges[0]).unwrap().translation.xy(); let sp = transforms.get(sd.edges[1]).unwrap().translation.xy(); (fp + sp + l_pos) / 3.0 }, CreateShape::Square => { assert!(sd.edges.len() == 2); let e1 = transforms.get(sd.edges[0]).unwrap().translation.xy(); (e1 + l_pos) * 0.5 }, _ => panic!("Should not be reachable, as circle has a center and capsule is disabled for now!"), }; let shape = shapes::Circle { radius: p_size, center: Vec2::ZERO, }; 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)) )) .id(); sd.center = Some(np); center } /// Inserts a new edge/point to the currently created shape, return if the shape is complete fn insert_edge_to_shape_creation( coms: &mut Commands, sd: &mut ShapeData, mpos: Vec2, p_size: f32, ) -> bool { // Spawn the new point // Spawn the first point(where the user just clicked) let shape = shapes::Circle { radius: p_size, center: Vec2::ZERO, }; let np = coms.spawn_bundle(GeometryBuilder::build_as( &shape, DrawMode::Fill(FillMode::color(Color::RED)), Transform::from_translation(mpos.extend(1.0)) )) .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::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( paths: &mut Query<&mut Path>, transforms: &Query<&mut Transform>, sd: &ShapeData, mpos: Vec2, ) { let path = match sd.shape { CreateShape::Triangle => { if sd.edges.len() == 1 { let first_point = transforms.get(sd.edges[0]).unwrap().translation.xy(); let shape = shapes::Line(first_point, mpos); ShapePath::build_as(&shape) } else if sd.edges.len() == 2 { let fp = transforms.get(sd.edges[0]).unwrap().translation.xy(); let sp = transforms.get(sd.edges[1]).unwrap().translation.xy(); 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 = transforms.get(sd.edges[0]).unwrap().translation.xy(); 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::Circle => { assert!(sd.center.is_some()); let center= transforms.get(sd.center.unwrap()).unwrap().translation.xy(); 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, p_size: f32) -> 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: p_size, center: Vec2::ZERO, }; let fp = coms.spawn_bundle(GeometryBuilder::build_as( &shape, DrawMode::Fill(FillMode::color(Color::RED)), Transform::from_translation(pos.extend(1.0)) )) .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 => { 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::Circle => Some(fp), _ => None, }; let edges = if center.is_none() { Vec::from([fp]) } else { Vec::new() }; ShapeData { shape: create_shape, main_shape, edges, center } }