Update raycasting to work properly for all players

This commit is contained in:
Sofia 2026-07-20 21:08:57 +03:00
parent d4f4dc43b0
commit 0678c56dae
5 changed files with 52 additions and 11 deletions

View File

@ -12,6 +12,7 @@ look_sensitivity = 1.5
camera = NodePath("camera_3d")
move_speed = 5.0
soldier_mesh = NodePath("soldier_m")
health = 100
collision_mask = 4
[node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418]

View File

@ -7,6 +7,7 @@
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh")]
move_speed = 5.0
soldier_mesh = NodePath("soldier_m")
health = 100
collision_layer = 2
collision_mask = 4

View File

@ -27,20 +27,29 @@ impl From<NetVector3> for Vector3 {
}
}
pub fn cast_ray(from: Vector3, to: Vector3, world: Option<Gd<World3D>>) -> Option<RaycastResult> {
pub fn cast_ray(
from: Vector3,
to: Vector3,
world: Option<Gd<World3D>>,
exclude: Array<Rid>,
) -> Option<RaycastResult> {
let ray = PhysicsRayQueryParameters3D::create(from, to);
if let Some(mut ray) = ray {
ray.set_collision_mask(0b110);
ray.set_collision_mask(0b111);
ray.set_hit_back_faces(false);
ray.set_hit_from_inside(false);
ray.set_collide_with_bodies(true);
ray.set_exclude(&exclude);
if let Some(world) = world
&& let Some(mut space) = world.get_direct_space_state()
{
let results = space.intersect_ray(&ray);
if let Some(position) = results.get("position") {
if let (Some(position), Some(collider)) =
(results.get("position"), results.get("collider"))
{
Some(RaycastResult {
position: Vector3::from_variant(&position),
collider: Gd::from_variant(&collider),
})
} else {
None
@ -55,4 +64,5 @@ pub fn cast_ray(from: Vector3, to: Vector3, world: Option<Gd<World3D>>) -> Optio
pub struct RaycastResult {
pub position: Vector3,
pub collider: Gd<Object>,
}

View File

@ -44,6 +44,7 @@ pub trait IPlayer {
fn get_transform(&self) -> NetPlayerTransform;
fn jump(&mut self);
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool;
fn take_damage(&mut self, damage: i32);
}
pub trait PlayerMovement {
@ -81,6 +82,8 @@ pub struct LocalPlayer {
move_speed: f32,
#[export]
soldier_mesh: Option<Gd<SoldierMesh>>,
#[export]
health: i32,
pub player_id: Option<u16>,
pub weapon: Option<DynGd<Node3D, dyn Weapon>>,
@ -156,8 +159,9 @@ impl IPlayer for LocalPlayer {
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
if self.shoot_cd <= 0. {
let rid = self.base().get_rid();
if let Some(weapon) = &mut self.weapon {
weapon.dyn_bind_mut().shoot(to, deal_damage);
weapon.dyn_bind_mut().shoot(rid, to, deal_damage);
}
self.shoot_cd = 0.2;
true
@ -165,6 +169,11 @@ impl IPlayer for LocalPlayer {
false
}
}
fn take_damage(&mut self, damage: i32) {
godot_print!("Took damage!");
self.health -= damage;
}
}
#[godot_api]
@ -225,6 +234,7 @@ impl ICharacterBody3D for LocalPlayer {
camera.get_global_position(),
camera.get_global_position() + forward,
self.base().get_world_3d(),
Array::from_iter(vec![self.base().get_rid()]),
) {
Some(res) => Some(res.position),
None => Some(camera.get_global_position() + forward * 100.),
@ -233,8 +243,6 @@ impl ICharacterBody3D for LocalPlayer {
None
};
godot_print!("{:?}", pos);
if let Some(pos) = pos {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
@ -298,6 +306,8 @@ pub struct RemotePlayer {
move_speed: f32,
#[export]
soldier_mesh: Option<Gd<SoldierMesh>>,
#[export]
health: i32,
pub player_id: Option<u16>,
pub weapon: Option<DynGd<Node3D, dyn Weapon>>,
@ -369,8 +379,9 @@ impl IPlayer for RemotePlayer {
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
if self.shoot_cd <= 0. {
let rid = self.base().get_rid();
if let Some(weapon) = &mut self.weapon {
weapon.dyn_bind_mut().shoot(to, deal_damage);
weapon.dyn_bind_mut().shoot(rid, to, deal_damage);
}
self.shoot_cd = 0.2;
true
@ -378,6 +389,11 @@ impl IPlayer for RemotePlayer {
false
}
}
fn take_damage(&mut self, damage: i32) {
godot_print!("Took damage!");
self.health -= damage;
}
}
#[godot_api]

View File

@ -3,10 +3,10 @@ use godot::{
prelude::*,
};
use crate::net::util::cast_ray;
use crate::{net::util::cast_ray, player::IPlayer};
pub trait Weapon {
fn shoot(&mut self, to: Vector3, deal_damage: bool);
fn shoot(&mut self, player: Rid, to: Vector3, deal_damage: bool);
}
#[derive(GodotClass)]
@ -24,16 +24,22 @@ pub struct Raygun {
#[godot_dyn]
impl Weapon for Raygun {
fn shoot(&mut self, to: Vector3, deal_damage: bool) {
fn shoot(&mut self, player: Rid, to: Vector3, deal_damage: bool) {
if let Some(emitter) = &mut self.sound_emitter {
emitter.play();
}
if let Some(source) = &self.bullet_source {
let target = cast_ray(source.get_global_position(), to, self.base().get_world_3d());
let target = cast_ray(
source.get_global_position(),
to,
self.base().get_world_3d(),
Array::from_iter(vec![player]),
);
let dir = (to - source.get_global_position()).normalized();
let beam_end = target
.as_ref()
.map(|r| r.position)
.unwrap_or(source.get_global_position() + dir * 100.);
@ -47,6 +53,13 @@ impl Weapon for Raygun {
parent.add_child(&bullet);
}
}
if deal_damage && let Some(target) = target {
godot_print!("{}", target.collider);
if let Ok(mut player) = target.collider.try_dynify::<dyn IPlayer>() {
player.dyn_bind_mut().take_damage(100);
}
}
}
}
}