213 lines
8.7 KiB
Rust
213 lines
8.7 KiB
Rust
use bevy::{
|
|
asset::embedded_asset,
|
|
input::mouse::MouseWheel,
|
|
math::NormedVectorSpace,
|
|
picking::{focus::HoverMap, pointer::PointerId},
|
|
prelude::*,
|
|
utils::HashMap,
|
|
window::PrimaryWindow,
|
|
};
|
|
use mevy::*;
|
|
|
|
use crate::camera::CameraMarker;
|
|
use crate::map::{AnimalKind, CellKind};
|
|
|
|
// #77767b
|
|
const TABBAR_COLOR: Color = Color::srgb(119. / 255., 118. / 255., 123. / 255.);
|
|
|
|
// #E8E8E8
|
|
const ENABLED_BUTTON_COLOR: Color = Color::srgb(232. / 255., 232. / 255., 232. / 255.);
|
|
|
|
pub struct Plugin;
|
|
impl bevy::prelude::Plugin for Plugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.init_resource::<CurrentAction>()
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, zoom_with_scroll);
|
|
embedded_asset!(app, "../assets/ui/enabled_tree.png");
|
|
embedded_asset!(app, "../assets/ui/disabled_tree.png");
|
|
embedded_asset!(app, "../assets/ui/enabled_grass.png");
|
|
embedded_asset!(app, "../assets/ui/disabled_grass.png");
|
|
embedded_asset!(app, "../assets/ui/enabled_cross.png");
|
|
embedded_asset!(app, "../assets/ui/disabled_cross.png");
|
|
embedded_asset!(app, "../assets/ui/enabled_goat.png");
|
|
embedded_asset!(app, "../assets/ui/disabled_goat.png");
|
|
}
|
|
}
|
|
|
|
#[derive(Resource, Default, PartialEq, Eq)]
|
|
pub enum CurrentAction {
|
|
#[default]
|
|
None,
|
|
ChangeCell(CellKind),
|
|
AddAnimal(AnimalKind),
|
|
}
|
|
|
|
#[derive(Component, Debug)]
|
|
struct PointersDragging(HashMap<PointerId, Vec2>);
|
|
|
|
#[derive(Component)]
|
|
pub struct MapUIComponent;
|
|
|
|
fn setup(mut world: Commands, asset_server: Res<AssetServer>) {
|
|
// Spawn all ui elements as children of this one
|
|
spawn! {
|
|
Node {width: 100%, height: 100%, display: Display::Flex, flex_direction: FlexDirection::Column, !};
|
|
PickingBehavior {
|
|
should_block_lower: false,
|
|
is_hoverable: true
|
|
};
|
|
.observe(|trigger: Trigger<Pointer<DragEnd>>, mut ptrs: Query<&mut PointersDragging>| {
|
|
if trigger.button == PointerButton::Primary {
|
|
ptrs.single_mut().0.remove(&trigger.pointer_id);
|
|
}
|
|
});
|
|
.observe(|
|
|
trigger: Trigger<Pointer<Drag>>,
|
|
mut ptrs: Query<&mut PointersDragging>,
|
|
mut cam: Query<&mut Transform, With<CameraMarker>>,
|
|
| {
|
|
if trigger.button == PointerButton::Primary {
|
|
let mut ptrs = ptrs.single_mut();
|
|
if !ptrs.0.contains_key(&trigger.pointer_id) {
|
|
return
|
|
}
|
|
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_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);
|
|
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());
|
|
|
|
// move camera
|
|
cam.translation.x -= (new_midpoint.x - old_midpoint.x)*cam.translation.z*0.001;
|
|
cam.translation.y += (new_midpoint.y - old_midpoint.y)*cam.translation.z*0.001;
|
|
|
|
if ptrs.0.len() > 1 {
|
|
let forward = cam.forward();
|
|
let z = cam.translation.z;
|
|
cam.translation += forward * (z * (1. - (new_d_to_midpoint/old_d_to_midpoint)) / forward.z);
|
|
// cam.scale *= old_d_to_midpoint/new_d_to_midpoint;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
[map][
|
|
Node{
|
|
flex_grow: 1.,
|
|
!};
|
|
PointersDragging(HashMap::new());
|
|
MapUIComponent;
|
|
PickingBehavior {
|
|
should_block_lower: false,
|
|
is_hoverable: true
|
|
};
|
|
.observe(|trigger: Trigger<Pointer<DragStart>>, mut ptrs: Query<&mut PointersDragging>| {
|
|
if trigger.button == PointerButton::Primary {
|
|
if let Ok(mut ptrs) = ptrs.get_mut(trigger.target) {
|
|
ptrs.0.insert(trigger.pointer_id, trigger.pointer_location.position);
|
|
}
|
|
}
|
|
});
|
|
]
|
|
[
|
|
Node{
|
|
width: 100%,
|
|
height: 10vh,
|
|
align_self: AlignSelf::FlexEnd,
|
|
!};
|
|
Button;
|
|
BackgroundColor(TABBAR_COLOR);
|
|
[forest][
|
|
ImageNode::new(asset_server.load("embedded://forestiles/../assets/ui/enabled_tree.png"));
|
|
Node {
|
|
// height: 80%,
|
|
// margin: [>1vh],
|
|
!};
|
|
BackgroundColor(TABBAR_COLOR);
|
|
.observe(move |trigger: Trigger<Pointer<Click>>, mut ca: ResMut<CurrentAction>, mut bg: Query<&mut BackgroundColor>| {
|
|
if trigger.button == PointerButton::Primary {
|
|
if *ca == CurrentAction::ChangeCell(CellKind::Forest) {
|
|
*ca = CurrentAction::None;
|
|
bg.get_mut(forest).unwrap().0 = TABBAR_COLOR;
|
|
} else {
|
|
*ca = CurrentAction::ChangeCell(CellKind::Forest);
|
|
bg.get_mut(forest).unwrap().0 = ENABLED_BUTTON_COLOR;
|
|
}
|
|
bg.get_mut(grass).unwrap().0 = TABBAR_COLOR;
|
|
bg.get_mut(goat).unwrap().0 = TABBAR_COLOR;
|
|
}
|
|
});
|
|
]
|
|
[grass][
|
|
ImageNode::new(asset_server.load("embedded://forestiles/../assets/ui/enabled_grass.png"));
|
|
Node {
|
|
// height: 80%,
|
|
// margin: [>1vh],
|
|
!};
|
|
BackgroundColor(TABBAR_COLOR);
|
|
.observe(move |trigger: Trigger<Pointer<Click>>, mut ca: ResMut<CurrentAction>, mut bg: Query<&mut BackgroundColor>| {
|
|
if trigger.button == PointerButton::Primary {
|
|
if *ca == CurrentAction::ChangeCell(CellKind::Grass) {
|
|
*ca = CurrentAction::None;
|
|
bg.get_mut(grass).unwrap().0 = TABBAR_COLOR;
|
|
} else {
|
|
*ca = CurrentAction::ChangeCell(CellKind::Grass);
|
|
bg.get_mut(grass).unwrap().0 = ENABLED_BUTTON_COLOR;
|
|
}
|
|
bg.get_mut(forest).unwrap().0 = TABBAR_COLOR;
|
|
bg.get_mut(goat).unwrap().0 = TABBAR_COLOR;
|
|
}
|
|
});
|
|
]
|
|
[goat][
|
|
ImageNode::new(asset_server.load("embedded://forestiles/../assets/ui/enabled_goat.png"));
|
|
Node {
|
|
// height: 80%,
|
|
// margin: [>1vh],
|
|
!};
|
|
BackgroundColor(TABBAR_COLOR);
|
|
.observe(move |trigger: Trigger<Pointer<Click>>, mut ca: ResMut<CurrentAction>, mut bg: Query<&mut BackgroundColor>| {
|
|
if trigger.button == PointerButton::Primary {
|
|
if *ca == CurrentAction::AddAnimal(AnimalKind::Goat) {
|
|
*ca = CurrentAction::None;
|
|
bg.get_mut(goat).unwrap().0 = TABBAR_COLOR;
|
|
} else {
|
|
*ca = CurrentAction::AddAnimal(AnimalKind::Goat);
|
|
bg.get_mut(goat).unwrap().0 = ENABLED_BUTTON_COLOR;
|
|
}
|
|
bg.get_mut(forest).unwrap().0 = TABBAR_COLOR;
|
|
bg.get_mut(grass).unwrap().0 = TABBAR_COLOR;
|
|
}
|
|
});
|
|
]
|
|
]
|
|
}
|
|
}
|
|
|
|
fn zoom_with_scroll(
|
|
mut cam: Query<&mut Transform, With<CameraMarker>>,
|
|
mut ev_scroll: EventReader<MouseWheel>,
|
|
hover_map: Res<HoverMap>,
|
|
window: Query<&Window, With<PrimaryWindow>>,
|
|
map_ui_id: Query<Entity, With<MapUIComponent>>,
|
|
) {
|
|
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()
|
|
{
|
|
let window = window.single();
|
|
let mut cam = cam.single_mut();
|
|
for ev in ev_scroll.read() {
|
|
let forward = cam.forward();
|
|
cam.translation += forward * (ev.y * 0.1);
|
|
// cam.fov = cam.fov + (ev.y * 0.1);
|
|
// let scale = (cam.scale.x - (ev.y * 0.1 / window.width().min(window.height())))
|
|
// .clamp(0.0001, 2. / window.width().min(window.height()));
|
|
}
|
|
}
|
|
}
|