Draw dots on click
This commit is contained in:
parent
fab857d6ae
commit
49c3a1517d
4 changed files with 206 additions and 1 deletions
|
@ -6,3 +6,5 @@ edition = "2021"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bevy = "0.10.1"
|
||||
bevy_egui = "0.20.3"
|
||||
|
|
8
src/global_state.rs
Normal file
8
src/global_state.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Resource, Default, Debug, PartialEq, Clone, Copy)]
|
||||
pub struct GlobalState {
|
||||
pub cursor_position: Vec2,
|
||||
pub window_extent: Vec2,
|
||||
pub polygon_started: bool,
|
||||
}
|
134
src/main.rs
134
src/main.rs
|
@ -1,3 +1,135 @@
|
|||
mod global_state;
|
||||
mod polygon;
|
||||
|
||||
///! This example illustrates how to resize windows, and how to respond to a window being resized.
|
||||
use bevy::{
|
||||
input::{
|
||||
mouse::{MouseButtonInput, MouseWheel},
|
||||
ButtonState,
|
||||
},
|
||||
prelude::*,
|
||||
sprite::MaterialMesh2dBundle,
|
||||
window::WindowResized,
|
||||
};
|
||||
|
||||
use bevy_egui::{egui, EguiContexts, EguiPlugin};
|
||||
use global_state::GlobalState;
|
||||
use polygon::ObjectInfos;
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_plugin(EguiPlugin)
|
||||
.insert_resource(GlobalState::default())
|
||||
.insert_resource(ObjectInfos::default())
|
||||
.add_startup_systems((setup_camera, setup))
|
||||
.add_systems((
|
||||
print_mouse_events_system,
|
||||
update_ui_side_panel,
|
||||
on_resize_system,
|
||||
))
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
commands.spawn(MaterialMesh2dBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Quad::default())).into(),
|
||||
transform: Transform::default()
|
||||
.with_scale(Vec3::splat(4.))
|
||||
.with_translation(Vec3::new(100.0, 10.0, 0.0)),
|
||||
material: materials.add(ColorMaterial::from(Color::YELLOW)),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
// Spawns the camera that draws UI
|
||||
fn setup_camera(mut cmd: Commands) {
|
||||
cmd.spawn(Camera2dBundle::default());
|
||||
}
|
||||
|
||||
fn update_ui_side_panel(mut contexts: EguiContexts, mut global_state: ResMut<GlobalState>) {
|
||||
egui::Window::new("Hello").show(contexts.ctx_mut(), |ui| {
|
||||
if global_state.polygon_started {
|
||||
// TODO
|
||||
} else {
|
||||
if ui.button("New Polygon").clicked() {
|
||||
global_state.polygon_started = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// This system prints out all mouse events as they come in
|
||||
fn print_mouse_events_system(
|
||||
mut mouse_button_input_events: EventReader<MouseButtonInput>,
|
||||
mut cursor_moved_events: EventReader<CursorMoved>,
|
||||
mut mouse_wheel_events: EventReader<MouseWheel>,
|
||||
mut global_state: ResMut<GlobalState>,
|
||||
mut object_infos: ResMut<ObjectInfos>,
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||
) {
|
||||
for event in mouse_button_input_events.iter() {
|
||||
match event.button {
|
||||
MouseButton::Left => match event.state {
|
||||
ButtonState::Pressed => {
|
||||
println!(
|
||||
"Left mouse button pressed at {:?}",
|
||||
global_state.cursor_position
|
||||
);
|
||||
|
||||
let polygon = match object_infos.active_polygon() {
|
||||
Some(polygon) => polygon,
|
||||
None => object_infos.add_polygon(),
|
||||
};
|
||||
|
||||
if polygon.add_point(global_state.cursor_position) {
|
||||
global_state.polygon_started = false;
|
||||
|
||||
// TODO remove single points -> draw full polygon
|
||||
} else {
|
||||
commands.spawn(MaterialMesh2dBundle {
|
||||
mesh: meshes.add(Mesh::from(shape::Quad::default())).into(),
|
||||
transform: Transform::default()
|
||||
.with_scale(Vec3::splat(4.0))
|
||||
.with_translation(
|
||||
(global_state.cursor_position
|
||||
- (global_state.window_extent * 0.5))
|
||||
.extend(0.0),
|
||||
),
|
||||
material: materials.add(ColorMaterial::from(Color::BLACK)),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
}
|
||||
ButtonState::Released => (),
|
||||
},
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
// store latest mouse cursor location
|
||||
for event in cursor_moved_events.iter() {
|
||||
global_state.cursor_position = event.position;
|
||||
}
|
||||
|
||||
for _event in mouse_wheel_events.iter() {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
fn on_resize_system(
|
||||
mut resize_reader: EventReader<WindowResized>,
|
||||
mut global_state: ResMut<GlobalState>,
|
||||
) {
|
||||
for e in resize_reader.iter() {
|
||||
// When resolution is being changed
|
||||
global_state.window_extent = Vec2::new(e.width, e.height);
|
||||
}
|
||||
}
|
||||
|
|
63
src/polygon.rs
Normal file
63
src/polygon.rs
Normal file
|
@ -0,0 +1,63 @@
|
|||
use bevy::prelude::*;
|
||||
|
||||
#[derive(Default, Debug, PartialEq)]
|
||||
pub struct Polygon {
|
||||
points: Vec<Vec2>,
|
||||
finished: bool,
|
||||
}
|
||||
|
||||
impl Polygon {
|
||||
const PROXIMITY_THRESHOLD: f32 = 5.0;
|
||||
|
||||
pub fn add_point(&mut self, point: Vec2) -> bool {
|
||||
debug_assert_eq!(self.finished, false);
|
||||
|
||||
// polygon must be at least an triangle
|
||||
// and check if we can close up the polygon
|
||||
if self.points.len() >= 3 && self.check_first_for_proximity(point) {
|
||||
self.points.push(point);
|
||||
self.finished = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// deny too close points
|
||||
if !self.check_all_for_proximity(point) {
|
||||
self.points.push(point);
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn finished(&self) -> bool {
|
||||
self.finished
|
||||
}
|
||||
|
||||
fn check_all_for_proximity(&self, point: Vec2) -> bool {
|
||||
self.points
|
||||
.iter()
|
||||
.any(|p| p.distance(point) < Self::PROXIMITY_THRESHOLD)
|
||||
}
|
||||
|
||||
fn check_first_for_proximity(&self, point: Vec2) -> bool {
|
||||
debug_assert!(!self.points.is_empty());
|
||||
|
||||
self.points.first().unwrap().distance(point) < Self::PROXIMITY_THRESHOLD
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default, Debug, PartialEq)]
|
||||
pub struct ObjectInfos {
|
||||
polygons: Vec<Polygon>,
|
||||
}
|
||||
|
||||
impl ObjectInfos {
|
||||
pub fn active_polygon(&mut self) -> Option<&mut Polygon> {
|
||||
self.polygons.iter_mut().find(|polygon| !polygon.finished())
|
||||
}
|
||||
|
||||
pub fn add_polygon(&mut self) -> &mut Polygon {
|
||||
self.polygons.push(Polygon::default());
|
||||
self.polygons.last_mut().unwrap()
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue