Add proper shooting effect

This commit is contained in:
Sofia 2026-07-20 01:46:51 +03:00
parent dc30551227
commit 79f223cb21
11 changed files with 226 additions and 40 deletions

BIN
godot/assets/particle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dawgsqbcveewg"
path.s3tc="res://.godot/imported/particle.png-5e5e4f76b889a93c8b085c65be799145.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://assets/particle.png"
dest_files=["res://.godot/imported/particle.png-5e5e4f76b889a93c8b085c65be799145.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

View File

@ -14,7 +14,7 @@ size = Vector2(100, 100)
[sub_resource type="BoxShape3D" id="BoxShape3D_1cgct"]
size = Vector3(100, 0.01, 100)
[node name="map_0" type="Map" unique_id=914577955 node_paths=PackedStringArray("spawner")]
[node name="map" type="Map" unique_id=914577955 node_paths=PackedStringArray("spawner")]
spawner = NodePath("spawner")
local_player = ExtResource("1_yjvui")
remote_player = ExtResource("2_kcncr")
@ -33,8 +33,8 @@ material_override = SubResource("StandardMaterial3D_u8vuu")
mesh = SubResource("PlaneMesh_1cgct")
[node name="static_body_3d" type="StaticBody3D" parent="terrain" unique_id=203785193]
collision_layer = 3
collision_mask = 3
collision_layer = 7
collision_mask = 7
[node name="collision_shape_3d" type="CollisionShape3D" parent="terrain/static_body_3d" unique_id=1466526153]
shape = SubResource("BoxShape3D_1cgct")

View File

@ -4,21 +4,19 @@
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh", "sound_emitter")]
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera", "soldier_mesh")]
look_sensitivity = 1.5
camera = NodePath("camera_3d")
move_speed = 5.0
soldier_mesh = NodePath("soldier_m")
sound_emitter = NodePath("")
collision_mask = 2
collision_mask = 4
[node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8724979, -0.2644562)
current = true
[node name="soldier_m" parent="." unique_id=281995630 instance=ExtResource("1_jd651")]
transform = Transform3D(-0.5, 0, -4.371139e-08, 0, 0.5, 0, 4.371139e-08, 0, -0.5, 0, 0, -1.1592964)
visible = false
transform = Transform3D(-0.5, 0, -4.371139e-08, 0, 0.5, 0, 4.371139e-08, 0, -0.5, 0.15878421, 0, 0.19227558)
[node name="collision_shape_3d2" type="CollisionShape3D" parent="." unique_id=442150782]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0310049, 0)

View File

@ -1,13 +1,19 @@
[gd_scene format=3 uid="uid://cw7duhhjebypt"]
[ext_resource type="PackedScene" uid="uid://cg81784ct8gf5" path="res://mesh/raygun.tscn" id="1_ckadf"]
[ext_resource type="PackedScene" uid="uid://ctslratcr8h6v" path="res://scenes/player/raygun_bullet.tscn" id="1_m84jv"]
[ext_resource type="AudioStream" uid="uid://xxpkjhaovyd" path="res://assets/LaserWithRecoveryEdited.ogg" id="2_lxble"]
[node name="raygun" type="Weapon" unique_id=751705927 node_paths=PackedStringArray("sound_emitter")]
[node name="raygun" type="Weapon" unique_id=751705927 node_paths=PackedStringArray("sound_emitter", "bullet_source")]
sound_emitter = NodePath("sound_emitter")
bullet_prefab = ExtResource("1_m84jv")
bullet_source = NodePath("bullet_source")
[node name="Raygun" parent="." unique_id=1928455392 instance=ExtResource("1_ckadf")]
[node name="sound_emitter" type="AudioStreamPlayer3D" parent="." unique_id=1572422640]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.8420726, 0)
stream = ExtResource("2_lxble")
[node name="bullet_source" type="Node3D" parent="." unique_id=211401237]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.36108458, -1.490972)

View File

@ -0,0 +1,40 @@
[gd_scene format=3 uid="uid://ctslratcr8h6v"]
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_3g557"]
particle_flag_align_y = true
radial_velocity_min = -500.0
radial_velocity_max = -500.0
scale_over_velocity_max = 1.0
[sub_resource type="Curve" id="Curve_dmbod"]
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
point_count = 2
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yxhor"]
emission_enabled = true
emission = Color(1, 0, 1, 1)
emission_energy_multiplier = 4.47
use_particle_trails = true
[sub_resource type="TubeTrailMesh" id="TubeTrailMesh_m77kh"]
material = SubResource("StandardMaterial3D_yxhor")
sections = 2
section_length = 0.5
section_rings = 5
cap_top = false
cap_bottom = false
curve = SubResource("Curve_dmbod")
[node name="raygun_bullet" type="Bullet" unique_id=1238833478 node_paths=PackedStringArray("emitter")]
emitter = NodePath("gpu_particles_3d")
[node name="gpu_particles_3d" type="GPUParticles3D" parent="." unique_id=1330763726]
emitting = false
amount = 1
lifetime = 3.8899999999999997
one_shot = true
fixed_fps = 100
trail_enabled = true
trail_lifetime = 0.5
process_material = SubResource("ParticleProcessMaterial_3g557")
draw_pass_1 = SubResource("TubeTrailMesh_m77kh")

View File

@ -4,11 +4,11 @@
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "sound_emitter")]
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh")]
move_speed = 5.0
soldier_mesh = NodePath("soldier_m")
sound_emitter = NodePath("")
collision_mask = 2
collision_layer = 2
collision_mask = 4
[node name="soldier_m" parent="." unique_id=281995630 instance=ExtResource("1_e2ekk")]
transform = Transform3D(-0.5, 0, -4.371139e-08, 0, 0.5, 0, 4.371139e-08, 0, -0.5, 0, 0, 0)

View File

@ -335,12 +335,13 @@ impl Game {
pub fn handle_shoot(
&mut self,
player_id: u16,
to: Vector3,
transform: NetPlayerTransform,
look_up: f32,
deal_damage: bool,
) -> bool {
if let Some(player) = self.find_player_mut(player_id) {
player.try_shoot(transform, look_up, deal_damage)
player.try_shoot(to, transform, look_up, deal_damage)
} else {
false
}
@ -432,6 +433,7 @@ impl Player {
pub fn try_shoot(
&mut self,
to: Vector3,
transform: NetPlayerTransform,
look_up: f32,
deal_damage: bool,
@ -441,7 +443,7 @@ impl Player {
.dyn_bind_mut()
.apply_rotation(transform.rotation.into());
character.dyn_bind_mut().apply_look_up(look_up);
character.dyn_bind_mut().try_shoot(true)
character.dyn_bind_mut().try_shoot(to, true)
} else {
false
}

View File

@ -227,10 +227,15 @@ impl INode for NetworkManager {
game.bind_mut().handle_jump(player_id);
}
}
Package::Shoot(player_id, transform, look_up) => {
Package::Shoot(player_id, to, transform, look_up) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut()
.handle_shoot(player_id, transform, look_up, false);
game.bind_mut().handle_shoot(
player_id,
to.into(),
transform,
look_up,
false,
);
}
}
_ => {}
@ -384,7 +389,7 @@ impl INode for NetworkManager {
}
}
}
Package::Shoot(_, transform, look_up) => {
Package::Shoot(_, to, transform, look_up) => {
if let Some(game) = &mut Game::singleton() {
let player = game
.bind()
@ -392,10 +397,14 @@ impl INode for NetworkManager {
.cloned();
if let Some(player) = player {
if game.bind_mut().handle_shoot(
player.id, transform, look_up, true,
player.id,
to.into(),
transform,
look_up,
true,
) {
peer.broadcast_reliable(Package::Shoot(
player.id, transform, look_up,
player.id, to, transform, look_up,
));
}
}
@ -531,7 +540,7 @@ pub enum Package {
Sync(HashMap<u16, SyncPackage>),
SelfSync(SyncPackage),
Jump(u16),
Shoot(u16, NetPlayerTransform, f32),
Shoot(u16, NetVector3, NetPlayerTransform, f32),
}
#[derive(Debug, Clone, Serialize, Deserialize)]

View File

@ -1,9 +1,9 @@
use std::f32::consts::PI;
use std::{f32::consts::PI, ops::Neg};
use godot::{
classes::{
AudioStreamPlayer3D, Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent,
InputEventMouseMotion, input::MouseMode,
InputEventMouseMotion, PhysicsRayQueryParameters3D, input::MouseMode,
},
obj::WithBaseField,
prelude::*,
@ -43,7 +43,7 @@ pub trait IPlayer {
fn get_look_up(&self) -> f32;
fn get_transform(&self) -> NetPlayerTransform;
fn jump(&mut self);
fn try_shoot(&mut self, deal_damage: bool) -> bool;
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool;
}
pub trait PlayerMovement {
@ -154,10 +154,10 @@ impl IPlayer for LocalPlayer {
fn apply_look_up(&mut self, _look: f32) {}
fn try_shoot(&mut self, deal_damage: bool) -> bool {
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
if self.shoot_cd <= 0. {
if let Some(weapon) = &mut self.weapon {
weapon.bind_mut().shoot(Vector3::ZERO, deal_damage);
weapon.bind_mut().shoot(to, deal_damage);
}
self.shoot_cd = 0.2;
true
@ -219,15 +219,52 @@ impl ICharacterBody3D for LocalPlayer {
fn input(&mut self, event: Gd<InputEvent>) {
if self.locked {
if event.is_action_pressed("shoot") {
let pos = if let Some(camera) = &self.camera {
let forward = camera.get_global_basis().col_c().neg();
let ray = PhysicsRayQueryParameters3D::create(
camera.get_global_position(),
camera.get_global_position() + forward * 10000.,
);
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) = 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 {
None
};
godot_print!("{:?}", pos);
if let Some(pos) = pos {
if let Some(peer) = &mut NetworkManager::singleton().bind_mut().peer {
match peer {
PeerKind::Client(peer, addr) => {
peer.send_reliable(addr, Shoot(0, self.get_transform(), self.look_up));
peer.send_reliable(
addr,
Shoot(0, pos.into(), self.get_transform(), self.look_up),
);
}
PeerKind::Server(peer, _) => {
if self.try_shoot(true) {
if self.try_shoot(pos, true) {
peer.broadcast_reliable(Shoot(
0,
pos.into(),
self.get_transform(),
self.look_up,
));
@ -236,6 +273,7 @@ impl ICharacterBody3D for LocalPlayer {
}
}
}
}
if let Ok(event) = event.try_cast::<InputEventMouseMotion>() {
let x = event.get_relative().x * 0.001 * self.look_sensitivity;
@ -343,10 +381,10 @@ impl IPlayer for RemotePlayer {
self.look_up = look;
}
fn try_shoot(&mut self, deal_damage: bool) -> bool {
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool {
if self.shoot_cd <= 0. {
if let Some(weapon) = &mut self.weapon {
weapon.bind_mut().shoot(Vector3::ZERO, deal_damage);
weapon.bind_mut().shoot(to, deal_damage);
}
self.shoot_cd = 0.2;
true

View File

@ -1,10 +1,17 @@
use godot::{classes::AudioStreamPlayer3D, prelude::*};
use godot::{
classes::{AudioStreamPlayer3D, GpuParticles3D, PhysicsRayQueryParameters3D},
prelude::*,
};
#[derive(GodotClass)]
#[class(base=Node3D, init)]
pub struct Weapon {
#[export]
sound_emitter: Option<Gd<AudioStreamPlayer3D>>,
#[export]
bullet_prefab: Option<Gd<PackedScene>>,
#[export]
bullet_source: Option<Gd<Node3D>>,
base: Base<Node3D>,
}
@ -14,5 +21,50 @@ impl Weapon {
if let Some(emitter) = &mut self.sound_emitter {
emitter.play();
}
if let Some(prefab) = &self.bullet_prefab {
let mut bullet = prefab.instantiate_as::<Bullet>();
if let Some(mut parent) = self.base().find_parent("map") {
parent.add_child(&bullet);
if let Some(source) = &self.bullet_source {
bullet.set_global_position(source.get_global_position());
}
}
bullet.bind_mut().target = Some(to);
}
}
}
#[derive(GodotClass)]
#[class(base=Node3D, init)]
pub struct Bullet {
#[export]
pub emitter: Option<Gd<GpuParticles3D>>,
pub target: Option<Vector3>,
alive_for: f64,
base: Base<Node3D>,
}
#[godot_api]
impl INode3D for Bullet {
fn ready(&mut self) {
if let Some(emitter) = &mut self.emitter {
emitter.set_emitting(true);
}
}
fn process(&mut self, delta: f64) {
self.alive_for += delta;
if self.alive_for > 0.05 {
let prev_pos = self.base().get_global_position();
if let Some(target) = self.target {
let new_pos = prev_pos.lerp(target, 0.5);
self.base_mut().set_position(new_pos);
}
}
}
}