Add ball and be able to pick it up

This commit is contained in:
Sofia 2026-07-21 21:07:50 +03:00
parent aeab1ed88c
commit ba7da5614c
9 changed files with 159 additions and 46 deletions

17
godot/mesh/ball_mesh.tscn Normal file
View File

@ -0,0 +1,17 @@
[gd_scene format=3 uid="uid://r13poamopmnv"]
[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")
[node name="mesh_instance_3d" type="MeshInstance3D" unique_id=37904686]
mesh = SubResource("SphereMesh_1cgct")

View File

@ -1,17 +1,6 @@
[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")
[ext_resource type="PackedScene" uid="uid://r13poamopmnv" path="res://mesh/ball_mesh.tscn" id="1_texud"]
[sub_resource type="SphereShape3D" id="SphereShape3D_1cgct"]
@ -21,8 +10,7 @@ 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")
[node name="mesh_instance_3d" parent="." unique_id=37904686 instance=ExtResource("1_texud")]
[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1408432914]
shape = SubResource("SphereShape3D_1cgct")

View File

@ -0,0 +1,8 @@
[gd_scene format=3 uid="uid://ci8r4lgijtalh"]
[ext_resource type="PackedScene" uid="uid://r13poamopmnv" path="res://mesh/ball_mesh.tscn" id="1_5wscr"]
[node name="ball_weapon" type="BallWeapon" unique_id=53185750]
[node name="mesh_instance_3d" parent="." unique_id=37904686 instance=ExtResource("1_5wscr")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.29060435)

View File

@ -2,6 +2,7 @@
[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://ci8r4lgijtalh" path="res://scenes/player/ball_weapon.tscn" id="2_jbny0"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_a50o4"]
animation = &"Soldier|StrafeLeft"
@ -48,6 +49,7 @@ hand_attachment = NodePath("bone_attachment_3d/hand")
animation_tree = NodePath("animation_tree")
skeleton = NodePath("SoldierM/Soldier/Skeleton3D")
raygun = ExtResource("1_a50o4")
ball = ExtResource("2_jbny0")
look_at = NodePath("look_at_root")
[node name="SoldierM" parent="." unique_id=1868587353 instance=ExtResource("1_sxefq")]
@ -55,10 +57,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.6933472, 0, 0, 0.7206036)
bones/1/rotation = Quaternion(0.69402224, 0, 0, 0.7199537)
bones/1/scale = Vector3(1, 1, 1)
bones/2/position = Vector3(0.002, 3.469447e-18, -1.4901118e-10)
bones/2/rotation = Quaternion(0.94524616, 2.1414793e-08, 2.3228983e-08, -0.3263583)
bones/2/rotation = Quaternion(0.9458209, 2.1373747e-08, 2.3266757e-08, -0.3246889)
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)
@ -66,7 +68,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.99965113, 1.8159536e-08, 1.8669295e-08, 0.026414612)
bones/6/rotation = Quaternion(0.9996778, 1.8178714e-08, 1.8650622e-08, 0.025387304)
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)
@ -75,33 +77,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.15285265, -0.13164668, 0.01958379, 0.9792455)
bones/10/rotation = Quaternion(-0.15427561, -0.13167602, 0.019766005, 0.97901475)
bones/10/scale = Vector3(1, 1, 1)
bones/11/position = Vector3(6.8186457e-17, 0.008, 0.001)
bones/11/rotation = Quaternion(0.064451575, 0.0001293997, -0.017637832, 0.99776495)
bones/11/rotation = Quaternion(0.058245, 0.0001169397, -0.01593934, 0.99817514)
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.8961373, 0.033810798, 0.43093914, -0.10043051)
bones/14/rotation = Quaternion(0.8948131, 0.033457648, 0.43200484, -0.10752621)
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.0371126e-08, -6.748454e-09, 0.9316012, 0.36348197)
bones/15/rotation = Quaternion(1.035401e-08, -6.774687e-09, 0.93067807, 0.3658392)
bones/15/scale = Vector3(1, 1, 1)
bones/16/position = Vector3(7.632945e-11, 0.007071071, 6.938894e-18)
bones/16/rotation = Quaternion(0.0037409808, -0.10074904, -0.18467231, 0.9776154)
bones/16/rotation = Quaternion(0.0062737567, -0.0943689, -0.18486792, 0.978202)
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.6575101, 0.16476046, -0.1328446, -0.7231091)
bones/18/rotation = Quaternion(0.6564217, 0.1684678, -0.13023898, -0.7237176)
bones/18/scale = Vector3(1, 0.99999994, 1)
bones/19/position = Vector3(-1.3005262e-15, 0.0050000004, -6.938894e-18)
bones/19/rotation = Quaternion(-2.1579417e-08, -3.5349842e-08, -0.2771271, 0.9608333)
bones/19/rotation = Quaternion(-2.1246766e-08, -3.5550773e-08, -0.26809898, 0.9633914)
bones/19/scale = Vector3(1, 1, 1)
bones/20/position = Vector3(-2.2286711e-10, 0.007071072, 0)
bones/20/rotation = Quaternion(-0.10949359, -0.472547, -0.13018106, 0.86473316)
bones/20/rotation = Quaternion(-0.112210214, -0.47133064, -0.13382514, 0.8644924)
bones/20/scale = Vector3(1, 0.9999999, 1)
bones/22/position = Vector3(0.010811842, -0.0085772155, 0.0026515652)
bones/22/position = Vector3(0.011061782, -0.0085772155, 0.0025831666)
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)
@ -150,7 +152,7 @@ origin_from = 2
origin_external_node = NodePath("../../../../look_at_root")
[node name="bone_attachment_3d" type="BoneAttachment3D" parent="." unique_id=1964353847]
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)
transform = Transform3D(-35.07064, 3.824201, -93.57043, -83.59483, 43.760143, 33.120216, 42.213154, 89.83552, -12.150139, -0.47213513, 3.3899364, 0.7408379)
bone_name = "HAND.R_end"
bone_idx = 17
use_external_skeleton = true

View File

@ -16,6 +16,7 @@ use crate::{
util::NetVector3,
},
player::{DamageSource, IPlayer, LocalPlayer, NetTransform, RemotePlayer},
weapon::WeaponType,
};
pub const GAME_MANAGER_GLOBAL: &str = "GameManagerGlobal";
@ -329,7 +330,25 @@ impl Game {
}
pub fn handle_ball_pickup(&mut self, player_id: u16) {
self.despawn_ball();
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer
&& let PeerKind::Server(peer, _) = peer
{
self.despawn_ball();
if let Some(player) = self.find_player_mut(player_id)
&& let Some(character) = &mut player.character
{
character.dyn_bind_mut().swap_weapon(WeaponType::Ball);
peer.broadcast_reliable(Package::SwapWeapon(player.id, WeaponType::Ball));
}
}
}
pub fn handle_swap_weapon(&mut self, player_id: u16, weapon_type: WeaponType) {
if let Some(player) = self.find_player_mut(player_id)
&& let Some(character) = &mut player.character
{
character.dyn_bind_mut().swap_weapon(weapon_type);
}
}
pub fn despawn_ball(&mut self) {

View File

@ -13,6 +13,7 @@ use crate::{
net::{net_stats::Stats, util::NetVector3},
player::{DamageSource, NetTransform},
ui::cli::{CliColor, CommandLinePanel},
weapon::WeaponType,
};
#[derive(GodotClass)]
@ -267,6 +268,11 @@ impl INode for NetworkManager {
game.bind_mut().despawn_ball();
}
}
Package::SwapWeapon(id, weapon_type) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().handle_swap_weapon(id, weapon_type);
}
}
_ => {}
},
}
@ -586,6 +592,7 @@ pub enum Package {
Kill(DamageSource, u16),
SpawnBall(NetTransform),
DespawnBall,
SwapWeapon(u16, WeaponType),
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -22,7 +22,7 @@ use crate::{
},
soldier_mesh::SoldierMesh,
ui::cli::CommandLinePanel,
weapon::Weapon,
weapon::{Weapon, WeaponType},
};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -49,6 +49,8 @@ pub trait IPlayer {
fn is_dead(&self) -> bool;
fn kill(&mut self, source_player: DamageSource);
fn dead_for(&self) -> f64;
fn swap_weapon(&mut self, weapon: WeaponType);
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>>;
}
pub trait PlayerMovement {
@ -102,7 +104,6 @@ pub struct LocalPlayer {
health: i32,
pub player_id: Option<u16>,
pub weapon: Option<DynGd<Node3D, dyn Weapon>>,
movement_dir: Vector3,
y_speed: f32,
@ -184,7 +185,9 @@ impl IPlayer for LocalPlayer {
if self.shoot_cd <= 0. {
let rid = self.base().get_rid();
if let Some(weapon) = &mut self.weapon {
if let Some(mesh) = &mut self.soldier_mesh
&& let Some(mut weapon) = mesh.bind().get_weapon()
{
weapon
.dyn_bind_mut()
.shoot(rid, self.player_id.unwrap_or(0), to, deal_damage);
@ -219,9 +222,6 @@ impl IPlayer for LocalPlayer {
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();
}
@ -233,6 +233,21 @@ impl IPlayer for LocalPlayer {
self.killer_id = Some(player_id);
}
}
fn swap_weapon(&mut self, weapon: WeaponType) {
if let Some(mesh) = &mut self.soldier_mesh {
match weapon {
WeaponType::Raygun => mesh.bind_mut().spawn_raygun(),
WeaponType::Ball => mesh.bind_mut().spawn_ball(),
};
}
}
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.soldier_mesh
.as_ref()
.and_then(|m| m.bind().get_weapon())
}
}
#[godot_api]
@ -253,9 +268,7 @@ impl ICharacterBody3D for LocalPlayer {
s.set_lock(true);
});
if let Some(mesh) = &mut self.soldier_mesh {
self.weapon = mesh.bind_mut().spawn_raygun();
}
self.swap_weapon(WeaponType::Raygun);
if let Some(camera) = &mut self.camera {
camera.set_current(true);
@ -430,7 +443,6 @@ pub struct RemotePlayer {
spectator_camera: Option<Gd<Camera3D>>,
pub player_id: Option<u16>,
pub weapon: Option<DynGd<Node3D, dyn Weapon>>,
movement_dir: Vector3,
y_speed: f32,
@ -507,7 +519,9 @@ impl IPlayer for RemotePlayer {
if self.shoot_cd <= 0. {
let rid = self.base().get_rid();
if let Some(weapon) = &mut self.weapon {
if let Some(mesh) = &mut self.soldier_mesh
&& let Some(mut weapon) = mesh.bind().get_weapon()
{
weapon
.dyn_bind_mut()
.shoot(rid, self.player_id.unwrap_or(0), to, deal_damage);
@ -542,9 +556,6 @@ impl IPlayer for RemotePlayer {
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();
}
@ -553,14 +564,27 @@ impl IPlayer for RemotePlayer {
}
self.is_dead = true;
}
fn swap_weapon(&mut self, weapon: WeaponType) {
if let Some(mesh) = &mut self.soldier_mesh {
match weapon {
WeaponType::Raygun => mesh.bind_mut().spawn_raygun(),
WeaponType::Ball => mesh.bind_mut().spawn_ball(),
};
}
}
fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.soldier_mesh
.as_ref()
.and_then(|m| m.bind().get_weapon())
}
}
#[godot_api]
impl ICharacterBody3D for RemotePlayer {
fn ready(&mut self) {
if let Some(mesh) = &mut self.soldier_mesh {
self.weapon = mesh.bind_mut().spawn_raygun();
}
self.swap_weapon(WeaponType::Raygun);
}
fn process(&mut self, delta: f64) {

View File

@ -3,7 +3,7 @@ use godot::{
prelude::*,
};
use crate::weapon::{Raygun, Weapon};
use crate::weapon::{BallWeapon, Raygun, Weapon};
#[derive(GodotClass)]
#[class(base=Node3D, init)]
@ -17,8 +17,12 @@ pub struct SoldierMesh {
#[export]
raygun: Option<Gd<PackedScene>>,
#[export]
ball: Option<Gd<PackedScene>>,
#[export]
look_at: Option<Gd<Node3D>>,
pub current_weapon: Option<DynGd<Node3D, dyn Weapon>>,
base: Base<Node3D>,
}
@ -49,15 +53,32 @@ impl SoldierMesh {
}
}
pub fn spawn_ball(&mut self) -> Option<DynGd<Node3D, dyn Weapon>> {
if let Some(ball) = &self.ball {
let node = ball.instantiate_as::<BallWeapon>();
self.spawn_weapon(node.into_dyn().upcast())
} else {
None
}
}
fn spawn_weapon(
&mut self,
node: DynGd<Node3D, dyn Weapon>,
) -> Option<DynGd<Node3D, dyn Weapon>> {
if let Some(mut weapon) = self.current_weapon.take() {
weapon.queue_free();
}
if let Some(hand) = &mut self.hand_attachment {
hand.add_child(&node);
self.current_weapon = Some(node.clone());
Some(node)
} else {
None
}
}
pub fn get_weapon(&self) -> Option<DynGd<Node3D, dyn Weapon>> {
self.current_weapon.clone()
}
}

View File

@ -1,4 +1,5 @@
use godot::{classes::AudioStreamPlayer3D, prelude::*};
use serde::{Deserialize, Serialize};
use crate::{
game_manager::Game,
@ -8,6 +9,13 @@ use crate::{
pub trait Weapon {
fn shoot(&mut self, player_rid: Rid, player_id: u16, to: Vector3, deal_damage: bool);
fn get_type(&self) -> WeaponType;
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize)]
pub enum WeaponType {
Raygun,
Ball,
}
#[derive(GodotClass)]
@ -68,6 +76,10 @@ impl Weapon for Raygun {
}
}
}
fn get_type(&self) -> WeaponType {
WeaponType::Raygun
}
}
#[derive(GodotClass)]
@ -113,3 +125,18 @@ impl Beam {
}
}
}
#[derive(GodotClass)]
#[class(base=Node3D, init)]
pub struct BallWeapon {
base: Base<Node3D>,
}
#[godot_dyn]
impl Weapon for BallWeapon {
fn shoot(&mut self, player_rid: Rid, player_id: u16, to: Vector3, deal_damage: bool) {}
fn get_type(&self) -> WeaponType {
WeaponType::Ball
}
}