From b57d31065a761783af427ed4c3452c1f3b49c783 Mon Sep 17 00:00:00 2001 From: Sofia Date: Tue, 21 Jul 2026 20:31:39 +0300 Subject: [PATCH] Add ball --- godot/maps/default_map/map0.tscn | 8 +++++- godot/scenes/lobby.tscn | 2 +- godot/scenes/misc/ball.tscn | 26 ++++++++++++++++++ godot/scenes/{ => misc}/game_manager.tscn | 0 godot/scenes/{ => misc}/network_manager.tscn | 0 godot/scenes/{ => ui}/command_line_panel.tscn | 0 godot/scenes/{ => ui}/player_listing.tscn | 0 rust/src/ball.rs | 18 +++++++++++++ rust/src/game_manager.rs | 27 ++++++++++++++----- rust/src/lib.rs | 1 + rust/src/map.rs | 27 +++++++++++++++++-- rust/src/net/network_manager.rs | 14 +++++++--- rust/src/player.rs | 18 ++++++------- 13 files changed, 118 insertions(+), 23 deletions(-) create mode 100644 godot/scenes/misc/ball.tscn rename godot/scenes/{ => misc}/game_manager.tscn (100%) rename godot/scenes/{ => misc}/network_manager.tscn (100%) rename godot/scenes/{ => ui}/command_line_panel.tscn (100%) rename godot/scenes/{ => ui}/player_listing.tscn (100%) create mode 100644 rust/src/ball.rs diff --git a/godot/maps/default_map/map0.tscn b/godot/maps/default_map/map0.tscn index b94cf10..4efd569 100644 --- a/godot/maps/default_map/map0.tscn +++ b/godot/maps/default_map/map0.tscn @@ -2,6 +2,7 @@ [ext_resource type="PackedScene" uid="uid://ct70bpbca8one" path="res://scenes/player/local_player.tscn" id="1_yjvui"] [ext_resource type="PackedScene" uid="uid://kfxc0migw80o" path="res://scenes/player/remote_player.tscn" id="2_kcncr"] +[ext_resource type="PackedScene" uid="uid://dfnbc8sbufa4j" path="res://scenes/misc/ball.tscn" id="3_e0nj3"] [sub_resource type="ImageTexture" id="ImageTexture_3vyb7"] @@ -14,10 +15,12 @@ size = Vector2(100, 100) [sub_resource type="BoxShape3D" id="BoxShape3D_1cgct"] size = Vector3(100, 0.01, 100) -[node name="map" type="Map" unique_id=914577955 node_paths=PackedStringArray("spawner")] +[node name="map" type="Map" unique_id=914577955 node_paths=PackedStringArray("spawner", "ball_spawner")] spawner = NodePath("spawner") +ball_spawner = NodePath("ball_spawner") local_player = ExtResource("1_yjvui") remote_player = ExtResource("2_kcncr") +ball = ExtResource("3_e0nj3") [node name="net_stats_label" type="NetStatsLabel" parent="." unique_id=1821474986] anchors_preset = 2 @@ -44,3 +47,6 @@ transform = Transform3D(1, 0, 0, 0, 0.7274598, 0.6861503, 0, -0.6861503, 0.72745 [node name="spawner" type="Node3D" parent="." unique_id=1364438299] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.028572083, 3.9666176, 0.031027317) + +[node name="ball_spawner" type="Node3D" parent="." unique_id=1149426253] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.080344, 4.78083, -9.363691) diff --git a/godot/scenes/lobby.tscn b/godot/scenes/lobby.tscn index 88b2c4f..e8e2156 100644 --- a/godot/scenes/lobby.tscn +++ b/godot/scenes/lobby.tscn @@ -1,6 +1,6 @@ [gd_scene format=3 uid="uid://bwd6bj21x310s"] -[ext_resource type="PackedScene" uid="uid://ccd0wj2usx5os" path="res://scenes/player_listing.tscn" id="1_o1atq"] +[ext_resource type="PackedScene" uid="uid://ccd0wj2usx5os" path="res://scenes/ui/player_listing.tscn" id="1_o1atq"] [sub_resource type="LabelSettings" id="LabelSettings_1cgct"] font_size = 32 diff --git a/godot/scenes/misc/ball.tscn b/godot/scenes/misc/ball.tscn new file mode 100644 index 0000000..ac432d4 --- /dev/null +++ b/godot/scenes/misc/ball.tscn @@ -0,0 +1,26 @@ +[gd_scene format=3 uid="uid://dfnbc8sbufa4j"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_yxhor"] +noise_type = 2 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_yli5f"] +noise = SubResource("FastNoiseLite_yxhor") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_3g557"] +albedo_color = Color(0, 1, 0, 1) +albedo_texture = SubResource("NoiseTexture2D_yli5f") + +[sub_resource type="SphereMesh" id="SphereMesh_1cgct"] +material = SubResource("StandardMaterial3D_3g557") + +[sub_resource type="SphereShape3D" id="SphereShape3D_1cgct"] + +[node name="ball" type="Ball" unique_id=816748600] +collision_layer = 4 +collision_mask = 7 + +[node name="mesh_instance_3d" type="MeshInstance3D" parent="." unique_id=2076561614] +mesh = SubResource("SphereMesh_1cgct") + +[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1408432914] +shape = SubResource("SphereShape3D_1cgct") diff --git a/godot/scenes/game_manager.tscn b/godot/scenes/misc/game_manager.tscn similarity index 100% rename from godot/scenes/game_manager.tscn rename to godot/scenes/misc/game_manager.tscn diff --git a/godot/scenes/network_manager.tscn b/godot/scenes/misc/network_manager.tscn similarity index 100% rename from godot/scenes/network_manager.tscn rename to godot/scenes/misc/network_manager.tscn diff --git a/godot/scenes/command_line_panel.tscn b/godot/scenes/ui/command_line_panel.tscn similarity index 100% rename from godot/scenes/command_line_panel.tscn rename to godot/scenes/ui/command_line_panel.tscn diff --git a/godot/scenes/player_listing.tscn b/godot/scenes/ui/player_listing.tscn similarity index 100% rename from godot/scenes/player_listing.tscn rename to godot/scenes/ui/player_listing.tscn diff --git a/rust/src/ball.rs b/rust/src/ball.rs new file mode 100644 index 0000000..022a23d --- /dev/null +++ b/rust/src/ball.rs @@ -0,0 +1,18 @@ +use godot::{classes::RigidBody3D, prelude::*}; + +use crate::player::NetTransform; + +#[derive(GodotClass)] +#[class(base=RigidBody3D, init)] +pub struct Ball { + base: Base, +} + +impl Ball { + pub fn get_transform(&self) -> NetTransform { + NetTransform { + location: self.base().get_global_position().into(), + rotation: self.base().get_global_rotation().into(), + } + } +} diff --git a/rust/src/game_manager.rs b/rust/src/game_manager.rs index 151c87a..4895179 100644 --- a/rust/src/game_manager.rs +++ b/rust/src/game_manager.rs @@ -14,7 +14,7 @@ use crate::{ }, util::NetVector3, }, - player::{DamageSource, IPlayer, LocalPlayer, NetPlayerTransform, RemotePlayer}, + player::{DamageSource, IPlayer, LocalPlayer, NetTransform, RemotePlayer}, }; pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal"; @@ -300,11 +300,26 @@ impl Game { for player in s.players.clone() { s.spawn_player_server(player.id); } + s.spawn_ball(None); }); } } } + pub fn spawn_ball(&mut self, transform: Option) { + if let Some(map) = &mut self.current_map { + let ball = map.bind_mut().spawn_ball(transform); + self.run_deferred(|_| { + if let Some(ball) = ball + && let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer + && let PeerKind::Server(peer, _) = peer + { + peer.broadcast_reliable(Package::SpawnBall(ball.bind().get_transform())); + } + }); + } + } + 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 @@ -360,7 +375,7 @@ impl Game { } // Method called on the client-side whenever a player has spawned - pub fn spawn_player_client(&mut self, id: u16, transform: NetPlayerTransform) { + pub fn spawn_player_client(&mut self, id: u16, transform: NetTransform) { if let Some(map) = &mut self.current_map { if let Some(player) = self.players.iter_mut().find(|p| p.id == id) { if let Some(character) = &mut player.character { @@ -423,7 +438,7 @@ impl Game { &mut self, player_id: u16, to: Vector3, - transform: NetPlayerTransform, + transform: NetTransform, look_up: f32, deal_damage: bool, ) -> bool { @@ -487,7 +502,7 @@ pub struct Player { } impl Player { - pub fn get_transform(&self) -> Option { + pub fn get_transform(&self) -> Option { if let Some(character) = &self.character { Some(character.dyn_bind().get_transform()) } else { @@ -495,7 +510,7 @@ impl Player { } } - pub fn set_transform(&mut self, transform: NetPlayerTransform) { + pub fn set_transform(&mut self, transform: NetTransform) { if let Some(character) = &mut self.character { character.dyn_bind_mut().apply_transform(transform); } @@ -562,7 +577,7 @@ impl Player { pub fn try_shoot( &mut self, to: Vector3, - transform: NetPlayerTransform, + transform: NetTransform, look_up: f32, deal_damage: bool, ) -> bool { diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 01fd242..bbc4953 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,5 +1,6 @@ use godot::prelude::*; +pub mod ball; pub mod game_manager; pub mod killbox; pub mod map; diff --git a/rust/src/map.rs b/rust/src/map.rs index 72ebb6a..060240b 100644 --- a/rust/src/map.rs +++ b/rust/src/map.rs @@ -1,8 +1,9 @@ use godot::{classes::CharacterBody3D, prelude::*}; use crate::{ + ball::Ball, game_manager::Game, - player::{IPlayer, LocalPlayer, NetPlayerTransform, RemotePlayer}, + player::{IPlayer, LocalPlayer, NetTransform, RemotePlayer}, }; #[derive(GodotClass)] @@ -11,9 +12,13 @@ pub struct Map { #[export] pub spawner: Option>, #[export] + pub ball_spawner: Option>, + #[export] pub local_player: Option>, #[export] pub remote_player: Option>, + #[export] + pub ball: Option>, base: Base, } @@ -36,7 +41,7 @@ impl Map { &mut self, player_id: u16, is_local: bool, - transform: Option, + transform: Option, ) -> Option> { if is_local { if let Some(local_player) = &self.local_player { @@ -84,4 +89,22 @@ impl Map { None } } + + pub fn spawn_ball(&mut self, transform: Option) -> Option> { + if let Some(ball_spawner) = self.ball_spawner.clone() + && let Some(ball_prefab) = &self.ball + { + let mut ball = ball_prefab.instantiate_as::(); + self.base_mut().add_child(&ball); + if let Some(transform) = transform { + ball.set_global_position(transform.location.into()); + ball.set_global_rotation(transform.rotation.into()); + } else { + ball.set_global_position(ball_spawner.get_global_position()); + } + Some(ball) + } else { + None + } + } } diff --git a/rust/src/net/network_manager.rs b/rust/src/net/network_manager.rs index 517e8a9..0b37550 100644 --- a/rust/src/net/network_manager.rs +++ b/rust/src/net/network_manager.rs @@ -11,7 +11,7 @@ use teanet::{Peer, PeerConfig}; use crate::{ game_manager::{Game, GameManager, NetPlayer}, net::{net_stats::Stats, util::NetVector3}, - player::{DamageSource, NetPlayerTransform}, + player::{DamageSource, NetTransform}, ui::cli::{CliColor, CommandLinePanel}, }; @@ -257,6 +257,11 @@ impl INode for NetworkManager { .handle_kill(source_player_id, target_player_id); } } + Package::SpawnBall(transform) => { + if let Some(game) = &mut Game::singleton() { + game.bind_mut().spawn_ball(Some(transform)); + } + } _ => {} }, } @@ -567,20 +572,21 @@ pub enum Package { MapLoaded, // Game packages - SpawnPlayer(u16, NetPlayerTransform), + SpawnPlayer(u16, NetTransform), Sync(HashMap), SelfSync(SyncPackage), Jump(u16), - Shoot(u16, NetVector3, NetPlayerTransform, f32), + Shoot(u16, NetVector3, NetTransform, f32), TakeDamage(DamageSource, u16, i32), Kill(DamageSource, u16), + SpawnBall(NetTransform), } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SyncPackage { pub movement_direction: NetVector3, pub look_up: f32, - pub transform: NetPlayerTransform, + pub transform: NetTransform, } pub enum PeerKind { diff --git a/rust/src/player.rs b/rust/src/player.rs index c16aff9..339c031 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -26,7 +26,7 @@ use crate::{ }; #[derive(Debug, Clone, Copy, Serialize, Deserialize)] -pub struct NetPlayerTransform { +pub struct NetTransform { pub location: NetVector3, pub rotation: NetVector3, } @@ -38,11 +38,11 @@ pub trait IPlayer { fn get_movement_dir(&self) -> Vector3; fn set_movement_dir(&mut self, dir: Vector3); fn get_move_speed(&self) -> f32; - fn apply_transform(&mut self, transform: NetPlayerTransform); + fn apply_transform(&mut self, transform: NetTransform); fn apply_rotation(&mut self, rot: Vector3); fn apply_look_up(&mut self, rot: f32); fn get_look_up(&self) -> f32; - fn get_transform(&self) -> NetPlayerTransform; + fn get_transform(&self) -> NetTransform; fn jump(&mut self); fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool; fn take_damage(&mut self, source_player: DamageSource, damage: i32, kill: bool); @@ -143,7 +143,7 @@ impl IPlayer for LocalPlayer { self.move_speed } - fn apply_transform(&mut self, transform: NetPlayerTransform) { + fn apply_transform(&mut self, transform: NetTransform) { self.base_mut() .set_global_position(transform.location.into()); self.base_mut() @@ -152,8 +152,8 @@ impl IPlayer for LocalPlayer { fn apply_rotation(&mut self, _rot: Vector3) {} - fn get_transform(&self) -> NetPlayerTransform { - NetPlayerTransform { + fn get_transform(&self) -> NetTransform { + NetTransform { location: self.base().get_global_position().into(), rotation: self.base().get_global_rotation().into(), } @@ -470,7 +470,7 @@ impl IPlayer for RemotePlayer { self.player_id } - fn apply_transform(&mut self, transform: NetPlayerTransform) { + fn apply_transform(&mut self, transform: NetTransform) { self.base_mut() .set_global_position(transform.location.into()); self.base_mut() @@ -481,8 +481,8 @@ impl IPlayer for RemotePlayer { self.base_mut().set_global_rotation(rot); } - fn get_transform(&self) -> NetPlayerTransform { - NetPlayerTransform { + fn get_transform(&self) -> NetTransform { + NetTransform { location: self.base().get_global_position().into(), rotation: self.base().get_global_rotation().into(), }