fmt + move cell::on_click into its own function
This commit is contained in:
parent
dbb17f0c48
commit
d210af93f8
@ -2,9 +2,7 @@ use bevy::prelude::*;
|
|||||||
|
|
||||||
pub struct Plugin;
|
pub struct Plugin;
|
||||||
impl bevy::prelude::Plugin for Plugin {
|
impl bevy::prelude::Plugin for Plugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Copy)]
|
#[derive(PartialEq, Eq, Clone, Copy)]
|
||||||
@ -14,5 +12,5 @@ pub enum AnimalKind {
|
|||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Animal {
|
pub struct Animal {
|
||||||
kind: AnimalKind
|
kind: AnimalKind,
|
||||||
}
|
}
|
||||||
|
122
src/camera.rs
122
src/camera.rs
@ -1,6 +1,13 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy::{input::mouse::MouseWheel, math::NormedVectorSpace, picking::{focus::HoverMap, pointer::PointerId}, prelude::*, utils::HashMap, window::PrimaryWindow};
|
use bevy::{
|
||||||
|
input::mouse::MouseWheel,
|
||||||
|
math::NormedVectorSpace,
|
||||||
|
picking::{focus::HoverMap, pointer::PointerId},
|
||||||
|
prelude::*,
|
||||||
|
utils::HashMap,
|
||||||
|
window::PrimaryWindow,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::ui;
|
use crate::ui;
|
||||||
|
|
||||||
@ -8,17 +15,14 @@ pub struct Plugin;
|
|||||||
impl bevy::prelude::Plugin for Plugin {
|
impl bevy::prelude::Plugin for Plugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Startup, setup);
|
app.add_systems(Startup, setup);
|
||||||
// .add_systems(Update, move_cam)
|
// .add_systems(Update, move_cam)
|
||||||
// .init_resource::<Pointers>();
|
// .init_resource::<Pointers>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup(mut cmds: Commands, window: Query<&Window>) {
|
fn setup(mut cmds: Commands, window: Query<&Window>) {
|
||||||
let zoom = 2./window.single().width().min(window.single().height());
|
let zoom = 2. / window.single().width().min(window.single().height());
|
||||||
cmds.spawn((
|
cmds.spawn((Camera2d, Transform::from_scale(Vec3::new(zoom, zoom, zoom))));
|
||||||
Camera2d,
|
|
||||||
Transform::from_scale(Vec3::new(zoom, zoom, zoom))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
@ -33,50 +37,80 @@ fn move_cam(
|
|||||||
window: Query<&Window, With<PrimaryWindow>>,
|
window: Query<&Window, With<PrimaryWindow>>,
|
||||||
mut pointers: ResMut<Pointers>,
|
mut pointers: ResMut<Pointers>,
|
||||||
hover_map: Res<HoverMap>,
|
hover_map: Res<HoverMap>,
|
||||||
time: Res<Time>
|
time: Res<Time>,
|
||||||
) {
|
) {
|
||||||
let window = window.single();
|
let window = window.single();
|
||||||
let mut cam = cam.single_mut();
|
let mut cam = cam.single_mut();
|
||||||
let map_ui_entity = map_ui_entity.single();
|
let map_ui_entity = map_ui_entity.single();
|
||||||
let ps = hover_map.iter().filter_map(|(id, hit_map)| match id {
|
let ps = hover_map
|
||||||
PointerId::Mouse => window.cursor_position().map(|p|
|
.iter()
|
||||||
match pointers.0.get(id) {
|
.filter_map(|(id, hit_map)| {
|
||||||
Some(p_cache) => (p_cache.1.filter(|_| mouse_buttons.pressed(MouseButton::Left)), p, p_cache.0),
|
match id {
|
||||||
None => (None, p, p)
|
PointerId::Mouse => window.cursor_position().map(|p| match pointers.0.get(id) {
|
||||||
}
|
Some(p_cache) => (
|
||||||
),
|
p_cache
|
||||||
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())),
|
.1
|
||||||
_ => None
|
.filter(|_| mouse_buttons.pressed(MouseButton::Left)),
|
||||||
}.map(|(pressed_start,new_pos, old_pos)| (pressed_start,new_pos,old_pos,id,hit_map))
|
p,
|
||||||
).collect::<Vec<_>>();
|
p_cache.0,
|
||||||
let pressed_on_map = ps.iter().filter(|p| p.0.is_some() && p.4.contains_key(&map_ui_entity)).collect::<Vec<_>>();
|
),
|
||||||
|
None => (None, p, p),
|
||||||
let old_midpoint = pressed_on_map.iter().fold(Vec2::ZERO, |acc, (_, _, old_pos, _, _)| {
|
}),
|
||||||
acc + (old_pos/pressed_on_map.len() as f32)
|
PointerId::Touch(i) => touches.get_pressed(*i).map(|t| {
|
||||||
});
|
(
|
||||||
let new_midpoint = pressed_on_map.iter().fold(Vec2::ZERO, |acc, (_, new_pos, _, _, _)| {
|
pointers
|
||||||
acc + (new_pos/pressed_on_map.len() as f32)
|
.0
|
||||||
});
|
.get(id)
|
||||||
|
.map(|(pos, start)| (*start).unwrap_or(time.elapsed())),
|
||||||
|
t.position(),
|
||||||
|
t.previous_position(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
.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.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)
|
||||||
|
});
|
||||||
|
let new_midpoint = pressed_on_map
|
||||||
|
.iter()
|
||||||
|
.fold(Vec2::ZERO, |acc, (_, new_pos, _, _, _)| {
|
||||||
|
acc + (new_pos / pressed_on_map.len() as f32)
|
||||||
|
});
|
||||||
|
|
||||||
// move camera
|
// move camera
|
||||||
cam.translation.x -= (new_midpoint.x - old_midpoint.x)*cam.scale.x;
|
cam.translation.x -= (new_midpoint.x - old_midpoint.x) * cam.scale.x;
|
||||||
cam.translation.y += (new_midpoint.y - old_midpoint.y)*cam.scale.y;
|
cam.translation.y += (new_midpoint.y - old_midpoint.y) * cam.scale.y;
|
||||||
|
|
||||||
// multiple fingers zoom
|
// multiple fingers zoom
|
||||||
if pressed_on_map.len() > 1 {
|
if pressed_on_map.len() > 1 {
|
||||||
let old_d_to_midpoint = pressed_on_map.iter().fold(0., |acc, (_, _, old_pos, _, _)| {
|
let old_d_to_midpoint = pressed_on_map
|
||||||
acc + (old_midpoint-old_pos).norm()
|
.iter()
|
||||||
});
|
.fold(0., |acc, (_, _, old_pos, _, _)| {
|
||||||
let new_d_to_midpoint = pressed_on_map.iter().fold(0., |acc, (_, new_pos, _, _, _)| {
|
acc + (old_midpoint - old_pos).norm()
|
||||||
acc + (new_midpoint-new_pos).norm()
|
});
|
||||||
});
|
let new_d_to_midpoint = pressed_on_map
|
||||||
let zoom = new_d_to_midpoint/old_d_to_midpoint;
|
.iter()
|
||||||
|
.fold(0., |acc, (_, new_pos, _, _, _)| {
|
||||||
|
acc + (new_midpoint - new_pos).norm()
|
||||||
|
});
|
||||||
|
let zoom = new_d_to_midpoint / old_d_to_midpoint;
|
||||||
cam.scale /= zoom;
|
cam.scale /= zoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
// mouse scroll zoom
|
// mouse scroll zoom
|
||||||
for ev in ev_scroll.read() {
|
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()));
|
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);
|
cam.scale = Vec3::new(scale, scale, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +118,13 @@ fn move_cam(
|
|||||||
pointers.0.clear();
|
pointers.0.clear();
|
||||||
for (pressed_start, new_pos, _, id, _) in ps {
|
for (pressed_start, new_pos, _, id, _) in ps {
|
||||||
match id {
|
match id {
|
||||||
PointerId::Mouse => {pointers.0.insert(*id, (new_pos, pressed_start));},
|
PointerId::Mouse => {
|
||||||
PointerId::Touch(_) => {pointers.0.insert(*id, (new_pos, pressed_start));},
|
pointers.0.insert(*id, (new_pos, pressed_start));
|
||||||
|
}
|
||||||
|
PointerId::Touch(_) => {
|
||||||
|
pointers.0.insert(*id, (new_pos, pressed_start));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/lib.rs
17
src/lib.rs
@ -1,12 +1,15 @@
|
|||||||
#![feature(duration_constructors)]
|
#![feature(duration_constructors)]
|
||||||
use bevy::{prelude::*, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}};
|
use bevy::{
|
||||||
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
||||||
|
prelude::*,
|
||||||
|
};
|
||||||
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
use bevy_inspector_egui::quick::WorldInspectorPlugin;
|
||||||
|
|
||||||
pub mod map;
|
|
||||||
pub mod camera;
|
|
||||||
pub mod ui;
|
|
||||||
pub mod time;
|
|
||||||
pub mod animals;
|
pub mod animals;
|
||||||
|
pub mod camera;
|
||||||
|
pub mod map;
|
||||||
|
pub mod time;
|
||||||
|
pub mod ui;
|
||||||
|
|
||||||
#[bevy_main]
|
#[bevy_main]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
@ -23,7 +26,7 @@ pub fn main() {
|
|||||||
LogDiagnosticsPlugin {
|
LogDiagnosticsPlugin {
|
||||||
filter: Some(vec![FrameTimeDiagnosticsPlugin::FPS]),
|
filter: Some(vec![FrameTimeDiagnosticsPlugin::FPS]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
},
|
||||||
))
|
))
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
148
src/map.rs
148
src/map.rs
@ -1,15 +1,20 @@
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use bevy::{asset::RenderAssetUsages, picking::PickSet, prelude::*, render::mesh::{Indices, PrimitiveTopology}};
|
use bevy::{
|
||||||
|
asset::RenderAssetUsages,
|
||||||
|
picking::PickSet,
|
||||||
|
prelude::*,
|
||||||
|
render::mesh::{Indices, PrimitiveTopology},
|
||||||
|
};
|
||||||
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
|
||||||
use rand::{thread_rng, Rng, SeedableRng};
|
use rand::{thread_rng, Rng, SeedableRng};
|
||||||
use voronoice::{BoundingBox, Point, VoronoiBuilder};
|
use voronoice::{BoundingBox, Point, VoronoiBuilder};
|
||||||
|
|
||||||
mod cells;
|
mod cells;
|
||||||
mod picking;
|
mod picking;
|
||||||
use picking::*;
|
|
||||||
use cells::*;
|
|
||||||
pub use cells::CellKind;
|
pub use cells::CellKind;
|
||||||
|
use cells::*;
|
||||||
|
use picking::*;
|
||||||
|
|
||||||
use crate::{time::GameTime, ui::CurrentAction};
|
use crate::{time::GameTime, ui::CurrentAction};
|
||||||
|
|
||||||
@ -35,16 +40,16 @@ pub const SIZE: usize = 10000;
|
|||||||
struct Seed(u32);
|
struct Seed(u32);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct Voronoi (voronoice::Voronoi);
|
pub struct Voronoi(voronoice::Voronoi);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct MapMarker;
|
pub struct MapMarker;
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
struct MapColors (Vec<[f32; 4]>);
|
struct MapColors(Vec<[f32; 4]>);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct CellsEntities (Vec<Entity>);
|
pub struct CellsEntities(Vec<Entity>);
|
||||||
|
|
||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct MeshNeedsUpdate(bool);
|
pub struct MeshNeedsUpdate(bool);
|
||||||
@ -53,12 +58,15 @@ fn setup(
|
|||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
mut meshes: ResMut<Assets<Mesh>>,
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
mut materials: ResMut<Assets<ColorMaterial>>,
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
||||||
seed: Res<Seed>
|
seed: Res<Seed>,
|
||||||
) {
|
) {
|
||||||
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed.0 as u64);
|
let mut rng = rand::rngs::SmallRng::seed_from_u64(seed.0 as u64);
|
||||||
let mut sites = Vec::with_capacity(SIZE);
|
let mut sites = Vec::with_capacity(SIZE);
|
||||||
for _ in 0..SIZE {
|
for _ in 0..SIZE {
|
||||||
sites.push(Point { x:rng.gen_range(-WIDTH/2.0..WIDTH/2.0) as f64, y:rng.gen_range(-HEIGHT/2.0..HEIGHT/2.0) as f64 })
|
sites.push(Point {
|
||||||
|
x: rng.gen_range(-WIDTH / 2.0..WIDTH / 2.0) as f64,
|
||||||
|
y: rng.gen_range(-HEIGHT / 2.0..HEIGHT / 2.0) as f64,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
let voronoi = VoronoiBuilder::default()
|
let voronoi = VoronoiBuilder::default()
|
||||||
.set_sites(sites)
|
.set_sites(sites)
|
||||||
@ -68,19 +76,22 @@ fn setup(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let mut cells = Vec::with_capacity(SIZE);
|
let mut cells = Vec::with_capacity(SIZE);
|
||||||
let z_noise = Fbm::<Perlin>::new(seed.0);
|
let z_noise = Fbm::<Perlin>::new(seed.0);
|
||||||
let moisture_noise = Fbm::<Perlin>::new(seed.0+1)
|
let moisture_noise = Fbm::<Perlin>::new(seed.0 + 1).set_frequency(2.);
|
||||||
.set_frequency(2.);
|
|
||||||
for i in 0..SIZE {
|
for i in 0..SIZE {
|
||||||
let c = voronoi.cell(i);
|
let c = voronoi.cell(i);
|
||||||
let site = c.site_position();
|
let site = c.site_position();
|
||||||
let z = (
|
let z = (
|
||||||
0.3 // Arbitrary value
|
0.3 // Arbitrary value
|
||||||
+ ((z_noise.get([site.x, site.y])+1.)/2.) // Noise + [0; 1]
|
+ ((z_noise.get([site.x, site.y])+1.)/2.) // Noise + [0; 1]
|
||||||
- ((site.x.powi(2)+site.y.powi(2)).sqrt()*0.5) // Distance - [0; sqrt(2)] * 0.5
|
- ((site.x.powi(2)+site.y.powi(2)).sqrt()*0.5)
|
||||||
).clamp(0., 1.);
|
// Distance - [0; sqrt(2)] * 0.5
|
||||||
|
)
|
||||||
|
.clamp(0., 1.);
|
||||||
let m = (
|
let m = (
|
||||||
(moisture_noise.get([site.x, site.y])+1.)/2. // Noise + [0; 1]
|
(moisture_noise.get([site.x, site.y]) + 1.) / 2.
|
||||||
).clamp(0., 1.) as f32;
|
// Noise + [0; 1]
|
||||||
|
)
|
||||||
|
.clamp(0., 1.) as f32;
|
||||||
let k = if z <= 0.5 {
|
let k = if z <= 0.5 {
|
||||||
CellKind::Sea
|
CellKind::Sea
|
||||||
} else if z <= 0.52 {
|
} else if z <= 0.52 {
|
||||||
@ -93,40 +104,40 @@ fn setup(
|
|||||||
cells.push(Cell {
|
cells.push(Cell {
|
||||||
kind: k,
|
kind: k,
|
||||||
voronoi_id: i,
|
voronoi_id: i,
|
||||||
altitude: (z*255.) as u8,
|
altitude: (z * 255.) as u8,
|
||||||
vertices: vec![]
|
vertices: vec![],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut poss = Vec::new();
|
let mut poss = Vec::new();
|
||||||
let mut indices = Vec::new();
|
let mut indices = Vec::new();
|
||||||
|
|
||||||
for (c, cd) in voronoi.iter_cells().zip(cells.iter_mut()).filter(|(_,cd)| cd.kind != CellKind::Forest) {
|
for (c, cd) in voronoi
|
||||||
|
.iter_cells()
|
||||||
|
.zip(cells.iter_mut())
|
||||||
|
.filter(|(_, cd)| cd.kind != CellKind::Forest)
|
||||||
|
{
|
||||||
let vs = c.iter_vertices().collect::<Vec<_>>();
|
let vs = c.iter_vertices().collect::<Vec<_>>();
|
||||||
let i = poss.len();
|
let i = poss.len();
|
||||||
for v in vs.iter() {
|
for v in vs.iter() {
|
||||||
poss.push(Vec3::new(v.x as f32, v.y as f32, 0.));
|
poss.push(Vec3::new(v.x as f32, v.y as f32, 0.));
|
||||||
}
|
}
|
||||||
for v in 1..(vs.len()-1) {
|
for v in 1..(vs.len() - 1) {
|
||||||
indices.extend_from_slice(&[i as u32, (i+v) as u32, (i+v+1) as u32]);
|
indices.extend_from_slice(&[i as u32, (i + v) as u32, (i + v + 1) as u32]);
|
||||||
cd.vertices.extend_from_slice(&[i, i+v, i+v+1]);
|
cd.vertices.extend_from_slice(&[i, i + v, i + v + 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let colors = vec![[0.; 4]; poss.len()];
|
let colors = vec![[0.; 4]; poss.len()];
|
||||||
let mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::default())
|
let mesh = Mesh::new(
|
||||||
// Add 4 vertices, each with its own position attribute (coordinate in
|
PrimitiveTopology::TriangleList,
|
||||||
// 3D space), for each of the corners of the parallelogram.
|
RenderAssetUsages::default(),
|
||||||
.with_inserted_attribute(
|
)
|
||||||
Mesh::ATTRIBUTE_POSITION,
|
// Add 4 vertices, each with its own position attribute (coordinate in
|
||||||
poss
|
// 3D space), for each of the corners of the parallelogram.
|
||||||
)
|
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, poss)
|
||||||
.with_inserted_attribute(
|
.with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone())
|
||||||
Mesh::ATTRIBUTE_COLOR,
|
.with_inserted_indices(Indices::U32(indices));
|
||||||
colors.clone()
|
|
||||||
)
|
|
||||||
.with_inserted_indices(Indices::U32(indices));
|
|
||||||
|
|
||||||
let mut cells_entities = Vec::with_capacity(cells.len());
|
let mut cells_entities = Vec::with_capacity(cells.len());
|
||||||
cmds.spawn((
|
cmds.spawn((
|
||||||
@ -136,74 +147,35 @@ fn setup(
|
|||||||
Voronoi(voronoi),
|
Voronoi(voronoi),
|
||||||
MapColors(colors),
|
MapColors(colors),
|
||||||
MeshNeedsUpdate(true),
|
MeshNeedsUpdate(true),
|
||||||
MapMarker
|
MapMarker,
|
||||||
)).with_children(|parent| {
|
))
|
||||||
|
.with_children(|parent| {
|
||||||
for cell in cells {
|
for cell in cells {
|
||||||
let kind = cell.kind;
|
let kind = cell.kind;
|
||||||
let mut cmd = parent.spawn(cell);
|
let mut cmd = parent.spawn(cell);
|
||||||
match kind {
|
match kind {
|
||||||
CellKind::Grass | CellKind::Forest => {
|
CellKind::Grass | CellKind::Forest => {
|
||||||
cmd.insert((Wealth(0), Regeneration {
|
cmd.insert((
|
||||||
last_update: Duration::ZERO,
|
Wealth(0),
|
||||||
full_growth_duration: kind.regen_full_growth_duration()
|
Regeneration {
|
||||||
}));
|
last_update: Duration::ZERO,
|
||||||
},
|
full_growth_duration: kind.regen_full_growth_duration(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
cmd.observe(|
|
cmd.observe(self::cells::on_click);
|
||||||
trigger: Trigger<Pointer<Click>>,
|
|
||||||
mut cells: Query<&mut Cell>,
|
|
||||||
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
|
||||||
mut cmds: Commands,
|
|
||||||
ca: Res<CurrentAction>,
|
|
||||||
gt: Res<GameTime>,
|
|
||||||
| {
|
|
||||||
if trigger.duration > Duration::from_millis(200) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
match *ca {
|
|
||||||
CurrentAction::ChangeCell(ck) => {
|
|
||||||
let mut cell = cells.get_mut(trigger.target).unwrap();
|
|
||||||
match ck {
|
|
||||||
CellKind::Forest => match cell.kind {
|
|
||||||
CellKind::Dirt | CellKind::Grass => {
|
|
||||||
cmds.entity(trigger.target).insert((Wealth(0), Regeneration {
|
|
||||||
last_update: gt.current,
|
|
||||||
full_growth_duration: CellKind::Forest.regen_full_growth_duration()
|
|
||||||
}));
|
|
||||||
cell.kind = CellKind::Forest;
|
|
||||||
map_needs_update.single_mut().0 = true;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
},
|
|
||||||
CellKind::Grass => match cell.kind {
|
|
||||||
CellKind::Dirt => {
|
|
||||||
cmds.entity(trigger.target).insert((Wealth(0), Regeneration {
|
|
||||||
last_update: gt.current,
|
|
||||||
full_growth_duration: CellKind::Grass.regen_full_growth_duration()
|
|
||||||
}));
|
|
||||||
cell.kind = CellKind::Grass;
|
|
||||||
map_needs_update.single_mut().0 = true;
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
cells_entities.push(cmd.id());
|
cells_entities.push(cmd.id());
|
||||||
}
|
}
|
||||||
}).insert(CellsEntities(cells_entities));
|
})
|
||||||
|
.insert(CellsEntities(cells_entities));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_map_mesh(
|
fn update_map_mesh(
|
||||||
cells: Query<(&Cell, Option<&Wealth>)>,
|
cells: Query<(&Cell, Option<&Wealth>)>,
|
||||||
mut map: Query<(&Mesh2d, &mut MapColors, &mut MeshNeedsUpdate), With<MapMarker>>,
|
mut map: Query<(&Mesh2d, &mut MapColors, &mut MeshNeedsUpdate), With<MapMarker>>,
|
||||||
mut meshes: ResMut<Assets<Mesh>>
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
) {
|
) {
|
||||||
let (mesh, mut cols, mut needs_update) = map.single_mut();
|
let (mesh, mut cols, mut needs_update) = map.single_mut();
|
||||||
if needs_update.0 {
|
if needs_update.0 {
|
||||||
@ -222,4 +194,4 @@ fn update_map_mesh(
|
|||||||
}
|
}
|
||||||
needs_update.0 = false;
|
needs_update.0 = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
140
src/map/cells.rs
140
src/map/cells.rs
@ -14,14 +14,14 @@ pub enum CellKind {
|
|||||||
Forest,
|
Forest,
|
||||||
Dirt,
|
Dirt,
|
||||||
Stone,
|
Stone,
|
||||||
Grass
|
Grass,
|
||||||
}
|
}
|
||||||
impl CellKind {
|
impl CellKind {
|
||||||
pub fn regen_full_growth_duration(&self) -> Duration {
|
pub fn regen_full_growth_duration(&self) -> Duration {
|
||||||
match self {
|
match self {
|
||||||
CellKind::Sea | CellKind::Beach | CellKind::Dirt | CellKind::Stone => unreachable!(),
|
CellKind::Sea | CellKind::Beach | CellKind::Dirt | CellKind::Stone => unreachable!(),
|
||||||
CellKind::Forest => Duration::from_days(365*100), // Let's say that a forest takes 100 years to mature
|
CellKind::Forest => Duration::from_days(365 * 100), // Let's say that a forest takes 100 years to mature
|
||||||
CellKind::Grass => Duration::from_weeks(7) // Let's say that grass takes 7 weeks to reach its max
|
CellKind::Grass => Duration::from_weeks(7), // Let's say that grass takes 7 weeks to reach its max
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -31,17 +31,27 @@ pub struct Cell {
|
|||||||
pub kind: CellKind,
|
pub kind: CellKind,
|
||||||
pub voronoi_id: usize,
|
pub voronoi_id: usize,
|
||||||
pub altitude: u8,
|
pub altitude: u8,
|
||||||
pub vertices: Vec<usize>
|
pub vertices: Vec<usize>,
|
||||||
}
|
}
|
||||||
impl Cell {
|
impl Cell {
|
||||||
pub fn color(&self, wealth: u8) -> [f32; 4] {
|
pub fn color(&self, wealth: u8) -> [f32; 4] {
|
||||||
match self.kind {
|
match self.kind {
|
||||||
CellKind::Sea => [0., 0., 1., 1.],
|
CellKind::Sea => [0., 0., 1., 1.],
|
||||||
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
|
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
|
||||||
CellKind::Forest => [0., 0.5 - (wealth as f32/255.*0.4), 0., 1.],
|
CellKind::Forest => [0., 0.5 - (wealth as f32 / 255. * 0.4), 0., 1.],
|
||||||
CellKind::Dirt => [0.53 - (wealth as f32/255.*0.4), 0.38-(wealth as f32/255.*0.4), 0.29-(wealth as f32/255.*0.4), 1.],
|
CellKind::Dirt => [
|
||||||
|
0.53 - (wealth as f32 / 255. * 0.4),
|
||||||
|
0.38 - (wealth as f32 / 255. * 0.4),
|
||||||
|
0.29 - (wealth as f32 / 255. * 0.4),
|
||||||
|
1.,
|
||||||
|
],
|
||||||
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
|
CellKind::Stone => [0.5, 0.5, 0.5, 1.],
|
||||||
CellKind::Grass => [(136./255.) - (wealth as f32/255.*0.15), (154./255.) + (wealth as f32/255.*0.1), (59./255.) - (wealth as f32/255.*0.15), 1.]
|
CellKind::Grass => [
|
||||||
|
(136. / 255.) - (wealth as f32 / 255. * 0.15),
|
||||||
|
(154. / 255.) + (wealth as f32 / 255. * 0.1),
|
||||||
|
(59. / 255.) - (wealth as f32 / 255. * 0.15),
|
||||||
|
1.,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,17 +69,17 @@ impl Default for Wealth {
|
|||||||
#[require(Wealth)]
|
#[require(Wealth)]
|
||||||
pub struct Regeneration {
|
pub struct Regeneration {
|
||||||
pub last_update: Duration,
|
pub last_update: Duration,
|
||||||
pub full_growth_duration: Duration
|
pub full_growth_duration: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cells_regeneration(
|
pub fn cells_regeneration(
|
||||||
mut cells: Query<(&mut Regeneration, &mut Wealth)>,
|
mut cells: Query<(&mut Regeneration, &mut Wealth)>,
|
||||||
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
||||||
gt: Res<GameTime>
|
gt: Res<GameTime>,
|
||||||
) {
|
) {
|
||||||
let mut map_needs_update = map_needs_update.single_mut();
|
let mut map_needs_update = map_needs_update.single_mut();
|
||||||
for (mut regen, mut wealth) in cells.iter_mut() {
|
for (mut regen, mut wealth) in cells.iter_mut() {
|
||||||
if gt.current - regen.last_update > regen.full_growth_duration/u8::MAX as u32 {
|
if gt.current - regen.last_update > regen.full_growth_duration / u8::MAX as u32 {
|
||||||
regen.last_update = gt.current;
|
regen.last_update = gt.current;
|
||||||
wealth.0 = wealth.0.saturating_add(1);
|
wealth.0 = wealth.0.saturating_add(1);
|
||||||
map_needs_update.0 = true;
|
map_needs_update.0 = true;
|
||||||
@ -82,7 +92,7 @@ pub fn expand(
|
|||||||
map: Query<(&Voronoi, &CellsEntities)>,
|
map: Query<(&Voronoi, &CellsEntities)>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
t: Res<Time>,
|
t: Res<Time>,
|
||||||
gt: Res<GameTime>
|
gt: Res<GameTime>,
|
||||||
) {
|
) {
|
||||||
let (voronoi, cells_entities) = map.single();
|
let (voronoi, cells_entities) = map.single();
|
||||||
let mut random = thread_rng();
|
let mut random = thread_rng();
|
||||||
@ -93,16 +103,37 @@ pub fn expand(
|
|||||||
let wealth = if cell.kind == CellKind::Forest {
|
let wealth = if cell.kind == CellKind::Forest {
|
||||||
1.
|
1.
|
||||||
} else {
|
} else {
|
||||||
wealth.unwrap().0 as f64/255.
|
wealth.unwrap().0 as f64 / 255.
|
||||||
};
|
};
|
||||||
if random.gen_bool((t.elapsed_secs_f64()*(gt.speed as f64)*wealth/(60.*60.*24.*30.)).min(1.)) { // Let say that grass takes 1 months to expand
|
if random.gen_bool(
|
||||||
let target = voronoi.0.cell(cell.voronoi_id).iter_neighbors().choose(&mut random).unwrap();
|
(t.elapsed_secs_f64() * (gt.speed as f64) * wealth / (60. * 60. * 24. * 30.))
|
||||||
|
.min(1.),
|
||||||
|
) {
|
||||||
|
// Let say that grass takes 1 months to expand
|
||||||
|
let target = voronoi
|
||||||
|
.0
|
||||||
|
.cell(cell.voronoi_id)
|
||||||
|
.iter_neighbors()
|
||||||
|
.choose(&mut random)
|
||||||
|
.unwrap();
|
||||||
changes.push((target, CellKind::Grass));
|
changes.push((target, CellKind::Grass));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cell.kind == CellKind::Forest {
|
if cell.kind == CellKind::Forest {
|
||||||
if random.gen_bool((t.elapsed_secs_f64()*(gt.speed as f64)*(wealth.unwrap().0 as f64/255.).sqrt()/(60.*60.*24.*365.*5.)).min(1.)) { // Let say that forest takes 5 years to expand
|
if random.gen_bool(
|
||||||
let target = voronoi.0.cell(cell.voronoi_id).iter_neighbors().choose(&mut random).unwrap();
|
(t.elapsed_secs_f64()
|
||||||
|
* (gt.speed as f64)
|
||||||
|
* (wealth.unwrap().0 as f64 / 255.).sqrt()
|
||||||
|
/ (60. * 60. * 24. * 365. * 5.))
|
||||||
|
.min(1.),
|
||||||
|
) {
|
||||||
|
// Let say that forest takes 5 years to expand
|
||||||
|
let target = voronoi
|
||||||
|
.0
|
||||||
|
.cell(cell.voronoi_id)
|
||||||
|
.iter_neighbors()
|
||||||
|
.choose(&mut random)
|
||||||
|
.unwrap();
|
||||||
changes.push((target, CellKind::Forest));
|
changes.push((target, CellKind::Forest));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,18 +141,75 @@ pub fn expand(
|
|||||||
for (v_id, kind) in changes {
|
for (v_id, kind) in changes {
|
||||||
let target = cells_entities.0[v_id];
|
let target = cells_entities.0[v_id];
|
||||||
let (mut cell, _) = cells.get_mut(target).unwrap();
|
let (mut cell, _) = cells.get_mut(target).unwrap();
|
||||||
if kind == CellKind::Forest && (cell.kind == CellKind::Dirt || cell.kind == CellKind::Grass) {
|
if kind == CellKind::Forest && (cell.kind == CellKind::Dirt || cell.kind == CellKind::Grass)
|
||||||
|
{
|
||||||
cell.kind = CellKind::Forest;
|
cell.kind = CellKind::Forest;
|
||||||
cmds.entity(target).insert((Wealth(0), Regeneration {
|
cmds.entity(target).insert((
|
||||||
full_growth_duration: CellKind::Forest.regen_full_growth_duration(),
|
Wealth(0),
|
||||||
last_update: gt.current
|
Regeneration {
|
||||||
}));
|
full_growth_duration: CellKind::Forest.regen_full_growth_duration(),
|
||||||
|
last_update: gt.current,
|
||||||
|
},
|
||||||
|
));
|
||||||
} else if kind == CellKind::Grass && cell.kind == CellKind::Dirt {
|
} else if kind == CellKind::Grass && cell.kind == CellKind::Dirt {
|
||||||
cell.kind = CellKind::Grass;
|
cell.kind = CellKind::Grass;
|
||||||
cmds.entity(target).insert((Wealth(0), Regeneration {
|
cmds.entity(target).insert((
|
||||||
full_growth_duration: CellKind::Grass.regen_full_growth_duration(),
|
Wealth(0),
|
||||||
last_update: gt.current
|
Regeneration {
|
||||||
}));
|
full_growth_duration: CellKind::Grass.regen_full_growth_duration(),
|
||||||
|
last_update: gt.current,
|
||||||
|
},
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_click(
|
||||||
|
trigger: Trigger<Pointer<Click>>,
|
||||||
|
mut cells: Query<&mut Cell>,
|
||||||
|
mut map_needs_update: Query<&mut MeshNeedsUpdate, With<MapMarker>>,
|
||||||
|
mut cmds: Commands,
|
||||||
|
ca: Res<CurrentAction>,
|
||||||
|
gt: Res<GameTime>,
|
||||||
|
) {
|
||||||
|
if trigger.duration > Duration::from_millis(200) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
match *ca {
|
||||||
|
CurrentAction::ChangeCell(ck) => {
|
||||||
|
let mut cell = cells.get_mut(trigger.target).unwrap();
|
||||||
|
match ck {
|
||||||
|
CellKind::Forest => match cell.kind {
|
||||||
|
CellKind::Dirt | CellKind::Grass => {
|
||||||
|
cmds.entity(trigger.target).insert((
|
||||||
|
Wealth(0),
|
||||||
|
Regeneration {
|
||||||
|
last_update: gt.current,
|
||||||
|
full_growth_duration: CellKind::Forest.regen_full_growth_duration(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
cell.kind = CellKind::Forest;
|
||||||
|
map_needs_update.single_mut().0 = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
CellKind::Grass => match cell.kind {
|
||||||
|
CellKind::Dirt => {
|
||||||
|
cmds.entity(trigger.target).insert((
|
||||||
|
Wealth(0),
|
||||||
|
Regeneration {
|
||||||
|
last_update: gt.current,
|
||||||
|
full_growth_duration: CellKind::Grass.regen_full_growth_duration(),
|
||||||
|
},
|
||||||
|
));
|
||||||
|
cell.kind = CellKind::Grass;
|
||||||
|
map_needs_update.single_mut().0 = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
use bevy::{picking::{backend::{HitData, PointerHits}, pointer::{PointerId, PointerLocation}}, prelude::*, window::PrimaryWindow};
|
use bevy::{
|
||||||
|
picking::{
|
||||||
|
backend::{HitData, PointerHits},
|
||||||
|
pointer::{PointerId, PointerLocation},
|
||||||
|
},
|
||||||
|
prelude::*,
|
||||||
|
window::PrimaryWindow,
|
||||||
|
};
|
||||||
use voronoice::Point;
|
use voronoice::Point;
|
||||||
|
|
||||||
use super::{CellsEntities, MapMarker, Voronoi};
|
use super::{CellsEntities, MapMarker, Voronoi};
|
||||||
@ -8,7 +15,7 @@ pub fn picking_backend(
|
|||||||
window: Query<&Window, With<PrimaryWindow>>,
|
window: Query<&Window, With<PrimaryWindow>>,
|
||||||
pointers: Query<(&PointerId, &PointerLocation)>,
|
pointers: Query<(&PointerId, &PointerLocation)>,
|
||||||
map: Query<(&Voronoi, &CellsEntities, &Transform), With<MapMarker>>,
|
map: Query<(&Voronoi, &CellsEntities, &Transform), With<MapMarker>>,
|
||||||
mut output: EventWriter<PointerHits>
|
mut output: EventWriter<PointerHits>,
|
||||||
) {
|
) {
|
||||||
let (cam, cam_id) = cam.single();
|
let (cam, cam_id) = cam.single();
|
||||||
let window = window.single();
|
let window = window.single();
|
||||||
@ -16,24 +23,38 @@ pub fn picking_backend(
|
|||||||
let mut last_cell = 0;
|
let mut last_cell = 0;
|
||||||
for (id, l) in pointers.iter() {
|
for (id, l) in pointers.iter() {
|
||||||
if let Some(mut pos) = l.location().map(|l| l.position) {
|
if let Some(mut pos) = l.location().map(|l| l.position) {
|
||||||
pos -= window.size()/2.;
|
pos -= window.size() / 2.;
|
||||||
pos *= cam.scale.xy();
|
pos *= cam.scale.xy();
|
||||||
pos.x += cam.translation.x;
|
pos.x += cam.translation.x;
|
||||||
pos.y -= cam.translation.y;
|
pos.y -= cam.translation.y;
|
||||||
if let Some(c) = voronoi.0.cell(last_cell).iter_path(Point { x: pos.x as f64, y: -pos.y as f64 }).last() {
|
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;
|
last_cell = c;
|
||||||
output.send(PointerHits {
|
output.send(PointerHits {
|
||||||
pointer: *id,
|
pointer: *id,
|
||||||
picks: vec![(cells_entities.0[c], HitData {
|
picks: vec![(
|
||||||
camera: cam_id,
|
cells_entities.0[c],
|
||||||
depth: map_pos.translation.z,
|
HitData {
|
||||||
position: Some(Vec3 { x: pos.x, y: pos.y, z: map_pos.translation.z }),
|
camera: cam_id,
|
||||||
normal: None
|
depth: map_pos.translation.z,
|
||||||
})],
|
position: Some(Vec3 {
|
||||||
order: map_pos.translation.z
|
x: pos.x,
|
||||||
|
y: pos.y,
|
||||||
|
z: map_pos.translation.z,
|
||||||
|
}),
|
||||||
|
normal: None,
|
||||||
|
},
|
||||||
|
)],
|
||||||
|
order: map_pos.translation.z,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
17
src/time.rs
17
src/time.rs
@ -6,23 +6,20 @@ pub struct Plugin;
|
|||||||
impl bevy::prelude::Plugin for Plugin {
|
impl bevy::prelude::Plugin for Plugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(GameTime {
|
app.insert_resource(GameTime {
|
||||||
current: Duration::ZERO,
|
current: Duration::ZERO,
|
||||||
speed: 24. * 60. * 60. * 10.
|
speed: 24. * 60. * 60. * 10.,
|
||||||
})
|
})
|
||||||
.add_systems(PreUpdate, update_time);
|
.add_systems(PreUpdate, update_time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct GameTime {
|
pub struct GameTime {
|
||||||
pub current: Duration,
|
pub current: Duration,
|
||||||
pub speed: f32 // = game time / real time
|
pub speed: f32, // = game time / real time
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_time(
|
fn update_time(mut gt: ResMut<GameTime>, time: Res<Time>) {
|
||||||
mut gt: ResMut<GameTime>,
|
|
||||||
time: Res<Time>
|
|
||||||
) {
|
|
||||||
let speed = gt.speed;
|
let speed = gt.speed;
|
||||||
gt.current += Duration::from_secs_f32(time.delta_secs() * speed);
|
gt.current += Duration::from_secs_f32(time.delta_secs() * speed);
|
||||||
}
|
}
|
||||||
|
47
src/ui.rs
47
src/ui.rs
@ -1,13 +1,24 @@
|
|||||||
|
use bevy::{
|
||||||
|
asset::embedded_asset,
|
||||||
|
input::mouse::MouseWheel,
|
||||||
|
math::{NormedVectorSpace, VectorSpace},
|
||||||
|
picking::{focus::HoverMap, pointer::PointerId},
|
||||||
|
prelude::*,
|
||||||
|
utils::{dbg, HashMap},
|
||||||
|
window::PrimaryWindow,
|
||||||
|
};
|
||||||
use mevy::*;
|
use mevy::*;
|
||||||
use bevy::{asset::embedded_asset, input::mouse::MouseWheel, math::{NormedVectorSpace, VectorSpace}, picking::{focus::HoverMap, pointer::PointerId}, prelude::*, utils::{dbg, HashMap}, window::PrimaryWindow};
|
|
||||||
|
|
||||||
use crate::{animals::AnimalKind, map::{self, CellKind, MapMarker}};
|
use crate::{
|
||||||
|
animals::AnimalKind,
|
||||||
|
map::{self, CellKind, MapMarker},
|
||||||
|
};
|
||||||
|
|
||||||
// #77767b
|
// #77767b
|
||||||
const TABBAR_COLOR: Color = Color::srgb(119./255., 118./255., 123./255.);
|
const TABBAR_COLOR: Color = Color::srgb(119. / 255., 118. / 255., 123. / 255.);
|
||||||
|
|
||||||
// #E8E8E8
|
// #E8E8E8
|
||||||
const ENABLED_BUTTON_COLOR: Color = Color::srgb(232./255., 232./255., 232./255.);
|
const ENABLED_BUTTON_COLOR: Color = Color::srgb(232. / 255., 232. / 255., 232. / 255.);
|
||||||
|
|
||||||
pub struct Plugin;
|
pub struct Plugin;
|
||||||
impl bevy::prelude::Plugin for Plugin {
|
impl bevy::prelude::Plugin for Plugin {
|
||||||
@ -31,7 +42,7 @@ pub enum CurrentAction {
|
|||||||
#[default]
|
#[default]
|
||||||
None,
|
None,
|
||||||
ChangeCell(CellKind),
|
ChangeCell(CellKind),
|
||||||
AddAnimal(AnimalKind)
|
AddAnimal(AnimalKind),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
@ -40,12 +51,9 @@ struct PointersDragging(HashMap<PointerId, Vec2>);
|
|||||||
#[derive(Component)]
|
#[derive(Component)]
|
||||||
pub struct MapUIComponent;
|
pub struct MapUIComponent;
|
||||||
|
|
||||||
fn setup(
|
fn setup(mut world: Commands, asset_server: Res<AssetServer>) {
|
||||||
mut world: Commands,
|
|
||||||
asset_server: Res<AssetServer>
|
|
||||||
) {
|
|
||||||
// Spawn all ui elements as children of this one
|
// Spawn all ui elements as children of this one
|
||||||
spawn!{
|
spawn! {
|
||||||
Node {width: 100%, height: 100%, display: Display::Flex, flex_direction: FlexDirection::Column, !};
|
Node {width: 100%, height: 100%, display: Display::Flex, flex_direction: FlexDirection::Column, !};
|
||||||
PickingBehavior {
|
PickingBehavior {
|
||||||
should_block_lower: false,
|
should_block_lower: false,
|
||||||
@ -67,17 +75,17 @@ fn setup(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
let mut cam = cam.single_mut();
|
let mut cam = cam.single_mut();
|
||||||
|
|
||||||
let old_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
|
let old_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
|
||||||
let old_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (old_midpoint-pos).norm());
|
let old_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (old_midpoint-pos).norm());
|
||||||
ptrs.0.insert(trigger.pointer_id, trigger.pointer_location.position);
|
ptrs.0.insert(trigger.pointer_id, trigger.pointer_location.position);
|
||||||
let new_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
|
let new_midpoint = ptrs.0.values().fold(Vec2::ZERO, |acc, pos| acc + (pos/ptrs.0.len() as f32));
|
||||||
let new_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (new_midpoint-pos).norm());
|
let new_d_to_midpoint = ptrs.0.values().fold(0., |acc, pos| acc + (new_midpoint-pos).norm());
|
||||||
|
|
||||||
// move camera
|
// move camera
|
||||||
cam.translation.x -= (new_midpoint.x - old_midpoint.x)*cam.scale.x;
|
cam.translation.x -= (new_midpoint.x - old_midpoint.x)*cam.scale.x;
|
||||||
cam.translation.y += (new_midpoint.y - old_midpoint.y)*cam.scale.y;
|
cam.translation.y += (new_midpoint.y - old_midpoint.y)*cam.scale.y;
|
||||||
|
|
||||||
if ptrs.0.len() > 1 {
|
if ptrs.0.len() > 1 {
|
||||||
cam.scale *= old_d_to_midpoint/new_d_to_midpoint;
|
cam.scale *= old_d_to_midpoint/new_d_to_midpoint;
|
||||||
}
|
}
|
||||||
@ -182,15 +190,20 @@ fn zoom_with_scroll(
|
|||||||
mut ev_scroll: EventReader<MouseWheel>,
|
mut ev_scroll: EventReader<MouseWheel>,
|
||||||
hover_map: Res<HoverMap>,
|
hover_map: Res<HoverMap>,
|
||||||
window: Query<&Window, With<PrimaryWindow>>,
|
window: Query<&Window, With<PrimaryWindow>>,
|
||||||
map_ui_id: Query<Entity, With<MapUIComponent>>
|
map_ui_id: Query<Entity, With<MapUIComponent>>,
|
||||||
) {
|
) {
|
||||||
let map_ui_id = map_ui_id.single();
|
let map_ui_id = map_ui_id.single();
|
||||||
if hover_map.get(&PointerId::Mouse).and_then(|hovered_ids| hovered_ids.get(&map_ui_id)).is_some() {
|
if hover_map
|
||||||
|
.get(&PointerId::Mouse)
|
||||||
|
.and_then(|hovered_ids| hovered_ids.get(&map_ui_id))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
let window = window.single();
|
let window = window.single();
|
||||||
let mut cam = cam.single_mut();
|
let mut cam = cam.single_mut();
|
||||||
for ev in ev_scroll.read() {
|
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()));
|
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);
|
cam.scale = Vec3::new(scale, scale, scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user