From 7c5dbd3a9f9051abc3b11210fd68819cde3b8d23 Mon Sep 17 00:00:00 2001 From: Sofia Date: Sun, 19 Jul 2026 22:49:21 +0300 Subject: [PATCH] Add shooting --- godot/project.godot | 5 ++ godot/scenes/player/local_player.tscn | 8 ++- godot/scenes/player/remote_player.tscn | 8 ++- godot/scenes/player/soldier_m.tscn | 29 +++++------ rust/src/game_manager.rs | 31 +++++++++++ rust/src/net/network_manager.rs | 24 +++++++++ rust/src/player.rs | 71 ++++++++++++++++++++++++-- 7 files changed, 155 insertions(+), 21 deletions(-) diff --git a/godot/project.godot b/godot/project.godot index c4453c5..9824a1d 100644 --- a/godot/project.godot +++ b/godot/project.godot @@ -73,6 +73,11 @@ jump={ "events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null) ] } +shoot={ +"deadzone": 0.2, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} [physics] diff --git a/godot/scenes/player/local_player.tscn b/godot/scenes/player/local_player.tscn index 289c465..5edd86d 100644 --- a/godot/scenes/player/local_player.tscn +++ b/godot/scenes/player/local_player.tscn @@ -1,14 +1,16 @@ [gd_scene format=3 uid="uid://ct70bpbca8one"] [ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_jd651"] +[ext_resource type="AudioStream" uid="uid://xxpkjhaovyd" path="res://assets/LaserWithRecoveryEdited.ogg" id="2_ywmwa"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"] -[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh")] +[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "sound_emitter")] look_sensitivity = 1.5 camera = NodePath("camera_3d") move_speed = 5.0 soldier_mesh = NodePath("soldier_m") +sound_emitter = NodePath("sound_emitter") collision_mask = 2 [node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418] @@ -22,3 +24,7 @@ visible = false [node name="collision_shape_3d2" type="CollisionShape3D" parent="." unique_id=442150782] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0310049, 0) shape = SubResource("CapsuleShape3D_oh8vq") + +[node name="sound_emitter" type="AudioStreamPlayer3D" parent="." unique_id=292990328] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8420726, 0) +stream = ExtResource("2_ywmwa") diff --git a/godot/scenes/player/remote_player.tscn b/godot/scenes/player/remote_player.tscn index f0f16c0..15f6edb 100644 --- a/godot/scenes/player/remote_player.tscn +++ b/godot/scenes/player/remote_player.tscn @@ -1,12 +1,14 @@ [gd_scene format=3 uid="uid://kfxc0migw80o"] [ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_e2ekk"] +[ext_resource type="AudioStream" uid="uid://xxpkjhaovyd" path="res://assets/LaserWithRecoveryEdited.ogg" id="2_orxjf"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"] -[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh")] +[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "sound_emitter")] move_speed = 5.0 soldier_mesh = NodePath("soldier_m") +sound_emitter = NodePath("sound_emitter") collision_mask = 2 [node name="soldier_m" parent="." unique_id=281995630 instance=ExtResource("1_e2ekk")] @@ -15,3 +17,7 @@ transform = Transform3D(-0.5, 0, -4.371139e-08, 0, 0.5, 0, 4.371139e-08, 0, -0.5 [node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1110995513] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0310049, 0) shape = SubResource("CapsuleShape3D_1cgct") + +[node name="sound_emitter" type="AudioStreamPlayer3D" parent="." unique_id=574144461] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.18387973, 1.6770729, -0.3557726) +stream = ExtResource("2_orxjf") diff --git a/godot/scenes/player/soldier_m.tscn b/godot/scenes/player/soldier_m.tscn index 98c317e..0bad915 100644 --- a/godot/scenes/player/soldier_m.tscn +++ b/godot/scenes/player/soldier_m.tscn @@ -2,7 +2,6 @@ [ext_resource type="PackedScene" uid="uid://cw7duhhjebypt" path="res://scenes/player/raygun.tscn" id="1_a50o4"] [ext_resource type="PackedScene" uid="uid://ncxcmgdit2j1" path="res://mesh/soldier_m.tscn" id="1_sxefq"] -[ext_resource type="PackedScene" uid="uid://cg81784ct8gf5" path="res://mesh/raygun.tscn" id="3_jbny0"] [sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_a50o4"] animation = &"Soldier|StrafeLeft" @@ -56,10 +55,10 @@ look_at = NodePath("look_at_root") [node name="Skeleton3D" parent="SoldierM/Soldier" parent_id_path=PackedInt32Array(1868587353, 803584260) index="0" unique_id=1574145981] bones/0/position = Vector3(0, 0, 0.00071418716) bones/1/position = Vector3(0, 0, -0.007) -bones/1/rotation = Quaternion(0.70569277, 0, 0, 0.7085179) +bones/1/rotation = Quaternion(0.6933472, 0, 0, 0.7206036) bones/1/scale = Vector3(1, 1, 1) bones/2/position = Vector3(0.002, 3.469447e-18, -1.4901118e-10) -bones/2/rotation = Quaternion(0.9509405, 2.0995262e-08, 2.3608855e-08, -0.30937394) +bones/2/rotation = Quaternion(0.94524616, 2.1414793e-08, 2.3228983e-08, -0.3263583) bones/2/scale = Vector3(1, 1, 1) bones/3/position = Vector3(0, 0.0069999984, 5.169879e-25) bones/3/scale = Vector3(1, 0.99999994, 1) @@ -67,7 +66,7 @@ bones/4/position = Vector3(-2.39752e-11, 0.010049875, -1.4156722e-10) bones/4/rotation = Quaternion(0.73982674, -2.6881349e-08, 7.0005948e-09, 0.67279744) bones/4/scale = Vector3(1, 0.99999994, 0.99999994) bones/6/position = Vector3(-0.002, 3.469447e-18, -1.4901205e-10) -bones/6/rotation = Quaternion(0.99916035, 1.7885682e-08, 1.893182e-08, 0.04097233) +bones/6/rotation = Quaternion(0.99965113, 1.8159536e-08, 1.8669295e-08, 0.026414612) bones/6/scale = Vector3(1, 1, 1) bones/7/position = Vector3(0, 0.0069999984, -5.169879e-25) bones/7/rotation = Quaternion(-0.21973656, 4.264305e-08, 9.604991e-09, 0.9755593) @@ -76,33 +75,33 @@ bones/8/position = Vector3(-2.3975525e-11, 0.010049875, -4.6138777e-11) bones/8/rotation = Quaternion(0.86758894, -7.867721e-09, 3.036851e-08, 0.4972821) bones/8/scale = Vector3(1, 0.99999994, 0.99999994) bones/10/position = Vector3(0, 0.009, 0) -bones/10/rotation = Quaternion(-0.1704422, -0.13139531, 0.021929594, 0.9763216) +bones/10/rotation = Quaternion(-0.15285265, -0.13164668, 0.01958379, 0.9792455) bones/10/scale = Vector3(1, 1, 1) bones/11/position = Vector3(6.8186457e-17, 0.008, 0.001) -bones/11/rotation = Quaternion(0.005668696, 1.1375248e-05, -0.0015512996, 0.9999828) +bones/11/rotation = Quaternion(0.064451575, 0.0001293997, -0.017637832, 0.99776495) bones/11/scale = Vector3(1, 1, 1) bones/12/position = Vector3(-2.2285185e-16, 0.0035, 0.0015000002) bones/12/rotation = Quaternion(-0.70710677, 0, 0, 0.70710677) bones/12/scale = Vector3(1, 1, 1) bones/14/position = Vector3(0.005, 0.005, -1.7336413e-21) -bones/14/rotation = Quaternion(0.88285106, 0.032361757, 0.43712845, -0.16865772) +bones/14/rotation = Quaternion(0.8961373, 0.033810798, 0.43093914, -0.10043051) bones/14/scale = Vector3(1, 0.99999994, 1) bones/15/position = Vector3(-1.3005262e-15, 0.0050000004, -6.938894e-18) -bones/15/rotation = Quaternion(1.0160434e-08, -7.0616895e-09, 0.92007947, 0.39173177) +bones/15/rotation = Quaternion(1.0371126e-08, -6.748454e-09, 0.9316012, 0.36348197) bones/15/scale = Vector3(1, 1, 1) bones/16/position = Vector3(7.632945e-11, 0.007071071, 6.938894e-18) -bones/16/rotation = Quaternion(0.027662799, -0.041891776, -0.18596037, 0.981274) +bones/16/rotation = Quaternion(0.0037409808, -0.10074904, -0.18467231, 0.9776154) bones/16/scale = Vector3(0.99999994, 0.9999999, 1) bones/18/position = Vector3(-0.005, 0.005, -1.7303326e-21) -bones/18/rotation = Quaternion(0.64603364, 0.20885898, -0.09923112, -0.7274418) +bones/18/rotation = Quaternion(0.6575101, 0.16476046, -0.1328446, -0.7231091) bones/18/scale = Vector3(1, 0.99999994, 1) bones/19/position = Vector3(-1.3005262e-15, 0.0050000004, -6.938894e-18) -bones/19/rotation = Quaternion(-1.7631736e-08, -3.747539e-08, -0.17163937, 0.98515993) +bones/19/rotation = Quaternion(-2.1579417e-08, -3.5349842e-08, -0.2771271, 0.9608333) bones/19/scale = Vector3(1, 1, 1) bones/20/position = Vector3(-2.2286711e-10, 0.007071072, 0) -bones/20/rotation = Quaternion(-0.13869229, -0.45811948, -0.17229414, 0.8609331) +bones/20/rotation = Quaternion(-0.10949359, -0.472547, -0.13018106, 0.86473316) bones/20/scale = Vector3(1, 0.9999999, 1) -bones/22/position = Vector3(0.012243621, -0.0085772155, 0.0022597443) +bones/22/position = Vector3(0.010811842, -0.0085772155, 0.0026515652) bones/22/rotation = Quaternion(3.090862e-08, 0.70710677, 0.70710677, 3.090862e-08) bones/22/scale = Vector3(1, 1, 1) bones/24/position = Vector3(-0.011000002, 0.0050000013, 0.0070000007) @@ -151,7 +150,7 @@ origin_from = 2 origin_external_node = NodePath("../../../../look_at_root") [node name="bone_attachment_3d" type="BoneAttachment3D" parent="." unique_id=1964353847] -transform = Transform3D(-31.74573, 3.559949, -94.760414, -86.96872, 38.738197, 30.590748, 37.797493, 92.12316, -9.201678, -0.47878417, 3.3534346, 0.7443533) +transform = Transform3D(-35.56741, 3.792272, -93.38403, -83.20849, 44.2147, 33.48737, 42.559406, 89.614044, -12.570532, -0.4718982, 3.3932464, 0.73897976) bone_name = "HAND.R_end" bone_idx = 17 use_external_skeleton = true @@ -160,8 +159,6 @@ external_skeleton = NodePath("../SoldierM/Soldier/Skeleton3D") [node name="hand" type="Node3D" parent="bone_attachment_3d" unique_id=171636900] transform = Transform3D(0.0039180024, -0.013382489, -0.0055279233, 0.00012702314, 0.005758277, -0.013850107, 0.014478719, 0.0035708423, 0.0016173583, 0.003051471, -0.0019010007, -0.002960747) -[node name="Raygun" parent="bone_attachment_3d/hand" unique_id=1928455392 instance=ExtResource("3_jbny0")] - [node name="animation_tree" type="AnimationTree" parent="." unique_id=1221968603] root_node = NodePath("../SoldierM") tree_root = SubResource("AnimationNodeBlendTree_kgpx5") diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index bed9f14..d0cf691 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -331,6 +331,20 @@ impl Game { } } } + + pub fn handle_shoot( + &mut self, + player_id: u16, + transform: NetPlayerTransform, + look_up: f32, + deal_damage: bool, + ) -> bool { + if let Some(player) = self.find_player_mut(player_id) { + player.try_shoot(transform, look_up, deal_damage) + } else { + false + } + } } #[derive(Clone, Debug)] @@ -415,6 +429,23 @@ impl Player { character.dyn_bind_mut().apply_look_up(rot); } } + + pub fn try_shoot( + &mut self, + transform: NetPlayerTransform, + look_up: f32, + deal_damage: bool, + ) -> bool { + if let Some(character) = &mut self.character { + character + .dyn_bind_mut() + .apply_rotation(transform.rotation.into()); + character.dyn_bind_mut().apply_look_up(look_up); + character.dyn_bind_mut().try_shoot(true) + } else { + false + } + } } #[derive(Debug, Serialize, Deserialize, Clone)] diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index d7669c2..6ac4b9c 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -227,6 +227,12 @@ impl INode for NetworkManager { game.bind_mut().handle_jump(player_id); } } + Package::Shoot(player_id, transform, look_up) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut() + .handle_shoot(player_id, transform, look_up, false); + } + } _ => {} }, } @@ -378,6 +384,23 @@ impl INode for NetworkManager { } } } + Package::Shoot(_, transform, look_up) => { + if let Some(game) = &mut Game::singleton() { + let player = game + .bind() + .find_player_by_addr(&conn.address) + .cloned(); + if let Some(player) = player { + if game.bind_mut().handle_shoot( + player.id, transform, look_up, true, + ) { + peer.broadcast_reliable(Package::Shoot( + player.id, transform, look_up, + )); + } + } + } + } _ => {} }, } @@ -508,6 +531,7 @@ pub enum Package { Sync(HashMap), SelfSync(SyncPackage), Jump(u16), + Shoot(u16, NetPlayerTransform, f32), } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/rust/src/player.rs b/rust/src/player.rs index 3490b89..d01c5d4 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -2,8 +2,8 @@ use std::f32::consts::PI; use godot::{ classes::{ - Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent, InputEventMouseMotion, - input::MouseMode, + AudioStreamPlayer3D, Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent, + InputEventMouseMotion, input::MouseMode, }, obj::WithBaseField, prelude::*, @@ -12,7 +12,11 @@ use serde::{Deserialize, Serialize}; use crate::{ net::{ - network_manager::{NetworkManager, Package::Jump, PeerKind}, + network_manager::{ + NetworkManager, + Package::{Jump, Shoot}, + PeerKind, + }, util::NetVector3, }, soldier_mesh::SoldierMesh, @@ -38,6 +42,8 @@ pub trait IPlayer { fn get_look_up(&self) -> f32; fn get_transform(&self) -> NetPlayerTransform; fn jump(&mut self); + fn try_shoot(&mut self, deal_damage: bool) -> bool; + fn shoot_fx(&mut self); } pub trait PlayerMovement { @@ -75,6 +81,8 @@ pub struct LocalPlayer { move_speed: f32, #[export] soldier_mesh: Option>, + #[export] + sound_emitter: Option>, pub player_id: Option, @@ -82,6 +90,8 @@ pub struct LocalPlayer { y_speed: f32, look_up: f32, + shoot_cd: f64, + locked: bool, base: Base, @@ -144,6 +154,18 @@ impl IPlayer for LocalPlayer { } fn apply_look_up(&mut self, _look: f32) {} + + fn try_shoot(&mut self, deal_damage: bool) -> bool { + if self.shoot_cd <= 0. { + self.shoot_fx(); + self.shoot_cd = 0.2; + true + } else { + false + } + } + + fn shoot_fx(&mut self) {} } #[godot_api] @@ -170,6 +192,8 @@ impl ICharacterBody3D for LocalPlayer { } fn process(&mut self, delta: f64) { + self.shoot_cd -= delta; + let input_direction = if self.locked { let input = Input::singleton(); @@ -195,6 +219,25 @@ impl ICharacterBody3D for LocalPlayer { fn input(&mut self, event: Gd) { if self.locked { + if event.is_action_pressed("shoot") { + if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { + match peer { + PeerKind::Client(peer, addr) => { + peer.send_reliable(addr, Shoot(0, self.get_transform(), self.look_up)); + } + PeerKind::Server(peer, _) => { + if self.try_shoot(true) { + peer.broadcast_reliable(Shoot( + 0, + self.get_transform(), + self.look_up, + )); + } + } + } + } + } + if let Ok(event) = event.try_cast::() { let x = event.get_relative().x * 0.001 * self.look_sensitivity; let y = event.get_relative().y * 0.001 * self.look_sensitivity; @@ -232,6 +275,8 @@ pub struct RemotePlayer { move_speed: f32, #[export] soldier_mesh: Option>, + #[export] + sound_emitter: Option>, pub player_id: Option, @@ -239,6 +284,8 @@ pub struct RemotePlayer { y_speed: f32, look_up: f32, + shoot_cd: f64, + base: Base, } @@ -297,6 +344,22 @@ impl IPlayer for RemotePlayer { fn apply_look_up(&mut self, look: f32) { self.look_up = look; } + + fn try_shoot(&mut self, deal_damage: bool) -> bool { + if self.shoot_cd <= 0. { + self.shoot_fx(); + self.shoot_cd = 0.2; + true + } else { + false + } + } + + fn shoot_fx(&mut self) { + if let Some(emitter) = &mut self.sound_emitter { + emitter.play(); + } + } } #[godot_api] @@ -310,6 +373,8 @@ impl ICharacterBody3D for RemotePlayer { fn process(&mut self, delta: f64) { self.player_update(delta); + self.shoot_cd -= delta; + if let Some(mesh) = &mut self.soldier_mesh { mesh.bind_mut() .update_movement(Vector2::new(self.movement_dir.x, -self.movement_dir.z));