From f0a987fddb60ad94b0fa1432f3fc30d445878b35 Mon Sep 17 00:00:00 2001 From: GarandPLG Date: Tue, 18 Nov 2025 22:37:28 +0100 Subject: [PATCH] Add player unit with basic selection and movement mechanics --- assets/mole_unit.png | Bin 0 -> 3223 bytes src/main.rs | 143 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 assets/mole_unit.png diff --git a/assets/mole_unit.png b/assets/mole_unit.png new file mode 100644 index 0000000000000000000000000000000000000000..8426ec6bce4c8366be1dad646655989fbcfeb312 GIT binary patch literal 3223 zcma)92{@GbA0Pk3&Y(q1yCl;%i@C@(nI>c0N60NQ%xg@T88gF-Bdv;ZluDA>R*TfS zb8C|hawno%a!)p!w%8~o`M*P}>%aT_pJ#qE@9+2d{J!`1`#zK83{9aj0{}EXj0NHlh$)fJq6CHjTtoms zqcaG|7gw(%5p*g6>0#i2bzqqT!F20rHn2O|(KRqSB+!J4B<_Hj^6{X6Fn~)z@WVnG z96X|*DVrLEcOhGTxD4(H$Y3s) zg~wocJRX{-k7lxI7@UcT2?nc&(bGeL3=}7d!KLs~433&e#EJ|uzzJm2SzJ1kfe^{0 z1TZ7G1SAr~5r112##$B5;C%2Nj01*GVPSA+Eap=(E11b;a)O!vaAg(#>LS3WfArxq zH6r9II+q^w4|Eao6&;MVgTudj5f=8DBOI&4R6i{C|rOHE&@^yt7m}1;ZQhZS3NyE7K`78)xqMxhgG%%lS&VY`k!nA zJXY^ZHdr523YYT#@K+;_7qM5Y0&DZ%P5OAroEgewgVupw=r3FQ5wbBicVaVx=%FCS zaj_yHY%I(TaVCa_C_OZ8nJda1-igi!LOsd!Fo3}UtBim&(E9@P`Uh}X_inJcKm{uT zMY+Y>gi&aK2c60dUX}In+#X=iz63-W3XKqzxEq5G=5$5>@*U5Q80a7ti}^&4*VmY+ zZ4jo*#e}z}bGS@))bi0vFYN}xS9UAgQ2KHcArQ-@gr@|GEFd6RY$i1#5TGsx0Tj1_ za+pC}9)%5<(ZDJqAkBh;=%B4p2z@jb?D)?F@qz(R%ohp#q)IR!Ou~rz`EQ#{F<)72 zx=i?F0D$*a&cML}PAJUkhypjOLk?ho)x!oySa((S2?#_io(`75SLug9v`%xq`(?Pe zgJ-H9A`CrOd_w$zG z$*1-#B-w4Dt}&qb$GA%OInI)Rpwz2)xlbx>YvGyo*$UZycM3F_Qnfm5EZ2G0x?Sl~ zun|G@g{HfjTDI?i3OFn^zS`oqtY1d0*Xr1yP`a3w49AI#k%hCE@FqQuS<=wB@1*#& zu(3@+m^ucWkjuI@E2QjncWvWscu8xsEk#z^iXBswS8wal+UHl;qTXzg)@JRDU0A9u zi;ivGUHE+3?9X&c{oKwWcq~(?`AH5XRyF=lIkeuyyJuq3*Haq29_(4@u3tyX1W*-g zo+x*}`8lzgW00q4dt2lI#TO;8N>H&{ZN$YsWJ*uXfT1_c zIw!*m=4*-n>G%OtnqKc8#Unh7|2?fMZyE+C&b>By5k1_vdE+hcgRSZ_j#P$^sdy&$ z&tnV&6b*$}l%A9+Sd9nH%hUvHcy&5N=lQKm)29lx7)8-H4!$0p;uBs8p{9v6oMcKz z<^JCgf+Fz*pDqX$z|?fNTg2M;J1S@-J;uIy@5zO5UhA*-u%7f;srY4hNKsv>9WIKr7_cHP^HFlSNo77^SvIhlV%%H7walhV@{IW zFXDpzt}BE+yGdjndwiyU;#vnRt9stFv?bjowY2d`(_Zi7%OmM;ncGXxoZGe$m0Ny4 zVRq3)-!SzLzDmO(heXmd6&Fg{o*A9?mkYNg;bZqm4L+nfqoy)+ldxiE?f3;8b@BwF z+`08Y!S|#N^_d7;hL?vpzGre>w3}RP#$)B&A*sWUpOeOIlad$tvP^?GH>~R36Oh@4 zpl^J)MvXz+UUlF?&b=<%5VLe`%^jM=Fp7MYT3y>g^3|+<#1B5{{es%5{NBGXDME&k z+5U!h%BQ*L;3Ey`*X<n$L0dhU1)D^}_Xe|?{TrX9bqL$l77RP90m4-#$*l?BK;zJFNH=kt!VClAQ_b08SwTWx z;*hGYu8!4^rjf(G3KN&YzT56f}-YC8gxpE zdZtgz7SLKruA6`#HMjyZAR^+vS4RHvWWqvjJo zQ~3LiKc3IpXoQp2zf4QEggRt$vU@G+u3or_bFNJ!-xwlI-k0ejYAR`P^}5nGR*DgE zZ)66dp|C^yt8II-F;1c1zWLe9;dyQJE>qY-3Y%Cnfr6m7@{{=&fB)b3r literal 0 HcmV?d00001 diff --git a/src/main.rs b/src/main.rs index 54f6e36..4051811 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,27 @@ const TILE_SIZE: TilemapTileSize = TilemapTileSize { y: TILE_HEIGHT, }; +#[derive(Component)] +struct Unit { + health: u32, + position: Vec2, + digging_power: u32, +} + +#[derive(Component)] +struct MoleUnit; + +#[derive(Component)] +struct Player; + +#[derive(Component)] +struct Selected; + +#[derive(Resource)] +struct BaseTilePositions { + positions: Vec, +} + fn startup(mut commands: Commands, asset_server: Res) { commands.spawn(Camera2d); @@ -42,10 +63,13 @@ fn startup(mut commands: Commands, asset_server: Res) { } } + let mut base_positions = Vec::new(); + for x in 0..3 { for y in 11..14 { if x < MAP_SIZE.x && y < MAP_SIZE.y { let tile_pos = TilePos { x, y }; + base_positions.push(tile_pos); let tile_entity = commands .spawn(TileBundle { position: tile_pos, @@ -62,6 +86,7 @@ fn startup(mut commands: Commands, asset_server: Res) { for y in 11..14 { if x < MAP_SIZE.x && y < MAP_SIZE.y { let tile_pos = TilePos { x, y }; + base_positions.push(tile_pos); let tile_entity = commands .spawn(TileBundle { position: tile_pos, @@ -74,6 +99,10 @@ fn startup(mut commands: Commands, asset_server: Res) { } } + commands.insert_resource(BaseTilePositions { + positions: base_positions, + }); + commands.entity(tilemap_entity).insert(TilemapBundle { grid_size: TILE_SIZE.into(), map_type: TilemapType::default(), @@ -99,6 +128,117 @@ fn startup(mut commands: Commands, asset_server: Res) { }); } +fn setup_player(mut commands: Commands, asset_server: Res) { + let tile_pos = TilePos { x: 1, y: 12 }; + let world_pos = tile_pos_to_world_pos(tile_pos); + + commands.spawn(( + Sprite { + image: asset_server.load("mole_unit.png"), + custom_size: Some(Vec2::new(TILE_WIDTH, TILE_HEIGHT)), + ..Default::default() + }, + Transform::from_translation(Vec3::new(world_pos.x, world_pos.y, 2.0)), + Player, + MoleUnit {}, + Unit { + health: 100, + position: world_pos, + digging_power: 5, + }, + )); +} + +fn tile_pos_to_world_pos(tile_pos: TilePos) -> Vec2 { + let half_map_width = (TILEMAP_WIDTH as f32 * TILE_WIDTH) / 2.0; + let half_map_height = (TILEMAP_HEIGHT as f32 * TILE_HEIGHT) / 2.0; + + Vec2::new( + (tile_pos.x as f32 * TILE_WIDTH) - half_map_width + (TILE_WIDTH / 2.0), + (tile_pos.y as f32 * TILE_HEIGHT) - half_map_height + (TILE_HEIGHT / 2.0), + ) +} + +fn world_pos_to_tile_pos(world_pos: Vec2) -> TilePos { + let half_map_width = (TILEMAP_WIDTH as f32 * TILE_WIDTH) / 2.0; + let half_map_height = (TILEMAP_HEIGHT as f32 * TILE_HEIGHT) / 2.0; + + let x = ((world_pos.x + half_map_width - (TILE_WIDTH / 2.0)) / TILE_WIDTH).floor() as u32; + let y = ((world_pos.y + half_map_height - (TILE_HEIGHT / 2.0)) / TILE_HEIGHT).floor() as u32; + + TilePos { x, y } +} + +fn handle_mouse_input( + mut commands: Commands, + mouse_button: Res>, + windows: Query<&Window>, + camera_q: Query<(&Camera, &GlobalTransform)>, + mut player_query: Query<(Entity, &mut Transform, &mut Unit), (With, With)>, + selected_query: Query, With, With)>, + base_tiles: Res, +) { + let Some(window) = windows.iter().next() else { + return; + }; + + let Some((camera, camera_transform)) = camera_q.iter().next() else { + return; + }; + + if let Some(cursor_position) = window.cursor_position() { + if let Ok(world_pos) = camera.viewport_to_world_2d(camera_transform, cursor_position) { + if mouse_button.just_pressed(MouseButton::Left) { + for entity in selected_query.iter() { + commands.entity(entity).remove::(); + } + + for (entity, transform, _) in player_query.iter() { + let distance = transform.translation.truncate().distance(world_pos); + if distance < TILE_WIDTH / 2.0 { + commands.entity(entity).insert(Selected); + println!("Zaznaczono jednostkę gracza"); + break; + } + } + } + + if mouse_button.just_pressed(MouseButton::Right) { + if let Some(selected_entity) = selected_query.iter().next() { + let target_tile_pos = world_pos_to_tile_pos(world_pos); + + if base_tiles.positions.contains(&target_tile_pos) { + if let Ok((_, mut transform, mut unit)) = + player_query.get_mut(selected_entity) + { + let new_world_pos = tile_pos_to_world_pos(target_tile_pos); + transform.translation.x = new_world_pos.x; + transform.translation.y = new_world_pos.y; + unit.position = new_world_pos; + println!("Przeniesiono jednostkę na pozycję {:?}", target_tile_pos); + } + } else { + println!("Nie można się przemieścić na ten tile - to nie jest base tile!"); + } + } + } + } + } +} + +fn highlight_selected_unit( + mut gizmos: Gizmos, + selected_query: Query<&Transform, (With, With)>, +) { + for transform in selected_query.iter() { + gizmos.circle_2d( + transform.translation.truncate(), + TILE_WIDTH / 2.0 + 2.0, + Color::srgb(1.0, 1.0, 0.0), + ); + } +} + fn main() { App::new() .add_plugins( @@ -118,6 +258,7 @@ fn main() { .set(ImagePlugin::default_nearest()), ) .add_plugins(TilemapPlugin) - .add_systems(Startup, startup) + .add_systems(Startup, (startup, setup_player)) + .add_systems(Update, (handle_mouse_input, highlight_selected_unit)) .run(); }