Skip to content

Instantly share code, notes, and snippets.

@shanecelis
Created July 20, 2024 10:22
Show Gist options
  • Save shanecelis/06b2d1a598e1e06d0a00671596e9f74f to your computer and use it in GitHub Desktop.
Save shanecelis/06b2d1a598e1e06d0a00671596e9f74f to your computer and use it in GitHub Desktop.
Click event for bevy
/* Original code Copyright (c) 2024 Shane Celis[1]
Licensed under the MIT License[2] or Apache License v2.0[3]
[1]: https://mastodon.gamedev.place/@shanecelis
[2]: https://opensource.org/licenses/MIT
[3]: https://www.apache.org/licenses/LICENSE-2.0
*/
//! Click event for Bevy.
//!
//! [Interaction::Pressed] is not the same as a click. A click is a press and
//! release of a mouse button on the same UI element. A press that leaves a UI
//! element and releases elsewhere is not considered a click.
//!
//! # Setup
//!
//! Add the plugin.
//!
//! ```
//! # use bevy::prelude::*;
//! # use bevy_asky::view::click;
//! let mut app = App::new();
//! app.add_plugins(click::plugin);
//! ```
//!
//! # Usage
//!
//! Add an observer on a button.
//!
//! ```
//! # use bevy::prelude::*;
//! # use bevy_asky::view::click::{self, Click};
//! fn setup(mut commands: Commands) {
//! commands.spawn(ButtonBundle::default())
//! .observe(|trigger: Trigger<Click>|
//! eprintln!("Clicked on {}", trigger.entity()));
//! }
//! ```
use bevy::prelude::*;
use bevy::ecs::entity::EntityHashMap;
/// A trigger event that signifies a click on a button.
///
/// ```
/// # use bevy::prelude::*;
/// # use bevy_asky::view::click::{self, Click};
/// fn setup(mut commands: Commands) {
/// commands.spawn(ButtonBundle::default())
/// .observe(|trigger: Trigger<Click>|
/// eprintln!("Clicked on {}", trigger.entity()));
/// }
#[derive(Event, Debug)]
pub struct Click;
/// Adds a system that triggers a [Click] event when [Button] with an
/// [Interaction] component is pressed and released.
///
/// ```
/// # use bevy::prelude::*;
/// # use bevy_asky::view::click;
/// let mut app = App::new();
/// app.add_plugins(click::plugin);
/// ```
pub fn plugin(app: &mut App) {
app.add_systems(Update, button_click);
}
/// This system looks at [Button] [Interaction] changes. If that state changes
/// from [Interaction::Pressed] to [Interaction::Hovered] then it will trigger a
/// [Click] event targeting the Entity with the [Interaction] component.
///
/// TODO: The `Local<EntityHashMap>` should be reset or drop elements that are stale
/// so it doesn't grow unbounded.
fn button_click(
mut interaction_query: Query<(Entity, &Interaction), (Changed<Interaction>, With<Button>)>,
mut last_state: Local<EntityHashMap<Interaction>>,
mut commands: Commands,
) {
for (id, interaction) in &mut interaction_query {
let last = last_state.get(&id);
if *interaction == Interaction::Hovered && matches!(last, Some(Interaction::Pressed)) {
commands.trigger_targets(Click, id);
}
last_state.insert(id, *interaction);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment