From 79092ea0f55b98337f8af0c0dd4276d9f3823bdd Mon Sep 17 00:00:00 2001 From: CoCo_Sol Date: Tue, 19 Mar 2024 15:08:41 +0000 Subject: [PATCH] Improve selection system (#78) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes: #66 Reviewed-on: https://git.tipragot.fr/fish-canard/border-wars/pulls/78 Reviewed-by: Raphaƫl --- crates/border-wars/src/main.rs | 4 +- crates/border-wars/src/map/mod.rs | 2 +- crates/border-wars/src/map/renderer.rs | 4 +- .../map/{click_tile.rs => selected_tile.rs} | 62 +++++++++++++------ 4 files changed, 49 insertions(+), 23 deletions(-) rename crates/border-wars/src/map/{click_tile.rs => selected_tile.rs} (67%) diff --git a/crates/border-wars/src/main.rs b/crates/border-wars/src/main.rs index cc2c72e..ac4d412 100644 --- a/crates/border-wars/src/main.rs +++ b/crates/border-wars/src/main.rs @@ -2,8 +2,8 @@ use bevy::prelude::*; use border_wars::camera::CameraPlugin; -use border_wars::map::click_tile::TilesClickable; use border_wars::map::renderer::RendererPlugin; +use border_wars::map::selected_tile::SelectTilePlugin; use border_wars::scenes::ScenesPlugin; fn main() { @@ -12,6 +12,6 @@ fn main() { .add_plugins(ScenesPlugin) .add_plugins(RendererPlugin) .add_plugins(CameraPlugin) - .add_plugins(TilesClickable) + .add_plugins(SelectTilePlugin) .run(); } diff --git a/crates/border-wars/src/map/mod.rs b/crates/border-wars/src/map/mod.rs index a5bfdf0..839b7e8 100644 --- a/crates/border-wars/src/map/mod.rs +++ b/crates/border-wars/src/map/mod.rs @@ -1,9 +1,9 @@ //! Contains all the logic related to the map. -pub mod click_tile; pub mod generation; pub mod hex; pub mod renderer; +pub mod selected_tile; use bevy::prelude::*; diff --git a/crates/border-wars/src/map/renderer.rs b/crates/border-wars/src/map/renderer.rs index 915d3c6..d391c72 100644 --- a/crates/border-wars/src/map/renderer.rs +++ b/crates/border-wars/src/map/renderer.rs @@ -21,7 +21,7 @@ impl Plugin for RendererPlugin { /// The gap between the center of the tiles in the map. #[derive(Resource)] -struct TilesGap(Vec2); +pub struct TilesGap(pub Vec2); /// The size of the tiles in the map. #[derive(Resource, Clone, Copy)] @@ -85,7 +85,7 @@ fn render_map( commands.entity(entity).insert(SpriteBundle { sprite: Sprite { - anchor: Anchor::BottomLeft, + anchor: Anchor::BottomCenter, ..default() }, texture, diff --git a/crates/border-wars/src/map/click_tile.rs b/crates/border-wars/src/map/selected_tile.rs similarity index 67% rename from crates/border-wars/src/map/click_tile.rs rename to crates/border-wars/src/map/selected_tile.rs index fb66845..2dcb0e4 100644 --- a/crates/border-wars/src/map/click_tile.rs +++ b/crates/border-wars/src/map/selected_tile.rs @@ -1,15 +1,10 @@ -//! All programs related to the clicking on a tile. +//! All programs related to the selection of a tile. use bevy::prelude::*; +use super::renderer::TilesGap; use super::Tile; -/// The event that is triggered when a tile is clicked. -/// -/// The event contains the index (ID) of the clicked tile. -#[derive(Event)] -pub struct TileJustClicked(pub u32); - /// An event that is triggered when a mouse button is clicked. /// /// The event contains the position of the cursor in the world. @@ -21,15 +16,37 @@ struct ClickOnTheWorld(Vec2); #[derive(Component)] pub struct ZoneNotClickable; -/// A plugin that handles the selection of tiles. -pub struct TilesClickable; +/// The currently selected tile. +#[derive(Resource, Default, Debug)] +pub enum SelectedTile { + /// The entity of the selected tile. + Tile(Entity), -impl Plugin for TilesClickable { + /// Zero tile selected. + #[default] + None, +} + +impl SelectedTile { + /// Returns the entity of the selected tile. + /// Returns `None` if no tile is selected. + pub const fn get_entity(&self) -> Option { + match self { + Self::Tile(entity) => Some(*entity), + Self::None => None, + } + } +} + +/// A plugin that handles the selection of tiles. +pub struct SelectTilePlugin; + +impl Plugin for SelectTilePlugin { fn build(&self, app: &mut App) { app.add_systems(PreUpdate, mouse_handler) .add_systems(PreUpdate, select_closest_tile) .add_event::() - .add_event::(); + .init_resource::(); } } @@ -73,25 +90,30 @@ fn mouse_handler( events_writer.send(ClickOnTheWorld(cursor_position_in_world)); } -/// Get the closest tile to the cursor and send it in an event. +/// Get the closest tile to the cursor and select it. fn select_closest_tile( tiles: Query<(Entity, &Transform, &Tile)>, mut click_event_reader: EventReader, - mut clicked_tile_event_writer: EventWriter, + tile_gap: Res, + mut current_entity: ResMut, ) { for click_event in click_event_reader.read() { - // The closest tile and its distance to the cursor. + // The closest tile and its position. let mut closest_entity: Option = None; let mut closest_position: Option = None; + // To keep the aspect ratio. + let click_position = click_event.0 / tile_gap.0; + for (tile_entity, tile_transform, tile_type) in tiles.iter() { - let mut tile_position = tile_transform.translation.truncate(); let tile_size = tile_type.get_image_size(); let tile_scale = tile_transform.scale.truncate(); - tile_position += (tile_size / 2.0) * tile_scale; + let mut tile_position = tile_transform.translation.truncate() / tile_gap.0; + // The origine of the tile is the bottom center. + tile_position.y += (tile_size.y / 2.0) * tile_scale.y / tile_gap.0.y; - let distance_to_cursor = tile_position.distance(click_event.0); + let distance_to_cursor = tile_position.distance(click_position); if closest_position.is_none() || closest_position > Some(distance_to_cursor) { closest_entity = Some(tile_entity); @@ -99,7 +121,11 @@ fn select_closest_tile( } } if let Some(tile_entity) = closest_entity { - clicked_tile_event_writer.send(TileJustClicked(tile_entity.index())); + if current_entity.get_entity() == Some(tile_entity) { + *current_entity = SelectedTile::None; + } else { + *current_entity = SelectedTile::Tile(tile_entity); + } } } }