diff --git a/godot/scenes/misc/ball.tscn b/godot/scenes/misc/ball.tscn index ac432d4..3a383b8 100644 --- a/godot/scenes/misc/ball.tscn +++ b/godot/scenes/misc/ball.tscn @@ -18,6 +18,8 @@ material = SubResource("StandardMaterial3D_3g557") [node name="ball" type="Ball" unique_id=816748600] collision_layer = 4 collision_mask = 7 +contact_monitor = true +max_contacts_reported = 10 [node name="mesh_instance_3d" type="MeshInstance3D" parent="." unique_id=2076561614] mesh = SubResource("SphereMesh_1cgct") diff --git a/rust/src/ball.rs b/rust/src/ball.rs index 022a23d..bbbfa5d 100644 --- a/rust/src/ball.rs +++ b/rust/src/ball.rs @@ -1,6 +1,9 @@ -use godot::{classes::RigidBody3D, prelude::*}; +use godot::{ + classes::{IRigidBody3D, RigidBody3D}, + prelude::*, +}; -use crate::player::NetTransform; +use crate::player::{IPlayer, NetTransform}; #[derive(GodotClass)] #[class(base=RigidBody3D, init)] @@ -8,11 +11,34 @@ pub struct Ball { base: Base, } +#[godot_api] +impl IRigidBody3D for Ball { + fn ready(&mut self) { + self.base() + .signals() + .body_entered() + .connect_other(self, |s, body| s.on_collision(body)); + } +} + +#[godot_api] impl Ball { + #[signal] + pub fn on_ball_pickup(player_id: u16); + pub fn get_transform(&self) -> NetTransform { NetTransform { location: self.base().get_global_position().into(), rotation: self.base().get_global_rotation().into(), } } + + fn on_collision(&mut self, node: Gd) { + godot_print!("ball collision"); + if let Ok(player) = node.try_dynify::() + && let Some(player_id) = player.dyn_bind().get_player_id() + { + self.run_deferred(move |s| s.signals().on_ball_pickup().emit(player_id)); + } + } } diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index 4895179..d10e9a6 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -4,6 +4,7 @@ use godot::{classes::CharacterBody3D, prelude::*, tools::get_autoload_by_name}; use serde::{Deserialize, Serialize}; use crate::{ + ball::Ball, map::Map, map_resource::MapResource, net::{ @@ -96,6 +97,7 @@ pub struct Game { game_started: bool, pub current_map: Option>, + pub world_ball: Option>, since_last_sync: f64, base: Base, @@ -309,6 +311,12 @@ impl Game { pub fn spawn_ball(&mut self, transform: Option) { if let Some(map) = &mut self.current_map { let ball = map.bind_mut().spawn_ball(transform); + if let Some(ball) = &ball { + self.world_ball = Some(ball.clone()); + ball.signals() + .on_ball_pickup() + .connect_other(self, |s, player_id| s.handle_ball_pickup(player_id)); + } self.run_deferred(|_| { if let Some(ball) = ball && let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer @@ -320,6 +328,23 @@ impl Game { } } + pub fn handle_ball_pickup(&mut self, player_id: u16) { + self.despawn_ball(); + } + + pub fn despawn_ball(&mut self) { + if let Some(mut ball) = self.world_ball.take() { + ball.queue_free(); + self.run_deferred(|_| { + if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer + && let PeerKind::Server(peer, _) = peer + { + peer.broadcast_reliable(Package::DespawnBall); + } + }); + } + } + pub fn spawn_player_server(&mut self, id: u16) -> Option> { if let Some(player) = self.find_player_mut(id) && let Some(character) = &mut player.character diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index 0b37550..f7d9c56 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -262,6 +262,11 @@ impl INode for NetworkManager { game.bind_mut().spawn_ball(Some(transform)); } } + Package::DespawnBall => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().despawn_ball(); + } + } _ => {} }, } @@ -580,6 +585,7 @@ pub enum Package { TakeDamage(DamageSource, u16, i32), Kill(DamageSource, u16), SpawnBall(NetTransform), + DespawnBall, } #[derive(Debug, Clone, Serialize, Deserialize)]