diff --git a/godot/scenes/player/local_player.tscn b/godot/scenes/player/local_player.tscn index a3500fa..57c3cc5 100644 --- a/godot/scenes/player/local_player.tscn +++ b/godot/scenes/player/local_player.tscn @@ -1,17 +1,20 @@ [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="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/splorch.tscn" id="2_ywmwa"] [sub_resource type="Environment" id="Environment_3nx84"] glow_enabled = true [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", "collider", "splorch")] look_sensitivity = 1.5 camera = NodePath("camera_3d") move_speed = 5.0 soldier_mesh = NodePath("soldier_m") +collider = NodePath("collision_shape_3d2") +splorch = NodePath("splorch") health = 100 collision_mask = 4 @@ -27,3 +30,6 @@ transform = Transform3D(-0.5, 0, -4.371139e-08, 0, 0.5, 0, 4.371139e-08, 0, -0.5 [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="splorch" parent="." unique_id=986677517 instance=ExtResource("2_ywmwa")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.16157162, 1.4223524, 0) diff --git a/godot/scenes/player/remote_player.tscn b/godot/scenes/player/remote_player.tscn index c9437c8..f4846ae 100644 --- a/godot/scenes/player/remote_player.tscn +++ b/godot/scenes/player/remote_player.tscn @@ -1,12 +1,15 @@ [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="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/splorch.tscn" 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", "collider", "splorch")] move_speed = 5.0 soldier_mesh = NodePath("soldier_m") +collider = NodePath("collision_shape_3d") +splorch = NodePath("gpu_particles_3d") health = 100 collision_layer = 2 collision_mask = 4 @@ -17,3 +20,6 @@ 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="gpu_particles_3d" parent="." unique_id=986677517 instance=ExtResource("2_orxjf")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.4540546, 0) diff --git a/godot/scenes/player/splorch.tscn b/godot/scenes/player/splorch.tscn new file mode 100644 index 0000000..b96b667 --- /dev/null +++ b/godot/scenes/player/splorch.tscn @@ -0,0 +1,34 @@ +[gd_scene format=3 uid="uid://cl66unms2gim0"] + +[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_1cgct"] +particle_flag_align_y = true +direction = Vector3(0, 1, 0) +spread = 90.0 +initial_velocity_min = 2.0 +initial_velocity_max = 5.0 + +[sub_resource type="Curve" id="Curve_yli5f"] +_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(0.08643617, 1), -3.6585922, -3.6585922, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0] +point_count = 3 + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dmbod"] +albedo_color = Color(0.44894964, 1.3055467e-06, 9.62615e-08, 1) +use_particle_trails = true + +[sub_resource type="TubeTrailMesh" id="TubeTrailMesh_wwb7k"] +material = SubResource("StandardMaterial3D_dmbod") +radius = 0.1 +radial_steps = 20 +section_length = 0.1 +section_rings = 10 +curve = SubResource("Curve_yli5f") + +[node name="gpu_particles_3d" type="GPUParticles3D" unique_id=986677517] +emitting = false +amount = 20 +one_shot = true +explosiveness = 0.78 +trail_enabled = true +trail_lifetime = 0.5 +process_material = SubResource("ParticleProcessMaterial_1cgct") +draw_pass_1 = SubResource("TubeTrailMesh_wwb7k") diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index d30c71d..523fb2e 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -14,7 +14,7 @@ use crate::{ }, util::NetVector3, }, - player::{IPlayer, NetPlayerTransform}, + player::{IPlayer, LocalPlayer, NetPlayerTransform, RemotePlayer}, }; pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; @@ -117,6 +117,11 @@ impl INode for Game { PeerKind::Server(peer, _) => { let mut sync_data = HashMap::new(); for player in &self.players { + if let Some(character) = &player.character { + if character.dyn_bind().is_dead() { + continue; + } + } if let (Some(dir), Some(look_up), Some(transform)) = ( player.get_move_dir(), player.get_look_up(), @@ -266,14 +271,38 @@ impl Game { peer.send_reliable(to, Package::MapLoaded); } else { self.run_deferred(|s| { - for player in &mut s.players { - if let Some(map) = &mut s.current_map { - let character = map.bind_mut().spawn_player( - player, + for player in s.players.clone() { + let player_id = player.id; + if let Some(mut map) = s.current_map.clone() { + let mut character = map.bind_mut().spawn_player( + &player, player.id == s.self_id.unwrap_or(0), None, ); - player.character = character; + + if let Some(character) = &mut character { + if let Ok(mut local_player) = + character.clone().try_cast::() + { + local_player + .bind_mut() + .signals() + .on_die() + .connect_other(s, move |s| s.on_death(player_id)); + } else if let Ok(mut local_player) = + character.clone().try_cast::() + { + local_player + .bind_mut() + .signals() + .on_die() + .connect_other(s, move |s| s.on_death(player_id)); + } + } + + if let Some(player) = s.find_player_mut(player_id) { + player.character = character; + } } } }); @@ -351,6 +380,10 @@ impl Game { false } } + + pub fn on_death(&mut self, player_id: u16) { + godot_print!("Player {} has died!", player_id); + } } #[derive(Clone, Debug)] @@ -448,7 +481,7 @@ impl Player { .dyn_bind_mut() .apply_rotation(transform.rotation.into()); character.dyn_bind_mut().apply_look_up(look_up); - character.dyn_bind_mut().try_shoot(to, true) + character.dyn_bind_mut().try_shoot(to, deal_damage) } else { false } diff --git a/rust/src/player.rs b/rust/src/player.rs index 8b967f5..09dd8ad 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -2,8 +2,9 @@ use std::{f32::consts::PI, ops::Neg}; use godot::{ classes::{ - AudioStreamPlayer3D, Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent, - InputEventMouseMotion, PhysicsRayQueryParameters3D, input::MouseMode, + AudioStreamPlayer3D, Camera3D, CharacterBody3D, CollisionShape3D, GpuParticles3D, + ICharacterBody3D, Input, InputEvent, InputEventMouseMotion, PhysicsRayQueryParameters3D, + input::MouseMode, }, obj::WithBaseField, prelude::*, @@ -45,6 +46,8 @@ pub trait IPlayer { fn jump(&mut self); fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool; fn take_damage(&mut self, damage: i32); + fn is_dead(&self) -> bool; + fn kill(&mut self); } pub trait PlayerMovement { @@ -83,6 +86,10 @@ pub struct LocalPlayer { #[export] soldier_mesh: Option>, #[export] + collider: Option>, + #[export] + splorch: Option>, + #[export] health: i32, pub player_id: Option, @@ -94,6 +101,8 @@ pub struct LocalPlayer { shoot_cd: f64, + is_dead: bool, + locked: bool, base: Base, @@ -158,6 +167,10 @@ impl IPlayer for LocalPlayer { fn apply_look_up(&mut self, _look: f32) {} fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool { + if self.is_dead { + return false; + } + if self.shoot_cd <= 0. { let rid = self.base().get_rid(); if let Some(weapon) = &mut self.weapon { @@ -171,8 +184,31 @@ impl IPlayer for LocalPlayer { } fn take_damage(&mut self, damage: i32) { - godot_print!("Took damage!"); self.health -= damage; + if self.health <= 0 { + self.kill(); + } + } + + fn is_dead(&self) -> bool { + self.is_dead + } + + fn kill(&mut self) { + self.signals().on_die().emit(); + if let Some(mut mesh) = self.soldier_mesh.take() { + mesh.queue_free(); + } + if let Some(mut weapon) = self.weapon.take() { + weapon.queue_free(); + } + if let Some(mut collider) = self.collider.take() { + collider.queue_free(); + } + if let Some(splorch) = &mut self.splorch { + splorch.set_emitting(true); + } + self.is_dead = true; } } @@ -288,7 +324,11 @@ impl ICharacterBody3D for LocalPlayer { } } +#[godot_api] impl LocalPlayer { + #[signal] + pub fn on_die(); + fn set_lock(&mut self, locked: bool) { self.locked = locked; if self.locked { @@ -307,6 +347,10 @@ pub struct RemotePlayer { #[export] soldier_mesh: Option>, #[export] + collider: Option>, + #[export] + splorch: Option>, + #[export] health: i32, pub player_id: Option, @@ -316,6 +360,8 @@ pub struct RemotePlayer { y_speed: f32, look_up: f32, + is_dead: bool, + shoot_cd: f64, base: Base, @@ -378,6 +424,10 @@ impl IPlayer for RemotePlayer { } fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool { + if self.is_dead { + return false; + } + if self.shoot_cd <= 0. { let rid = self.base().get_rid(); if let Some(weapon) = &mut self.weapon { @@ -391,8 +441,31 @@ impl IPlayer for RemotePlayer { } fn take_damage(&mut self, damage: i32) { - godot_print!("Took damage!"); self.health -= damage; + if self.health <= 0 { + self.kill(); + } + } + + fn is_dead(&self) -> bool { + self.is_dead + } + + fn kill(&mut self) { + self.signals().on_die().emit(); + if let Some(mut mesh) = self.soldier_mesh.take() { + mesh.queue_free(); + } + if let Some(mut weapon) = self.weapon.take() { + weapon.queue_free(); + } + if let Some(mut collider) = self.collider.take() { + collider.queue_free(); + } + if let Some(splorch) = &mut self.splorch { + splorch.set_emitting(true); + } + self.is_dead = true; } } @@ -417,3 +490,9 @@ impl ICharacterBody3D for RemotePlayer { } } } + +#[godot_api] +impl RemotePlayer { + #[signal] + pub fn on_die(); +} diff --git a/rust/src/weapon.rs b/rust/src/weapon.rs index f0c0b45..953fe3d 100644 --- a/rust/src/weapon.rs +++ b/rust/src/weapon.rs @@ -55,7 +55,6 @@ impl Weapon for Raygun { } if deal_damage && let Some(target) = target { - godot_print!("{}", target.collider); if let Ok(mut player) = target.collider.try_dynify::() { player.dyn_bind_mut().take_damage(100); }