custom picking for map
This commit is contained in:
parent
bc621ff9c1
commit
62dd037957
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -338,9 +338,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bevy-inspector-egui"
|
||||
version = "0.28.0"
|
||||
version = "0.28.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd64580f4496ed987c6231c6a7d833068914331a9084bf5a3dd9dcbc66fd8a73"
|
||||
checksum = "36172627eb6fd8586600972bcbba2880ed6f59e4e243dcf2ed7ff68d987577ce"
|
||||
dependencies = [
|
||||
"bevy-inspector-egui-derive",
|
||||
"bevy_app",
|
||||
@ -2402,7 +2402,7 @@ dependencies = [
|
||||
"vec_map",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
"windows 0.52.0",
|
||||
"windows 0.58.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -30,7 +30,7 @@ bevy = { version = "0.15", default-features = false, features = [
|
||||
"bevy_gltf",
|
||||
"bevy_mesh_picking_backend",
|
||||
"bevy_pbr",
|
||||
"bevy_picking",
|
||||
# "bevy_picking",
|
||||
"bevy_render",
|
||||
"bevy_scene",
|
||||
"bevy_sprite",
|
||||
|
@ -1,4 +1,6 @@
|
||||
use bevy::{input::mouse::MouseWheel, math::NormedVectorSpace, picking::{focus::HoverMap, pointer::PointerId}, prelude::*, utils::{dbg, HashMap}, window::PrimaryWindow};
|
||||
use std::time::Duration;
|
||||
|
||||
use bevy::{input::mouse::MouseWheel, math::NormedVectorSpace, picking::{focus::HoverMap, pointer::PointerId}, prelude::*, utils::HashMap, window::PrimaryWindow};
|
||||
|
||||
use crate::ui;
|
||||
|
||||
@ -20,7 +22,7 @@ fn setup(mut cmds: Commands, window: Query<&Window>) {
|
||||
}
|
||||
|
||||
#[derive(Resource, Default)]
|
||||
struct Pointers(HashMap<PointerId, Vec2>);
|
||||
struct Pointers(HashMap<PointerId, (Vec2, Option<Duration>)>);
|
||||
|
||||
fn move_cam(
|
||||
mut cam: Query<&mut Transform, With<Camera2d>>,
|
||||
@ -30,18 +32,24 @@ fn move_cam(
|
||||
touches: Res<Touches>,
|
||||
window: Query<&Window, With<PrimaryWindow>>,
|
||||
mut pointers: ResMut<Pointers>,
|
||||
hover_map: Res<HoverMap>
|
||||
hover_map: Res<HoverMap>,
|
||||
time: Res<Time>
|
||||
) {
|
||||
let window = window.single();
|
||||
let mut cam = cam.single_mut();
|
||||
let map_ui_entity = map_ui_entity.single();
|
||||
let ps = hover_map.iter().filter_map(|(id, hit_map)| match id {
|
||||
PointerId::Mouse => window.cursor_position().map(|p| (mouse_buttons.pressed(MouseButton::Left), p, pointers.0.get(id).map(|p| *p).unwrap_or(p))),
|
||||
PointerId::Touch(i) => touches.get_pressed(*i).map(|t| (true, t.position(), t.previous_position())),
|
||||
PointerId::Mouse => window.cursor_position().map(|p|
|
||||
match pointers.0.get(id) {
|
||||
Some(p_cache) => (p_cache.1.filter(|_| mouse_buttons.pressed(MouseButton::Left)), p, p_cache.0),
|
||||
None => (None, p, p)
|
||||
}
|
||||
),
|
||||
PointerId::Touch(i) => touches.get_pressed(*i).map(|t| (pointers.0.get(id).map(|(pos, start)| (*start).unwrap_or(time.elapsed())), t.position(), t.previous_position())),
|
||||
_ => None
|
||||
}.map(|(pressed,new_pos, old_pos)| (pressed,new_pos,old_pos,id,hit_map))
|
||||
}.map(|(pressed_start,new_pos, old_pos)| (pressed_start,new_pos,old_pos,id,hit_map))
|
||||
).collect::<Vec<_>>();
|
||||
let pressed_on_map = ps.iter().filter(|p| p.0 && p.4.contains_key(&map_ui_entity)).collect::<Vec<_>>();
|
||||
let pressed_on_map = ps.iter().filter(|p| p.0.is_some() && p.4.contains_key(&map_ui_entity)).collect::<Vec<_>>();
|
||||
|
||||
let old_midpoint = pressed_on_map.iter().fold(Vec2::ZERO, |acc, (_, _, old_pos, _, _)| {
|
||||
acc + (old_pos/pressed_on_map.len() as f32)
|
||||
@ -63,7 +71,6 @@ fn move_cam(
|
||||
acc + (new_midpoint-new_pos).norm()
|
||||
});
|
||||
let zoom = new_d_to_midpoint/old_d_to_midpoint;
|
||||
dbg!(zoom);
|
||||
cam.scale /= zoom;
|
||||
}
|
||||
|
||||
@ -71,11 +78,15 @@ fn move_cam(
|
||||
for ev in ev_scroll.read() {
|
||||
let scale = (cam.scale.x-(ev.y*0.1/window.width().min(window.height()))).clamp(0.0001, 2./window.width().min(window.height()));
|
||||
cam.scale = Vec3::new(scale, scale, scale);
|
||||
dbg!(cam.scale);
|
||||
}
|
||||
|
||||
// update cached pointer positions
|
||||
for (_, new_pos, _, id, _) in ps {
|
||||
pointers.0.insert(*id, new_pos);
|
||||
pointers.0.clear();
|
||||
for (pressed_start, new_pos, _, id, _) in ps {
|
||||
match id {
|
||||
PointerId::Mouse => {pointers.0.insert(*id, (new_pos, pressed_start));},
|
||||
PointerId::Touch(_) => {pointers.0.insert(*id, (new_pos, pressed_start));},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
25
src/map.rs
25
src/map.rs
@ -1,9 +1,11 @@
|
||||
use bevy::{asset::RenderAssetUsages, prelude::*, render::mesh::{Indices, PrimitiveTopology}};
|
||||
use bevy::{asset::RenderAssetUsages, picking::PickSet, prelude::*, render::mesh::{Indices, PrimitiveTopology}, utils::HashMap};
|
||||
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use voronoice::{BoundingBox, Point, VoronoiBuilder};
|
||||
|
||||
mod cells;
|
||||
mod picking;
|
||||
use picking::*;
|
||||
use cells::*;
|
||||
|
||||
pub struct Plugin;
|
||||
@ -12,6 +14,7 @@ impl bevy::prelude::Plugin for Plugin {
|
||||
app.add_systems(Startup, setup)
|
||||
.insert_resource(Time::<Fixed>::from_seconds(0.25)) // Time for a day
|
||||
.add_systems(FixedUpdate, update_cells)
|
||||
.add_systems(PreUpdate, picking_backend.in_set(PickSet::Backend))
|
||||
.insert_resource(ClearColor(Color::srgb(0., 0., 1.)))
|
||||
.insert_resource(Seed(0));
|
||||
}
|
||||
@ -28,7 +31,7 @@ pub const SIZE: usize = 10000;
|
||||
struct Seed(u32);
|
||||
|
||||
#[derive(Component)]
|
||||
struct Voronoi (voronoice::Voronoi);
|
||||
pub struct Voronoi (voronoice::Voronoi);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct MapMarker;
|
||||
@ -36,6 +39,9 @@ pub struct MapMarker;
|
||||
#[derive(Component)]
|
||||
struct MapColors (Vec<[f32; 4]>);
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CellsEntities (Vec<Entity>);
|
||||
|
||||
fn setup(
|
||||
mut cmds: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
@ -118,6 +124,7 @@ fn setup(
|
||||
)
|
||||
.with_inserted_indices(Indices::U32(indices));
|
||||
|
||||
let mut cells_entities = Vec::with_capacity(cells_data.len());
|
||||
cmds.spawn((
|
||||
Mesh2d(meshes.add(mesh)),
|
||||
MeshMaterial2d(materials.add(ColorMaterial::default())),
|
||||
@ -127,12 +134,14 @@ fn setup(
|
||||
MapMarker
|
||||
)).with_children(|parent| {
|
||||
for cd in cells_data {
|
||||
match cd.kind {
|
||||
CellKind::Forest | CellKind::Grass => parent.spawn((cd, LastUpdate(0))),
|
||||
_ => parent.spawn(cd)
|
||||
};
|
||||
}
|
||||
let mut cmd = parent.spawn((cd, LastUpdate(0)));
|
||||
cmd.observe(|trigger: Trigger<Pointer<Drag>>, mut cells: Query<&mut CellData>| {
|
||||
cells.get_mut(trigger.target).unwrap().kind = CellKind::Sea;
|
||||
});
|
||||
cells_entities.push(cmd.id());
|
||||
}
|
||||
}).insert(CellsEntities(cells_entities));
|
||||
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
@ -156,11 +165,11 @@ fn update_cells(
|
||||
} {
|
||||
lu.0 = 0;
|
||||
cd.resource = (cd.resource + 1).clamp(0, 4);
|
||||
modified = true;
|
||||
}
|
||||
// cd.update();
|
||||
let col = cd.color();
|
||||
for id in cd.vertices.iter() {
|
||||
modified = modified || cols.0[*id] != col;
|
||||
cols.0[*id] = col.clone();
|
||||
}
|
||||
}
|
||||
|
38
src/map/picking.rs
Normal file
38
src/map/picking.rs
Normal file
@ -0,0 +1,38 @@
|
||||
use bevy::{picking::{backend::{HitData, PointerHits}, pointer::{PointerId, PointerLocation}}, prelude::*, window::PrimaryWindow};
|
||||
use voronoice::Point;
|
||||
|
||||
use super::{CellsEntities, MapMarker, Voronoi};
|
||||
|
||||
pub fn picking_backend(
|
||||
cam: Query<(&Transform, Entity), With<Camera2d>>,
|
||||
window: Query<&Window, With<PrimaryWindow>>,
|
||||
pointers: Query<(&PointerId, &PointerLocation)>,
|
||||
map: Query<(&Voronoi, &CellsEntities, &Transform), With<MapMarker>>,
|
||||
mut output: EventWriter<PointerHits>
|
||||
) {
|
||||
let (cam, cam_id) = cam.single();
|
||||
let window = window.single();
|
||||
let (voronoi, cells_entities, map_pos) = map.single();
|
||||
let mut last_cell = 0;
|
||||
for (id, l) in pointers.iter() {
|
||||
if let Some(mut pos) = l.location().map(|l| l.position) {
|
||||
pos -= window.size()/2.;
|
||||
pos *= cam.scale.xy();
|
||||
pos -= cam.translation.xy();
|
||||
if let Some(c) = voronoi.0.cell(last_cell).iter_path(Point { x: pos.x as f64, y: -pos.y as f64 }).last() {
|
||||
last_cell = c;
|
||||
output.send(PointerHits {
|
||||
pointer: *id,
|
||||
picks: vec![(cells_entities.0[c], HitData {
|
||||
camera: cam_id,
|
||||
depth: map_pos.translation.z,
|
||||
position: Some(Vec3 { x: pos.x, y: pos.y, z: map_pos.translation.z }),
|
||||
normal: None
|
||||
})],
|
||||
order: map_pos.translation.z
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
27
src/ui.rs
27
src/ui.rs
@ -1,5 +1,7 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::map::{self, MapMarker};
|
||||
|
||||
pub struct Plugin;
|
||||
impl bevy::prelude::Plugin for Plugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
@ -14,14 +16,21 @@ fn setup(
|
||||
mut cmds: Commands
|
||||
) {
|
||||
cmds.spawn((
|
||||
Node {
|
||||
width: Val::Percent(100.0),
|
||||
height: Val::Percent(100.0),
|
||||
align_items: AlignItems::Center,
|
||||
justify_content: JustifyContent::Center,
|
||||
..default()
|
||||
},
|
||||
MapUIComponent
|
||||
));
|
||||
// Node {
|
||||
// width: Val::Percent(100.0),
|
||||
// height: Val::Percent(100.0),
|
||||
// align_items: AlignItems::Center,
|
||||
// justify_content: JustifyContent::Center,
|
||||
// ..default()
|
||||
// },
|
||||
MapUIComponent));
|
||||
// )).observe(|mut trigger: Trigger<Pointer<Click>>, map: Query<(&map::Voronoi, &map::CellsEntities), With<MapMarker>>| {
|
||||
// let event = trigger.event();
|
||||
// // dbg!(event);
|
||||
// if event.button == PointerButton::Primary {
|
||||
// let pos = event.pointer_location.position;
|
||||
// }
|
||||
// trigger.propagate(false);
|
||||
// });
|
||||
// Spawn all ui elements as children of this one
|
||||
}
|
Loading…
Reference in New Issue
Block a user