Improve how raycasting is done

This commit is contained in:
Sofia 2026-07-20 20:44:49 +03:00
parent 33095ec1b9
commit d4f4dc43b0
3 changed files with 57 additions and 31 deletions

View File

@ -1,4 +1,7 @@
use godot::prelude::*; use godot::{
classes::{PhysicsRayQueryParameters3D, World3D},
prelude::*,
};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -23,3 +26,33 @@ impl From<NetVector3> for Vector3 {
Vector3::new(value.x, value.y, value.z) Vector3::new(value.x, value.y, value.z)
} }
} }
pub fn cast_ray(from: Vector3, to: Vector3, world: Option<Gd<World3D>>) -> Option<RaycastResult> {
let ray = PhysicsRayQueryParameters3D::create(from, to);
if let Some(mut ray) = ray {
ray.set_collision_mask(0b110);
ray.set_hit_back_faces(false);
ray.set_hit_from_inside(false);
ray.set_collide_with_bodies(true);
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") {
Some(RaycastResult {
position: Vector3::from_variant(&position),
})
} else {
None
}
} else {
None
}
} else {
None
}
}
pub struct RaycastResult {
pub position: Vector3,
}

View File

@ -17,7 +17,7 @@ use crate::{
Package::{Jump, Shoot}, Package::{Jump, Shoot},
PeerKind, PeerKind,
}, },
util::NetVector3, util::{NetVector3, cast_ray},
}, },
soldier_mesh::SoldierMesh, soldier_mesh::SoldierMesh,
ui::cli::CommandLinePanel, ui::cli::CommandLinePanel,
@ -221,29 +221,13 @@ impl ICharacterBody3D for LocalPlayer {
if event.is_action_pressed("shoot") { if event.is_action_pressed("shoot") {
let pos = if let Some(camera) = &self.camera { let pos = if let Some(camera) = &self.camera {
let forward = camera.get_global_basis().col_c().neg(); let forward = camera.get_global_basis().col_c().neg();
let ray = PhysicsRayQueryParameters3D::create( match cast_ray(
camera.get_global_position(), camera.get_global_position(),
camera.get_global_position() + forward * 10000., camera.get_global_position() + forward,
); self.base().get_world_3d(),
if let Some(mut ray) = ray { ) {
ray.set_collision_mask(0b110); Some(res) => Some(res.position),
ray.set_hit_back_faces(false); None => Some(camera.get_global_position() + forward * 100.),
ray.set_hit_from_inside(false);
ray.set_collide_with_bodies(true);
if let Some(world) = self.base().get_world_3d()
&& let Some(mut space) = world.get_direct_space_state()
{
let results = space.intersect_ray(&ray);
if let Some(position) = results.get("position") {
Some(Vector3::from_variant(&position))
} else {
Some(camera.get_global_position() + forward * 100.)
}
} else {
None
}
} else {
None
} }
} else { } else {
None None

View File

@ -3,6 +3,8 @@ use godot::{
prelude::*, prelude::*,
}; };
use crate::net::util::cast_ray;
pub trait Weapon { pub trait Weapon {
fn shoot(&mut self, to: Vector3, deal_damage: bool); fn shoot(&mut self, to: Vector3, deal_damage: bool);
} }
@ -27,16 +29,23 @@ impl Weapon for Raygun {
emitter.play(); emitter.play();
} }
if let Some(prefab) = &self.bullet_prefab { if let Some(source) = &self.bullet_source {
let mut bullet = prefab.instantiate_as::<Beam>(); let target = cast_ray(source.get_global_position(), to, self.base().get_world_3d());
let dir = (to - source.get_global_position()).normalized();
let beam_end = target
.map(|r| r.position)
.unwrap_or(source.get_global_position() + dir * 100.);
if let Some(prefab) = &self.bullet_prefab {
let mut bullet = prefab.instantiate_as::<Beam>();
if let Some(source) = &self.bullet_source {
bullet.bind_mut().source = Some(source.get_global_position()); bullet.bind_mut().source = Some(source.get_global_position());
} bullet.bind_mut().target = Some(beam_end);
bullet.bind_mut().target = Some(to);
if let Some(mut parent) = self.base().find_parent("map") { if let Some(mut parent) = self.base().find_parent("map") {
parent.add_child(&bullet); parent.add_child(&bullet);
}
} }
} }
} }