Add play_fx for weapons

This commit is contained in:
Sofia 2026-08-06 18:36:07 +03:00
parent c866db3581
commit a34884fb27
7 changed files with 68 additions and 38 deletions

View File

@ -1103,8 +1103,9 @@ impl Game {
.bind_mut() .bind_mut()
.record_event(ReplayEvent::Shoot(player_id, to.into())); .record_event(ReplayEvent::Shoot(player_id, to.into()));
} }
let play_fx = self.current_replay_playback.is_none();
if let Some(player) = self.find_player_mut(player_id) { if let Some(player) = self.find_player_mut(player_id) {
player.try_shoot(to, transform, look_up, deal_damage) player.try_shoot(to, transform, look_up, deal_damage, play_fx)
} else { } else {
false false
} }
@ -1596,13 +1597,14 @@ impl Player {
transform: NetTransform, transform: NetTransform,
look_up: f32, look_up: f32,
deal_damage: bool, deal_damage: bool,
play_fx: bool,
) -> bool { ) -> bool {
if let Some(character) = &mut self.character { if let Some(character) = &mut self.character {
character character
.dyn_bind_mut() .dyn_bind_mut()
.apply_rotation(transform.rotation.into()); .apply_rotation(transform.rotation.into());
character.dyn_bind_mut().apply_look_up(look_up); character.dyn_bind_mut().apply_look_up(look_up);
character.dyn_bind_mut().try_shoot(to, deal_damage) character.dyn_bind_mut().try_shoot(to, deal_damage, play_fx)
} else { } else {
false false
} }

View File

@ -1,4 +1,7 @@
use godot::{classes::Area3D, prelude::*}; use godot::{
classes::{Area3D, StaticBody3D},
prelude::*,
};
use crate::{ use crate::{
game::Game, game::Game,
@ -156,9 +159,9 @@ impl Triggerable {
} }
#[derive(GodotClass)] #[derive(GodotClass)]
#[class(base=Area3D, init)] #[class(base=StaticBody3D, init)]
pub struct ShootableTrigger { pub struct ShootableTrigger {
base: Base<Area3D>, base: Base<StaticBody3D>,
} }
#[godot_api] #[godot_api]

View File

@ -206,8 +206,8 @@ impl IPlayer for LocalPlayer {
} }
} }
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool { fn try_shoot(&mut self, to: Vector3, deal_damage: bool, play_fx: bool) -> bool {
if self.buffs.can_shoot() && self.try_shoot_common(to, deal_damage) { if self.buffs.can_shoot() && self.try_shoot_common(to, deal_damage, play_fx) {
if let Some(weapon) = &mut self.weapon { if let Some(weapon) = &mut self.weapon {
weapon.set_position(-Vector3::FORWARD); weapon.set_position(-Vector3::FORWARD);
weapon.set_rotation(Vector3::RIGHT * 0.5); weapon.set_rotation(Vector3::RIGHT * 0.5);
@ -667,7 +667,7 @@ impl ICharacterBody3D for LocalPlayer {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer { if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer { match peer {
PeerKind::Client(peer, addr) => { PeerKind::Client(peer, addr) => {
if self.try_shoot(pos, false) { if self.try_shoot(pos, false, true) {
peer.send_reliable( peer.send_reliable(
addr, addr,
Shoot(0, pos.into(), self.get_transform(), self.look_up), Shoot(0, pos.into(), self.get_transform(), self.look_up),
@ -675,7 +675,7 @@ impl ICharacterBody3D for LocalPlayer {
} }
} }
PeerKind::Server(peer, _) => { PeerKind::Server(peer, _) => {
if self.try_shoot(pos, true) { if self.try_shoot(pos, true, true) {
peer.broadcast_reliable(Shoot( peer.broadcast_reliable(Shoot(
self.player_id.unwrap_or(0), self.player_id.unwrap_or(0),
pos.into(), pos.into(),

View File

@ -54,7 +54,7 @@ pub trait IPlayer {
fn get_look_up(&self) -> f32; fn get_look_up(&self) -> f32;
fn get_transform(&self) -> NetTransform; fn get_transform(&self) -> NetTransform;
fn jump(&mut self); fn jump(&mut self);
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool; fn try_shoot(&mut self, to: Vector3, deal_damage: bool, play_fx: bool) -> bool;
fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool; fn try_punch(&mut self, to: Vector3, deal_damage: bool) -> bool;
fn take_damage(&mut self, source_player: DamageSource, damage: i32, kill: bool); fn take_damage(&mut self, source_player: DamageSource, damage: i32, kill: bool);
fn is_dead(&self) -> bool; fn is_dead(&self) -> bool;
@ -88,7 +88,7 @@ pub trait PlayerCommon {
fn drop_ball_common(&mut self, with_velocity: bool) -> bool; fn drop_ball_common(&mut self, with_velocity: bool) -> bool;
fn get_look_dir(&self) -> Vector3; fn get_look_dir(&self) -> Vector3;
fn can_take_damage(&self, source: &DamageSource) -> bool; fn can_take_damage(&self, source: &DamageSource) -> bool;
fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool) -> bool; fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool, play_fx: bool) -> bool;
fn try_punch_common(&mut self, to: Vector3, deal_damage: bool) -> bool; fn try_punch_common(&mut self, to: Vector3, deal_damage: bool) -> bool;
fn throw_telegrenade_common(&mut self, to: Vector3) -> bool; fn throw_telegrenade_common(&mut self, to: Vector3) -> bool;
fn telegrenade_teleport_common(&mut self, to: Vector3) -> bool; fn telegrenade_teleport_common(&mut self, to: Vector3) -> bool;
@ -207,7 +207,7 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
true true
} }
fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool) -> bool { fn try_shoot_common(&mut self, to: Vector3, deal_damage: bool, play_fx: bool) -> bool {
if self.is_dead() { if self.is_dead() {
return false; return false;
} }
@ -227,6 +227,7 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
to, to,
camera_origin.get_basis().col_b(), camera_origin.get_basis().col_b(),
deal_damage, deal_damage,
play_fx,
) )
} else { } else {
false false

View File

@ -151,9 +151,9 @@ impl IPlayer for RemotePlayer {
self.look_up = look; self.look_up = look;
} }
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool { fn try_shoot(&mut self, to: Vector3, deal_damage: bool, play_fx: bool) -> bool {
if self.buffs.can_shoot() { if self.buffs.can_shoot() {
self.try_shoot_common(to, deal_damage) self.try_shoot_common(to, deal_damage, play_fx)
} else { } else {
false false
} }

View File

@ -22,6 +22,7 @@ pub trait Weapon {
to: Vector3, to: Vector3,
up: Vector3, up: Vector3,
deal_damage: bool, deal_damage: bool,
play_fx: bool,
) -> bool; ) -> bool;
fn get_type(&self) -> WeaponType; fn get_type(&self) -> WeaponType;
fn get_max_cd(&self) -> f64; fn get_max_cd(&self) -> f64;
@ -73,12 +74,15 @@ impl Weapon for Raygun {
to: Vector3, to: Vector3,
_: Vector3, _: Vector3,
deal_damage: bool, deal_damage: bool,
play_fx: bool,
) -> bool { ) -> bool {
if self.cooldown_remaining > 0. { if self.cooldown_remaining > 0. {
return false; return false;
} }
if let Some(emitter) = &mut self.sound_emitter { if let Some(emitter) = &mut self.sound_emitter
&& play_fx
{
emitter.play(); emitter.play();
} }
@ -90,12 +94,14 @@ impl Weapon for Raygun {
&Array::from_iter(vec![player]), &Array::from_iter(vec![player]),
); );
let target_clone = target.clone(); if play_fx {
self.run_deferred(|s| { let target_clone = target.clone();
if let Some(target) = target_clone { self.run_deferred(|s| {
add_decal(&target, s.decal.clone()); if let Some(target) = target_clone {
} add_decal(&target, s.decal.clone());
}); }
});
}
let dir = (to - source.get_global_position()).normalized(); let dir = (to - source.get_global_position()).normalized();
let beam_end = target let beam_end = target
@ -103,7 +109,9 @@ impl Weapon for Raygun {
.map(|r| r.position) .map(|r| r.position)
.unwrap_or(source.get_global_position() + dir * 100.); .unwrap_or(source.get_global_position() + dir * 100.);
if let Some(prefab) = &self.bullet_prefab { if let Some(prefab) = &self.bullet_prefab
&& play_fx
{
let mut bullet = prefab.instantiate_as::<Beam>(); let mut bullet = prefab.instantiate_as::<Beam>();
bullet.bind_mut().source = Some(source.get_global_position()); bullet.bind_mut().source = Some(source.get_global_position());
@ -196,15 +204,20 @@ impl Weapon for Shotgun {
to: Vector3, to: Vector3,
up: Vector3, up: Vector3,
deal_damage: bool, deal_damage: bool,
play_fx: bool,
) -> bool { ) -> bool {
if self.cooldown_remaining > 0. { if self.cooldown_remaining > 0. {
return false; return false;
} }
if let Some(audio) = &mut self.sound_emitter { if let Some(audio) = &mut self.sound_emitter
&& play_fx
{
audio.play(); audio.play();
} }
if let Some(vfx) = &mut self.vfx { if let Some(vfx) = &mut self.vfx
&& play_fx
{
vfx.set_emitting(true); vfx.set_emitting(true);
} }
@ -219,20 +232,22 @@ impl Weapon for Shotgun {
PI / 2., PI / 2.,
10., 10.,
); );
let mut bullet_decal_results = Vec::new(); if play_fx {
for _ in 0..10 { let mut bullet_decal_results = Vec::new();
if let Some(result) = results for _ in 0..10 {
.get(self.rng.randi_range(0, results.len() as i32 - 1) as usize) if let Some(result) = results
.cloned() .get(self.rng.randi_range(0, results.len() as i32 - 1) as usize)
{ .cloned()
bullet_decal_results.push(result); {
bullet_decal_results.push(result);
}
} }
}
for result in bullet_decal_results { for result in bullet_decal_results {
self.run_deferred(move |s| { self.run_deferred(move |s| {
add_decal(&result, s.decal.clone()); add_decal(&result, s.decal.clone());
}); });
}
} }
for result in &results { for result in &results {
@ -334,7 +349,16 @@ pub struct BallWeapon {
#[godot_dyn] #[godot_dyn]
impl Weapon for BallWeapon { impl Weapon for BallWeapon {
fn shoot(&mut self, _: Rid, _: u16, _: Vector3, _: Vector3, _: Vector3, _: bool) -> bool { fn shoot(
&mut self,
_: Rid,
_: u16,
_: Vector3,
_: Vector3,
_: Vector3,
_: bool,
_: bool,
) -> bool {
true true
} }

View File

@ -380,7 +380,7 @@ impl INode for ReplayPlayback {
} }
ReplayEvent::Shoot(player_id, to) => { ReplayEvent::Shoot(player_id, to) => {
if let Some(character) = self.player_characters.get_mut(player_id) { if let Some(character) = self.player_characters.get_mut(player_id) {
character.bind_mut().try_shoot((*to).into(), false); character.bind_mut().try_shoot((*to).into(), false, true);
} }
} }
ReplayEvent::Respawn(player_id, data) => { ReplayEvent::Respawn(player_id, data) => {