Despawn ball on contact

This commit is contained in:
Sofia 2026-07-21 20:45:14 +03:00
parent b57d31065a
commit 51a81cc432
4 changed files with 61 additions and 2 deletions

View File

@ -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")

View File

@ -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<RigidBody3D>,
}
#[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<Node>) {
godot_print!("ball collision");
if let Ok(player) = node.try_dynify::<dyn IPlayer>()
&& let Some(player_id) = player.dyn_bind().get_player_id()
{
self.run_deferred(move |s| s.signals().on_ball_pickup().emit(player_id));
}
}
}

View File

@ -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<Gd<Map>>,
pub world_ball: Option<Gd<Ball>>,
since_last_sync: f64,
base: Base<Node>,
@ -309,6 +311,12 @@ impl Game {
pub fn spawn_ball(&mut self, transform: Option<NetTransform>) {
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<DynGd<CharacterBody3D, dyn IPlayer>> {
if let Some(player) = self.find_player_mut(id)
&& let Some(character) = &mut player.character

View File

@ -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)]