Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve minimap camera controls #642

Merged
merged 3 commits into from
Sep 7, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 124 additions & 40 deletions crates/controller/src/hud/minimap/interaction.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::fmt;

use bevy::{
input::{mouse::MouseButtonInput, ButtonState},
input::{
mouse::{MouseButtonInput, MouseMotion},
ButtonState,
},
prelude::*,
window::PrimaryWindow,
};
Expand All @@ -19,35 +22,47 @@ pub(super) struct InteractionPlugin;

impl Plugin for InteractionPlugin {
fn build(&self, app: &mut App) {
app.add_event::<MinimapClickEvent>().add_systems(
InputSchedule,
(
click_handler.in_set(InteractionSet::ClickHandler),
move_camera_system.after(InteractionSet::ClickHandler),
send_units_system
.after(InteractionSet::ClickHandler)
.before(CommandsSet::SendSelected),
delivery_location_system
.after(InteractionSet::ClickHandler)
.before(CommandsSet::DeliveryLocation),
)
.run_if(in_state(GameState::Playing)),
);
app.add_event::<MinimapPressEvent>()
.add_event::<MinimapDragEvent>()
.insert_resource(DraggingButtons(Vec::new()))
.add_systems(
InputSchedule,
(
press_handler
.in_set(InteractionSet::PressHandler)
.run_if(on_event::<MouseButtonInput>()),
drag_handler
.in_set(InteractionSet::DragHandler)
.after(InteractionSet::PressHandler)
.run_if(on_event::<MouseMotion>()),
move_camera_system
.after(InteractionSet::PressHandler)
.after(InteractionSet::DragHandler),
send_units_system
.after(InteractionSet::PressHandler)
.before(CommandsSet::SendSelected),
delivery_location_system
.after(InteractionSet::PressHandler)
.before(CommandsSet::DeliveryLocation),
)
.run_if(in_state(GameState::Playing)),
);
}
}

#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq, SystemSet)]
enum InteractionSet {
ClickHandler,
PressHandler,
DragHandler,
}

#[derive(Event)]
struct MinimapClickEvent {
struct MinimapPressEvent {
button: MouseButton,
position: Vec2,
}

impl MinimapClickEvent {
impl MinimapPressEvent {
fn new(button: MouseButton, position: Vec2) -> Self {
Self { button, position }
}
Expand All @@ -63,68 +78,137 @@ impl MinimapClickEvent {
}
}

impl fmt::Debug for MinimapClickEvent {
impl fmt::Debug for MinimapPressEvent {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} -> {:?}", self.button, self.position)
}
}

fn click_handler(
#[derive(Event)]
struct MinimapDragEvent {
button: MouseButton,
position: Vec2,
}

impl MinimapDragEvent {
fn new(button: MouseButton, position: Vec2) -> Self {
Self { button, position }
}

fn button(&self) -> MouseButton {
self.button
}

/// Position on the map in 2D flat coordinates (these are not minimap
/// coordinates).
fn position(&self) -> Vec2 {
self.position
}
}

#[derive(Resource, Deref, DerefMut)]
struct DraggingButtons(Vec<MouseButton>);

fn press_handler(
window_query: Query<&Window, With<PrimaryWindow>>,
mut input_events: EventReader<MouseButtonInput>,
hud: HudNodes<With<MinimapNode>>,
bounds: Res<MapBounds>,
mut click_events: EventWriter<MinimapClickEvent>,
mut dragging: ResMut<DraggingButtons>,
mut press_events: EventWriter<MinimapPressEvent>,
) {
let Some(cursor) = window_query.single().cursor_position() else {
return;
};
let cursor = window_query.single().cursor_position();

for event in input_events.iter() {
if event.state != ButtonState::Released {
if event.state != ButtonState::Pressed {
Zakru marked this conversation as resolved.
Show resolved Hide resolved
dragging.retain(|b| *b != event.button);
continue;
}

let Some(cursor) = cursor else {
continue;
};

if let Some(mut relative) = hud.relative_position(cursor) {
dragging.push(event.button);
relative.y = 1. - relative.y;
let event = MinimapClickEvent::new(event.button, bounds.rel_to_abs(relative));
info!("Sending minimap click event {event:?}.");
click_events.send(event);
let event = MinimapPressEvent::new(event.button, bounds.rel_to_abs(relative));
info!("Sending minimap press event {event:?}.");
press_events.send(event);
}
}
}

fn drag_handler(
window_query: Query<&Window, With<PrimaryWindow>>,
hud: HudNodes<With<MinimapNode>>,
bounds: Res<MapBounds>,
dragging: Res<DraggingButtons>,
mut drag_events: EventWriter<MinimapDragEvent>,
) {
if dragging.is_empty() {
return;
}

let Some(cursor) = window_query.single().cursor_position() else {
return;
};

if let Some(relative) = hud.relative_position(cursor) {
let proportional = Vec2::new(relative.x, 1. - relative.y);
let world = bounds.rel_to_abs(proportional);

for button in &**dragging {
let event = MinimapDragEvent::new(*button, world);
drag_events.send(event);
}
}
}

fn move_camera_system(
Zakru marked this conversation as resolved.
Show resolved Hide resolved
mut click_events: EventReader<MinimapClickEvent>,
mut press_events: EventReader<MinimapPressEvent>,
mut drag_events: EventReader<MinimapDragEvent>,
mut camera_events: EventWriter<MoveFocusEvent>,
) {
for click in click_events.iter() {
if click.button() != MouseButton::Left {
for press in press_events.iter() {
if press.button() != MouseButton::Left {
continue;
}
camera_events.send(MoveFocusEvent::new(click.position()));

let event = MoveFocusEvent::new(press.position());
camera_events.send(event);
}

for drag in drag_events.iter() {
if drag.button() != MouseButton::Left {
continue;
}

let event = MoveFocusEvent::new(drag.position());
camera_events.send(event);
}
}

fn send_units_system(
mut click_events: EventReader<MinimapClickEvent>,
mut press_events: EventReader<MinimapPressEvent>,
mut send_events: EventWriter<SendSelectedEvent>,
) {
for click in click_events.iter() {
if click.button() != MouseButton::Right {
for press in press_events.iter() {
if press.button() != MouseButton::Right {
continue;
}
send_events.send(SendSelectedEvent::new(click.position()));
send_events.send(SendSelectedEvent::new(press.position()));
}
}

fn delivery_location_system(
mut click_events: EventReader<MinimapClickEvent>,
mut press_events: EventReader<MinimapPressEvent>,
mut location_events: EventWriter<DeliveryLocationSelectedEvent>,
) {
for click in click_events.iter() {
if click.button() != MouseButton::Right {
for press in press_events.iter() {
if press.button() != MouseButton::Right {
continue;
}
location_events.send(DeliveryLocationSelectedEvent::new(click.position()));
location_events.send(DeliveryLocationSelectedEvent::new(press.position()));
}
}