I am trying to see where the mouse is pressed so I can select my character. I have tried the following
#[derive(Default)]
struct State { // Set up from example
mouse_button_event_reader: EventReader<MouseButtonInput>,
cursor_moved_event_reader: EventReader<CursorMoved>,
}
fn select_character(
mut state: ResMut<State>,
mouse_button_input_events: Res<Events<MouseButtonInput>>,
cursor_moved_events: Res<Events<CursorMoved>>,
) {
for (cursor_event, mouse_event) in state
.cursor_moved_event_reader
.iter(&cursor_moved_events)
.zip(
state
.mouse_button_event_reader
.iter(&mouse_button_input_events),
)
{
println!("{:?}", cursor_event);
println!("{:?}", mouse_event);
}
}
This kind of works, but the mouse needs to be moving while it is clicked. Is there a way of getting the position once the mouse is pressed?
Edit:
I thought .find_latest
might work, getting it to return the latest Some
value.
for event in state
.mouse_button_event_reader
.iter(&mouse_button_input_events)
{
let cursor_event = state
.cursor_moved_event_reader
.find_latest(&cursor_moved_events, |x| x.is_Some() // Not sure how to only return values that are Some(x)
);
println!("{:?}", event);
println!("{:?}", cursor_event);
}
It appears that .find_latest
is for finding the next unread value. Which means you would probably also require movement. Since, it is likely is a click was the last event, the movement was already captured.
Now, I can't promise that this is idiomatic since we're all new at this, but there is a solution:
Add two floating-point variables to your state-struct. Then, when the cursor is moved, store that position. When the mouse is clicked, recall that information. Since it becomes a part of the resource (state) that information will be available for read and write.
Implemented
#[derive(Default)]
struct State { // Set up from example
mouse_button_event_reader: EventReader<MouseButtonInput>,
cursor_moved_event_reader: EventReader<CursorMoved>,
}
struct MouseLoc(Vec2);
fn select_character(
mut state: ResMut<State>,
mouse_pos: ResMut<MouseLoc>,
mouse_button_input_events: Res<Events<MouseButtonInput>>,
) {
for event in state
.mouse_button_event_reader
.iter(&mouse_button_input_events)
{
println!("event: {:?} position: {:?}", event, mouse_pos.0);
}
}
fn mouse_movement_updating_system(
mut mouse_pos: ResMut<MouseLoc>,
mut state: ResMut<State>,
cursor_moved_events: Res<Events<CursorMoved>>,
) {
for event in state.cursor_moved_event_reader.iter(&cursor_moved_events) {
mouse_pos.0 = event.position;
}
}
fn main() {
App::build()
.add_default_plugins()
...
.add_resource(MouseLoc(Vec2::new(0.0, 0.0)))
.add_system(mouse_movement_updating_system.system());
.add_system(position_mouse_click_system.system());
...
.run();
}
I think what you want is something like this:
fn handle_mouse_clicks(mouse_input: Res<Input<MouseButton>>, windows: Res<Windows>) {
let win = windows.get_primary().expect("no primary window");
if mouse_input.just_pressed(MouseButton::Left) {
println!("click at {:?}", win.cursor_position());
}
}
This works for version 0.5.0 of bevy: https://docs.rs/bevy/0.5.0/bevy/window/struct.Window.html#method.cursor_position
You could implement your own object always tracking the current position (via an event reader) as well, but in my tests, the method described above gives a more (temporal) accurate result (you get the position at the time the click comes through not an arbitrarily old position) - but I am not an expert on this!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With