diff --git a/assets/pawn.aseprite b/assets/pawn.aseprite new file mode 100644 index 0000000..0d7af7f Binary files /dev/null and b/assets/pawn.aseprite differ diff --git a/assets/pawn.png b/assets/pawn.png new file mode 100644 index 0000000..4ac4ae5 Binary files /dev/null and b/assets/pawn.png differ diff --git a/src/main.rs b/src/main.rs index bf556b0..86976c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,9 @@ use bevy::{ diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, input::mouse::MouseMotion, + math::Vec4Swizzles, prelude::*, + render::camera::RenderTarget, }; use bevy_ecs_tilemap::prelude::*; use defs::SurfaceDef; @@ -35,6 +37,9 @@ const TERRAINS: [SurfaceDef; 3] = [ }, ]; +#[derive(Component)] +struct PlayerCharacter {} + #[derive(Component, Clone)] struct TileTerrain { terrain_id: usize, @@ -46,9 +51,21 @@ impl TileTerrain { } } +#[derive(Component, Default, Clone, Copy, Debug)] +pub struct PawnPos { + pub x: u32, + pub y: u32, +} + +#[derive(Component, Default, Clone, Copy, Debug)] +pub struct PawnDest { + pub x: u32, + pub y: u32, +} + #[derive(Bundle, Default)] struct PawnBundle { - position: TilePos, + position: PawnPos, sprite: Sprite, transform: Transform, global_transform: GlobalTransform, @@ -62,7 +79,7 @@ fn make_ground_layer( tilemap_size: TilemapSize, texture_handle: Handle, tile_size: TilemapTileSize, -) { +) -> Entity { let mut tile_storage = TileStorage::empty(tilemap_size); let tilemap_entity = commands.spawn_empty().id(); @@ -99,41 +116,59 @@ fn make_ground_layer( transform: get_tilemap_center_transform(&tilemap_size, &grid_size, &map_type, 0.0), ..Default::default() }); + tilemap_entity } -fn make_pawn(commands: &mut Commands, texture_handle: Handle, tile_size: TilemapTileSize) { - commands.spawn(PawnBundle { - transform: Transform::from_xyz(0.0, 0.0, 1.0), - texture: texture_handle, - sprite: Sprite { - rect: Option::Some(Rect::new( - 3. * tile_size.x, - 4. * tile_size.y, - 4. * tile_size.x, - 5. * tile_size.y, - )), +fn make_pawn( + commands: &mut Commands, + tilemap_entity: Entity, + texture_handle: Handle, + tile_size: &TilemapTileSize, + map_size: &TilemapSize, +) { + let pos = PawnPos { + x: map_size.x / 2, + y: map_size.y / 2, + }; + commands + .spawn(PawnBundle { + position: pos, + transform: Transform::from_xyz( + (pos.x as f32) * tile_size.x, + (pos.y as f32) * tile_size.y, + 1.0, + ), + texture: texture_handle, + visibility: Visibility { is_visible: true }, ..Default::default() - }, - visibility: Visibility { is_visible: true }, - ..Default::default() - }); + }) + .insert(PlayerCharacter {}) + .set_parent(tilemap_entity); + info!("Pawn at {:?}", pos); } fn startup(mut commands: Commands, asset_server: Res) { commands.spawn(Camera2dBundle::default()); - let texture_handle = asset_server.load("tileset.png"); + let tileset_texture_handle = asset_server.load("tileset.png"); + let pawn_texture_handle: Handle = asset_server.load("pawn.png"); let tilemap_size = TilemapSize { x: 320, y: 320 }; let tile_size = TilemapTileSize { x: 32.0, y: 32.0 }; - make_ground_layer( + let tilemap_entity = make_ground_layer( &mut commands, tilemap_size, - texture_handle.clone(), + tileset_texture_handle, tile_size, ); - make_pawn(&mut commands, texture_handle, tile_size); + make_pawn( + &mut commands, + tilemap_entity, + pawn_texture_handle, + &tile_size, + &tilemap_size, + ); } fn mouse_motion( @@ -151,6 +186,70 @@ fn mouse_motion( } } +fn pawn_control( + mut commands: Commands, + wnds: Res, + buttons: Res>, + query: Query>, + camera_q: Query<(&GlobalTransform, &Camera)>, + tilemap_q: Query<(&TilemapSize, &TilemapGridSize, &TilemapType, &Transform)>, +) { + if buttons.just_released(MouseButton::Right) { + let (cam_gt, cam) = camera_q.single(); + let wnd = if let RenderTarget::Window(id) = cam.target { + wnds.get(id).unwrap() + } else { + wnds.get_primary().unwrap() + }; + + if let Some(screen_pos) = wnd.cursor_position() { + query.for_each(|entity| { + if let Some(world_ray) = cam.viewport_to_world(cam_gt, screen_pos) { + let (map_size, map_grid_size, map_type, map_t) = tilemap_q.single(); + + let tilemap_pos = (map_t.compute_matrix().inverse() + * Vec4::from((world_ray.origin, 1.0))) + .xy(); + info!("WP {:?} {:?}", world_ray.origin, tilemap_pos); + if let Some(tile_pos) = + TilePos::from_world_pos(&tilemap_pos, map_size, map_grid_size, map_type) + { + info!("{:?}", tile_pos); + commands.entity(entity).insert(PawnDest { + x: tile_pos.x, + y: tile_pos.y, + }); + } + } + }); + } + } +} + +fn pawn_motion( + mut commands: Commands, + mut pawn_q: Query<(Entity, &mut PawnPos, &mut Transform, Option<&PawnDest>)>, + tilemap_q: Query<(&TilemapGridSize, &TilemapTileSize, &TilemapType)>, +) { + let (map_grid_size, map_tile_size, map_type) = tilemap_q.single(); + pawn_q.for_each_mut(|(entity, mut pos, mut transform, dest)| match dest { + Some(d) => { + pos.x = d.x; + pos.y = d.y; + transform.translation = Vec3::from(( + (pos.x as f32) * map_tile_size.x, + (pos.y as f32) * map_tile_size.y, + 1.0, + )); + commands.entity(entity).remove::(); + } + None => { + let world_pos = TilePos::new(pos.x, pos.y).center_in_world(map_grid_size, map_type); + transform.translation.x = world_pos.x; + transform.translation.y = world_pos.y; + } + }) +} fn main() { App::new() @@ -172,5 +271,7 @@ fn main() { .add_plugin(TilemapPlugin) .add_startup_system(startup) .add_system(mouse_motion) + .add_system(pawn_control) + .add_system(pawn_motion) .run(); }