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

Added an example to iso_diamond example for handling tile clicks in respect to the 2d camera #529

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all 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
65 changes: 65 additions & 0 deletions examples/iso_diamond.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bevy::prelude::*;
use bevy::window::PrimaryWindow;
use bevy_ecs_tilemap::prelude::*;
mod helpers;

Expand Down Expand Up @@ -86,6 +87,69 @@ fn startup(mut commands: Commands, asset_server: Res<AssetServer>) {
});
}

/// handle_tile_click is a function designed for responding to the user clicking on a tile-map entity in a Bevy engine game.
///
/// When the user clicks with the left or right mouse button, the system will calculate the tile position from the cursor position, accounting for
/// the camera/perspective scale and transforms, and the map's location in the world space.
///
/// When the left or right mouse button has been just pressed, it increments or decrements, respectively, the current tile texture index for the tile.

/// If the cursor's position does not exist within the window, no action is taken.
///
/// # Errors
/// This function may panic if there is not exactly one camera entity or one primary window.
fn handle_tile_click(
mut commands: Commands,
q_windows: Query<&Window, With<PrimaryWindow>>,
q_cameras: Query<(&Camera, &Transform)>,
mut mouse_buttons: Res<ButtonInput<MouseButton>>,
mut q_tile_texture: Query<&mut TileTextureIndex>,
mut q_tilemap: Query<(&mut TileStorage, &mut TilemapSize, &mut TilemapGridSize, &mut TilemapType, &Transform)>) {

let delta = if mouse_buttons.just_pressed(MouseButton::Left) { 1i32 }
else if mouse_buttons.just_pressed(MouseButton::Right) { -1i32 }
else { 0 };

let (camera, camera_transform) = q_cameras.get_single().expect("Expected a single camera entity");
let window = q_windows.get_single().expect("Expected a single window");
match window.cursor_position() {
Some(position) => {
// Window size in pixels
let win_size = Vec2::new(window.width(), window.height());

// The cursor's position in Normalized Device Coordinates, ranging from (-1, -1) bottom left to (1, 1) top right.
let ndc_pos = ((position / win_size) * 2.0 - Vec2::new(1.0, 1.0) ) * Vec2::new(1.0, -1.0);

// Create a point in NDC with a depth of 0 (this is arbitrary and should be adjusted if your game isn't in a flat 2D plane).
let point_ndc = Vec3::new(ndc_pos.x, ndc_pos.y, 0.0);

//Apply the camera's projection matrix to the NDC
let camera_matrix_inverse = camera.projection_matrix().inverse();
let point_world = camera_matrix_inverse.transform_point3(point_ndc);

// Apply the camera's transformation.
let world_space_position = camera_transform.compute_matrix() * point_world.extend(1f32);

for (mut tile_storage, map_size, grid_size, map_type, map_transform) in q_tilemap.iter_mut() {
//convert world space to map space
let map_position = map_transform.compute_matrix().inverse() * world_space_position;

//use the map space point to file the tile
let tile_pos = TilePos::from_world_pos(&map_position.xy(), &map_size, &grid_size, &map_type).unwrap();
let tile_entity = tile_storage.get(&tile_pos).unwrap();
let tti = q_tile_texture.get_mut(tile_entity).unwrap();
let new_index = (7 + tti.0 as i32 + delta) % 7;

commands.entity(tile_entity).insert(TileTextureIndex(new_index as u32));
}

},
None => {
//Cursor is not inside window
}
}
}

fn main() {
App::new()
.add_plugins(
Expand All @@ -102,5 +166,6 @@ fn main() {
.add_plugins(TilemapPlugin)
.add_systems(Startup, startup)
.add_systems(Update, helpers::camera::movement)
.add_systems(Update, handle_tile_click)
.run();
}
Loading