Compare commits

..

7 Commits

Author SHA1 Message Date
79f223cb21 Add proper shooting effect 2026-07-20 01:46:51 +03:00
dc30551227 Add simple shooting 2026-07-19 23:06:52 +03:00
7c5dbd3a9f Add shooting 2026-07-19 22:49:21 +03:00
38743e850a Use look-at modifiers 2026-07-19 22:16:04 +03:00
35cfad6358 Implement some sort of look up rotation 2026-07-19 21:50:17 +03:00
1bb646b3c2 Add a lot of assets, add player model somewhat 2026-07-19 20:41:14 +03:00
eb20849844 Update gdextension for cross-compiling for windows 2026-07-19 18:57:03 +03:00
51 changed files with 1201 additions and 72 deletions

View File

@ -6,8 +6,8 @@ reloadable = true
[libraries]
linux.debug.x86_64 = "res://../target/debug/libquakeball.so"
linux.release.x86_64 = "res://../target/release/libquakeball.so"
windows.debug.x86_64 = "res://../target/debug/quakeball.dll"
windows.release.x86_64 = "res://../target/release/quakeball.dll"
windows.debug.x86_64 = "res://../target/x86_64-pc-windows-gnu/debug/quakeball.dll"
windows.release.x86_64 = "res://../target/x86_64-pc-windows-gnu/release/quakeball.dll"
macos.debug = "res://../target/debug/libquakeball.dylib"
macos.release = "res://../target/release/libquakeball.dylib"
macos.debug.arm64 = "res://../target/debug/libquakeball.dylib"

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
godot/assets/Gear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,41 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c7epv5p0qau02"
path.s3tc="res://.godot/imported/Gear.png-4a33d7121b716ce6c6e8a5c001bd6bc4.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
[deps]
source_file="res://assets/Gear.png"
dest_files=["res://.godot/imported/Gear.png-4a33d7121b716ce6c6e8a5c001bd6bc4.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

BIN
godot/assets/Hit.mp3 Normal file

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://bfg31e3s4jv8c"
path="res://.godot/imported/Hit.mp3-1e43ad11df7f4d135dfebfbf61e21305.mp3str"
[deps]
source_file="res://assets/Hit.mp3"
dest_files=["res://.godot/imported/Hit.mp3-1e43ad11df7f4d135dfebfbf61e21305.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

BIN
godot/assets/LaserFast.mp3 Normal file

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://dw5vleoexlhwx"
path="res://.godot/imported/LaserFast.mp3-7950076d801cb865e24808499aec09df.mp3str"
[deps]
source_file="res://assets/LaserFast.mp3"
dest_files=["res://.godot/imported/LaserFast.mp3-7950076d801cb865e24808499aec09df.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

BIN
godot/assets/LaserShot.ogg Normal file

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://dlsto2l7tudif"
path="res://.godot/imported/LaserShot.ogg-6aac68be79c568543c2853d102341790.oggvorbisstr"
[deps]
source_file="res://assets/LaserShot.ogg"
dest_files=["res://.godot/imported/LaserShot.ogg-6aac68be79c568543c2853d102341790.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="mp3"
type="AudioStreamMP3"
uid="uid://cqboecwvt1cp8"
path="res://.godot/imported/LaserWithRecovery.mp3-10fbe4c1e5d75ceb94f91b483f19f811.mp3str"
[deps]
source_file="res://assets/LaserWithRecovery.mp3"
dest_files=["res://.godot/imported/LaserWithRecovery.mp3-10fbe4c1e5d75ceb94f91b483f19f811.mp3str"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

Binary file not shown.

View File

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://xxpkjhaovyd"
path="res://.godot/imported/LaserWithRecoveryEdited.ogg-7b52758d22998fcb799b2fc8da1b30b1.oggvorbisstr"
[deps]
source_file="res://assets/LaserWithRecoveryEdited.ogg"
dest_files=["res://.godot/imported/LaserWithRecoveryEdited.ogg-7b52758d22998fcb799b2fc8da1b30b1.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

BIN
godot/assets/Raygun.fbx Normal file

Binary file not shown.

View File

@ -0,0 +1,46 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://ckl63r2rgqra7"
path="res://.godot/imported/Raygun.fbx-2973e1d298710d4aade91960a0085ed7.scn"
[deps]
source_file="res://assets/Raygun.fbx"
dest_files=["res://.godot/imported/Raygun.fbx-2973e1d298710d4aade91960a0085ed7.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=true
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
fbx/naming_version=2

BIN
godot/assets/Soldier.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cbvxh8xp8ilac"
path="res://.godot/imported/Soldier.png-df8ce7c3aef599e55e465baf8a8fb940.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/Soldier.png"
dest_files=["res://.godot/imported/Soldier.png-df8ce7c3aef599e55e465baf8a8fb940.ctex"]
[params]
compress/mode=0
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

BIN
godot/assets/SoldierF.fbx Normal file

Binary file not shown.

View File

@ -0,0 +1,46 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://hoh8hhdo2epf"
path="res://.godot/imported/SoldierF.fbx-a9563c4d0e146b777cf04292b446b71b.scn"
[deps]
source_file="res://assets/SoldierF.fbx"
dest_files=["res://.godot/imported/SoldierF.fbx-a9563c4d0e146b777cf04292b446b71b.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=true
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
fbx/naming_version=2

BIN
godot/assets/SoldierM.fbx Normal file

Binary file not shown.

View File

@ -0,0 +1,46 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://dk6l25ooah3ap"
path="res://.godot/imported/SoldierM.fbx-337e6d55347223adba2f34b068add0bd.scn"
[deps]
source_file="res://assets/SoldierM.fbx"
dest_files=["res://.godot/imported/SoldierM.fbx-337e6d55347223adba2f34b068add0bd.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/root_script=null
mesh_library/use_node_names_as_mesh_names=false
array_mesh/deduplicate_surfaces=true
nodes/apply_root_scale=true
nodes/root_scale=1.0
nodes/import_as_skeleton_bones=false
nodes/use_name_suffixes=true
nodes/use_node_type_suffixes=true
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=true
animation/remove_immutable_tracks=true
animation/import_rest_as_RESET=false
import_script/path=""
materials/extract=0
materials/extract_format=0
materials/extract_path=""
_subresources={}
fbx/importer=0
fbx/allow_geometry_helper_nodes=false
fbx/embedded_image_handling=1
fbx/naming_version=2

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

77
godot/export_presets.cfg Normal file
View File

@ -0,0 +1,77 @@
[runnable_presets]
"Windows Desktop"="Windows Desktop"
[preset.0]
name="Windows Desktop"
platform="Windows Desktop"
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path="dist/quakeball.exe"
patches=PackedStringArray()
patch_delta_encoding=false
patch_delta_compression_level_zstd=19
patch_delta_min_reduction=0.1
patch_delta_include_filters="*"
patch_delta_exclude_filters=""
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2
[preset.0.options]
custom_template/debug=""
custom_template/release=""
debug/export_console_wrapper=1
binary_format/embed_pck=false
texture_format/s3tc_bptc=true
texture_format/etc2_astc=false
shader_baker/enabled=false
binary_format/architecture="x86_64"
codesign/enable=false
codesign/timestamp=true
codesign/timestamp_server_url=""
codesign/digest_algorithm=1
codesign/description=""
codesign/custom_options=PackedStringArray()
application/modify_resources=true
application/icon=""
application/console_wrapper_icon=""
application/icon_interpolation=4
application/file_version=""
application/product_version=""
application/company_name=""
application/product_name=""
application/file_description=""
application/copyright=""
application/trademarks=""
application/export_angle=0
application/export_d3d12=0
application/d3d12_agility_sdk_multiarch=true
ssh_remote_deploy/enabled=false
ssh_remote_deploy/host="user@host_ip"
ssh_remote_deploy/port="22"
ssh_remote_deploy/extra_args_ssh=""
ssh_remote_deploy/extra_args_scp=""
ssh_remote_deploy/run_script="Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'
$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'
$trigger = New-ScheduledTaskTrigger -Once -At 00:00
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
$task = New-ScheduledTask -Action $action -Trigger $trigger -Settings $settings
Register-ScheduledTask godot_remote_debug -InputObject $task -Force:$true
Start-ScheduledTask -TaskName godot_remote_debug
while (Get-ScheduledTask -TaskName godot_remote_debug | ? State -eq running) { Start-Sleep -Milliseconds 100 }
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue"
ssh_remote_deploy/cleanup_script="Stop-ScheduledTask -TaskName godot_remote_debug -ErrorAction:SilentlyContinue
Unregister-ScheduledTask -TaskName godot_remote_debug -Confirm:$false -ErrorAction:SilentlyContinue
Remove-Item -Recurse -Force '{temp_dir}'"
dotnet/include_scripts_content=false
dotnet/include_debug_symbols=true
dotnet/embed_build_outputs=false

View File

@ -0,0 +1,7 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://d3rjo75pb7dvx"]
[ext_resource type="Texture2D" uid="uid://c7epv5p0qau02" path="res://assets/Gear.png" id="1_qr2ym"]
[resource]
albedo_texture = ExtResource("1_qr2ym")
texture_filter = 0

View File

@ -0,0 +1,7 @@
[gd_resource type="StandardMaterial3D" format=3 uid="uid://ynnhfjaijwf2"]
[ext_resource type="Texture2D" uid="uid://cbvxh8xp8ilac" path="res://assets/Soldier.png" id="1_1r3w7"]
[resource]
albedo_texture = ExtResource("1_1r3w7")
texture_filter = 0

9
godot/mesh/raygun.tscn Normal file
View File

@ -0,0 +1,9 @@
[gd_scene format=3 uid="uid://cg81784ct8gf5"]
[ext_resource type="PackedScene" uid="uid://ckl63r2rgqra7" path="res://assets/Raygun.fbx" id="1_njit6"]
[ext_resource type="Material" uid="uid://d3rjo75pb7dvx" path="res://mesh/materials/gear.tres" id="2_81k8r"]
[node name="Raygun" unique_id=1928455392 instance=ExtResource("1_njit6")]
[node name="Sniper_Rifle" parent="." index="0" unique_id=1373814885]
surface_material_override/0 = ExtResource("2_81k8r")

View File

@ -0,0 +1,9 @@
[gd_scene format=3 uid="uid://c5es36uh06m3s"]
[ext_resource type="PackedScene" uid="uid://hoh8hhdo2epf" path="res://assets/SoldierF.fbx" id="1_22b8v"]
[ext_resource type="Material" uid="uid://ynnhfjaijwf2" path="res://mesh/materials/soldier_material.tres" id="2_eabro"]
[node name="SoldierF" unique_id=686733085 instance=ExtResource("1_22b8v")]
[node name="Soldier_Female_Mesh" parent="Soldier_Female/Skeleton3D" parent_id_path=PackedInt32Array(210736176) index="0" unique_id=1355420912]
surface_material_override/0 = ExtResource("2_eabro")

33
godot/mesh/soldier_m.tscn Normal file
View File

@ -0,0 +1,33 @@
[gd_scene format=3 uid="uid://ncxcmgdit2j1"]
[ext_resource type="PackedScene" uid="uid://dk6l25ooah3ap" path="res://assets/SoldierM.fbx" id="1_bn1bx"]
[ext_resource type="Texture2D" uid="uid://cbvxh8xp8ilac" path="res://assets/Soldier.png" id="2_n4j5p"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_n4j5p"]
albedo_texture = ExtResource("2_n4j5p")
texture_filter = 0
[node name="SoldierM" unique_id=1868587353 instance=ExtResource("1_bn1bx")]
[node name="Male_IK_HAND_R" parent="Aim_Control" parent_id_path=PackedInt32Array(1488925479) index="1" unique_id=1011336848]
transform = Transform3D(0.005883459, -0.29583848, 0.4030446, -0.40563864, 0.23280492, 0.17680238, -0.29227144, -0.3290613, -0.23726773, 0.005743145, 1.1526048e-05, -0.001571659)
[node name="Skeleton3D" parent="Soldier" parent_id_path=PackedInt32Array(1731022909) index="0" unique_id=1317624294]
bones/2/rotation = Quaternion(0.95160115, 2.0944638e-08, 2.3653786e-08, -0.30733573)
bones/3/rotation = Quaternion(-0.35209325, 4.091232e-08, 1.5390487e-08, 0.93596494)
bones/4/rotation = Quaternion(0.7398268, -2.6881363e-08, 7.0005823e-09, 0.6727974)
bones/6/rotation = Quaternion(0.99905884, 1.7840092e-08, 1.8974825e-08, 0.043377537)
bones/7/rotation = Quaternion(-0.21973659, 4.264305e-08, 9.6049915e-09, 0.9755593)
bones/8/rotation = Quaternion(0.86758906, -7.8677225e-09, 3.0368508e-08, 0.49728197)
bones/10/rotation = Quaternion(-0.17222604, -0.13130432, 0.022178583, 0.9760151)
bones/11/rotation = Quaternion(-7.566992e-10, 4.6566073e-10, -9.313229e-10, 1)
bones/14/rotation = Quaternion(0.88124394, 0.03244469, 0.43789235, -0.17494844)
bones/15/rotation = Quaternion(-1.1794475e-08, 6.1331285e-08, 0.9187617, 0.39481288)
bones/16/rotation = Quaternion(0.029948184, -0.036407195, -0.18585202, 0.9814462)
bones/18/rotation = Quaternion(0.6445215, 0.21459225, -0.094257906, -0.72777593)
bones/19/rotation = Quaternion(-1.332124e-08, -2.4520514e-08, -0.15752357, 0.98751533)
bones/20/rotation = Quaternion(-0.14214668, -0.45634764, -0.17772992, 0.86020535)
bones/22/position = Vector3(0.012593047, -0.0085772155, 0.0021641199)
[node name="Soldier_Male_Mesh" parent="Soldier/Skeleton3D" index="0" unique_id=1081951616]
surface_material_override/0 = SubResource("StandardMaterial3D_n4j5p")

View File

@ -35,6 +35,10 @@ project/assembly_name="QuakeBall"
naming/node_name_casing=2
[filesystem]
import/blender/enabled=false
[input]
toggle_cli={
@ -69,6 +73,11 @@ jump={
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":32,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
]
}
shoot={
"deadzone": 0.2,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
[physics]

View File

@ -1,21 +0,0 @@
[gd_scene format=3 uid="uid://ct70bpbca8one"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_1cgct"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
[node name="player" type="LocalPlayer" unique_id=863055906 node_paths=PackedStringArray("camera")]
look_sensitivity = 1.5
camera = NodePath("camera_3d")
move_speed = 5.0
collision_mask = 2
[node name="mesh_instance_3d" type="MeshInstance3D" parent="." unique_id=700336478]
mesh = SubResource("CapsuleMesh_1cgct")
[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1110995513]
shape = SubResource("CapsuleShape3D_1cgct")
[node name="camera_3d" type="Camera3D" parent="." unique_id=1773137418]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5391109, 0)
current = true

View File

@ -1,7 +1,7 @@
[gd_scene format=3 uid="uid://7iooamjot1tg"]
[ext_resource type="PackedScene" uid="uid://ct70bpbca8one" path="res://scenes/local_player.tscn" id="1_yjvui"]
[ext_resource type="PackedScene" uid="uid://kfxc0migw80o" path="res://scenes/remote_player.tscn" id="2_kcncr"]
[ext_resource type="PackedScene" uid="uid://ct70bpbca8one" path="res://scenes/player/local_player.tscn" id="1_yjvui"]
[ext_resource type="PackedScene" uid="uid://kfxc0migw80o" path="res://scenes/player/remote_player.tscn" id="2_kcncr"]
[sub_resource type="ImageTexture" id="ImageTexture_3vyb7"]
@ -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

@ -0,0 +1,23 @@
[gd_scene format=3 uid="uid://ct70bpbca8one"]
[ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_jd651"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_oh8vq"]
[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")
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.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)
shape = SubResource("CapsuleShape3D_oh8vq")

View File

@ -0,0 +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", "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

@ -0,0 +1,18 @@
[gd_scene format=3 uid="uid://kfxc0migw80o"]
[ext_resource type="PackedScene" uid="uid://bod6b3befmyt5" path="res://scenes/player/soldier_m.tscn" id="1_e2ekk"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh")]
move_speed = 5.0
soldier_mesh = NodePath("soldier_m")
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)
[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1110995513]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.0310049, 0)
shape = SubResource("CapsuleShape3D_1cgct")

View File

@ -0,0 +1,174 @@
[gd_scene format=3 uid="uid://bod6b3befmyt5"]
[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"]
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_a50o4"]
animation = &"Soldier|StrafeLeft"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_jbny0"]
animation = &"Soldier|StrafeRight"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_kknoo"]
animation = &"Soldier|Run"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_hjbn3"]
animation = &"Soldier|ReverseRun"
[sub_resource type="AnimationNodeAnimation" id="AnimationNodeAnimation_3lfhi"]
animation = &"Soldier|Idle"
[sub_resource type="AnimationNodeBlendSpace2D" id="AnimationNodeBlendSpace2D_tt88r"]
sync_mode = 2
blend_point_0/node = SubResource("AnimationNodeAnimation_a50o4")
blend_point_0/pos = Vector2(-1, 0)
blend_point_0/name = &"Soldier|StrafeLeft"
blend_point_1/node = SubResource("AnimationNodeAnimation_jbny0")
blend_point_1/pos = Vector2(1, 0)
blend_point_1/name = &"Soldier|StrafeRight"
blend_point_2/node = SubResource("AnimationNodeAnimation_kknoo")
blend_point_2/pos = Vector2(0, 1)
blend_point_2/name = &"Soldier|Run"
blend_point_3/node = SubResource("AnimationNodeAnimation_hjbn3")
blend_point_3/pos = Vector2(0, -1)
blend_point_3/name = &"Soldier|ReverseRun"
blend_point_4/node = SubResource("AnimationNodeAnimation_3lfhi")
blend_point_4/pos = Vector2(0, 0)
blend_point_4/name = &"Soldier|Idle"
[sub_resource type="AnimationNodeBlendTree" id="AnimationNodeBlendTree_kgpx5"]
graph_offset = Vector2(-81.14978, 126.45578)
nodes/output/position = Vector2(560, 100)
nodes/Movement/node = SubResource("AnimationNodeBlendSpace2D_tt88r")
nodes/Movement/position = Vector2(350, 90)
node_connections = [&"output", 0, &"Movement"]
[node name="soldier_m" type="SoldierMesh" unique_id=281995630 node_paths=PackedStringArray("hand_attachment", "animation_tree", "skeleton", "look_at")]
hand_attachment = NodePath("bone_attachment_3d/hand")
animation_tree = NodePath("animation_tree")
skeleton = NodePath("SoldierM/Soldier/Skeleton3D")
raygun = ExtResource("1_a50o4")
look_at = NodePath("look_at_root")
[node name="SoldierM" parent="." unique_id=1868587353 instance=ExtResource("1_sxefq")]
[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/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/scale = Vector3(1, 1, 1)
bones/3/position = Vector3(0, 0.0069999984, 5.169879e-25)
bones/3/scale = Vector3(1, 0.99999994, 1)
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/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)
bones/7/scale = Vector3(1, 0.99999994, 1)
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/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/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/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/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/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/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/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/scale = Vector3(1, 0.9999999, 1)
bones/22/position = Vector3(0.010811842, -0.0085772155, 0.0026515652)
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)
bones/24/rotation = Quaternion(3.090862e-08, 0.70710677, 0.70710677, 3.090862e-08)
bones/24/scale = Vector3(1, 1, 1)
bones/26/position = Vector3(0.0025000002, 0.005, 0.0045)
bones/26/rotation = Quaternion(3.090862e-08, 0.70710677, 0.70710677, 3.090862e-08)
bones/26/scale = Vector3(1, 1, 1)
bones/28/position = Vector3(-0.0025, 0.005, 0.0045)
bones/28/rotation = Quaternion(3.090862e-08, 0.70710677, 0.70710677, 3.090862e-08)
bones/28/scale = Vector3(1, 1, 1)
bones/30/position = Vector3(0.002, 0.012192632, -0.012331131)
bones/32/position = Vector3(-0.002, 0.012192632, -0.012331131)
bones/34/position = Vector3(0.002, 0.0031428207, -0.022681827)
bones/34/scale = Vector3(1, 1, 1)
bones/36/position = Vector3(-0.002, -0.00568604, -0.02264523)
bones/36/rotation = Quaternion(0, 0, 0, 1)
[node name="look_at_modifier_3d" type="LookAtModifier3D" parent="SoldierM/Soldier/Skeleton3D" index="1" unique_id=1054155740]
target_node = NodePath("../../../../look_at_root/look_at")
bone_name = "HEAD"
bone = 11
forward_axis = 5
origin_from = 2
origin_external_node = NodePath("../../../../look_at_root")
[node name="look_at_modifier_3d2" type="LookAtModifier3D" parent="SoldierM/Soldier/Skeleton3D" index="2" unique_id=916451501]
transform = Transform3D(1, -2.2737368e-13, 0, 2.2737368e-13, 1, 0, -1.3552527e-20, 0, 1, 0, 0, 0)
target_node = NodePath("../../../../look_at_root/look_at")
bone_name = "UA.R"
bone = 14
forward_axis = 1
relative = true
origin_from = 2
origin_external_node = NodePath("../../../../look_at_root")
[node name="look_at_modifier_3d3" type="LookAtModifier3D" parent="SoldierM/Soldier/Skeleton3D" index="3" unique_id=1721786929]
transform = Transform3D(1, -6.82121e-13, 0, 6.82121e-13, 1, 0, -4.065758e-20, 0, 1, 0, 0, 0)
target_node = NodePath("../../../../look_at_root/look_at")
bone_name = "UA.L"
bone = 18
forward_axis = 2
primary_rotation_axis = 2
relative = true
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)
bone_name = "HAND.R_end"
bone_idx = 17
use_external_skeleton = true
external_skeleton = NodePath("../SoldierM/Soldier/Skeleton3D")
[node name="hand" type="Node3D" parent="bone_attachment_3d" unique_id=171636900]
transform = Transform3D(0.0039180024, -0.013382489, -0.0055279233, 0.00012702314, 0.005758277, -0.013850107, 0.014478719, 0.0035708423, 0.0016173583, 0.003051471, -0.0019010007, -0.002960747)
[node name="animation_tree" type="AnimationTree" parent="." unique_id=1221968603]
root_node = NodePath("../SoldierM")
tree_root = SubResource("AnimationNodeBlendTree_kgpx5")
anim_player = NodePath("../SoldierM/AnimationPlayer")
parameters/Movement/blend_position = Vector2(0, 0)
[node name="look_at_root" type="Node3D" parent="." unique_id=107308061]
transform = Transform3D(1, 0, 0, 0, 1.0000001, 0, 0, 0, 1.0000001, 0, 3.7622375, 0)
[node name="look_at" type="Node3D" parent="look_at_root" unique_id=1308525699]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 2.698)
[editable path="SoldierM"]

View File

@ -1,15 +0,0 @@
[gd_scene format=3 uid="uid://kfxc0migw80o"]
[sub_resource type="CapsuleMesh" id="CapsuleMesh_1cgct"]
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"]
[node name="player" type="RemotePlayer" unique_id=845968872]
move_speed = 5.0
collision_mask = 2
[node name="mesh_instance_3d" type="MeshInstance3D" parent="." unique_id=700336478]
mesh = SubResource("CapsuleMesh_1cgct")
[node name="collision_shape_3d" type="CollisionShape3D" parent="." unique_id=1110995513]
shape = SubResource("CapsuleShape3D_1cgct")

View File

@ -10,7 +10,7 @@ use crate::{
network_manager::{
NetworkManager,
Package::{self, SelfSync},
PeerKind,
PeerKind, SyncPackage,
},
util::NetVector3,
},
@ -109,21 +109,27 @@ impl INode for Game {
.iter()
.find(|p| p.id == self.self_id.unwrap_or(0))
{
if let Some((dir, rot)) = &player.get_self_sync() {
peer.send_unreliable(
socket_addr,
SelfSync(dir.clone(), rot.clone()),
);
if let Some(data) = &player.get_self_sync() {
peer.send_unreliable(socket_addr, SelfSync(data.clone()));
}
}
}
PeerKind::Server(peer, _) => {
let mut sync_data = HashMap::new();
for player in &self.players {
if let (Some(dir), Some(transform)) =
(player.get_move_dir(), player.get_transform())
{
sync_data.insert(player.id, (dir, transform));
if let (Some(dir), Some(look_up), Some(transform)) = (
player.get_move_dir(),
player.get_look_up(),
player.get_transform(),
) {
sync_data.insert(
player.id,
SyncPackage {
movement_direction: dir,
look_up,
transform,
},
);
}
}
peer.broadcast_unreliable(Package::Sync(sync_data));
@ -288,13 +294,22 @@ impl Game {
}
}
pub fn handle_sync(&mut self, sync_data: HashMap<u16, (NetVector3, NetPlayerTransform)>) {
for (player_id, (dir, transform)) in sync_data {
pub fn handle_sync(&mut self, sync_data: HashMap<u16, SyncPackage>) {
for (
player_id,
SyncPackage {
movement_direction,
look_up,
transform,
},
) in sync_data
{
if let Some(player) = self.players.iter_mut().find(|p| p.id == player_id) {
if player.id != self.self_id.unwrap_or(0) {
// Sync remote players always
player.set_transform(transform);
player.set_move_dir(dir);
player.set_move_dir(movement_direction);
player.apply_look_up(look_up);
} else {
// Sync local player only if it's far enough
if let Some(local_net_transform) = player.get_transform() {
@ -316,6 +331,21 @@ 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(to, transform, look_up, deal_damage)
} else {
false
}
}
}
#[derive(Clone, Debug)]
@ -351,27 +381,41 @@ impl Player {
}
}
pub fn get_look_up(&self) -> Option<f32> {
if let Some(character) = &self.character {
Some(character.dyn_bind().get_look_up())
} else {
None
}
}
pub fn set_move_dir(&mut self, dir: NetVector3) {
if let Some(character) = &mut self.character {
character.dyn_bind_mut().set_movement_dir(dir.into());
}
}
pub fn get_self_sync(&self) -> Option<(NetVector3, NetVector3)> {
pub fn get_self_sync(&self) -> Option<SyncPackage> {
if let Some(character) = &self.character {
Some((
character.dyn_bind().get_movement_dir().into(),
character.dyn_bind().get_transform().rotation,
))
Some(SyncPackage {
movement_direction: character.dyn_bind().get_movement_dir().into(),
look_up: character.dyn_bind().get_look_up(),
transform: character.dyn_bind().get_transform(),
})
} else {
None
}
}
pub fn apply_self_sync(&mut self, dir: NetVector3, rot: NetVector3) {
pub fn apply_self_sync(&mut self, data: SyncPackage) {
if let Some(character) = &mut self.character {
character.dyn_bind_mut().set_movement_dir(dir.into());
character.dyn_bind_mut().apply_rotation(rot.into());
character
.dyn_bind_mut()
.set_movement_dir(data.movement_direction.into());
character
.dyn_bind_mut()
.apply_rotation(data.transform.rotation.into());
character.dyn_bind_mut().apply_look_up(data.look_up);
}
}
@ -380,6 +424,30 @@ impl Player {
character.dyn_bind_mut().jump();
}
}
pub fn apply_look_up(&mut self, rot: f32) {
if let Some(character) = &mut self.character {
character.dyn_bind_mut().apply_look_up(rot);
}
}
pub fn try_shoot(
&mut self,
to: Vector3,
transform: NetPlayerTransform,
look_up: f32,
deal_damage: bool,
) -> bool {
if let Some(character) = &mut self.character {
character
.dyn_bind_mut()
.apply_rotation(transform.rotation.into());
character.dyn_bind_mut().apply_look_up(look_up);
character.dyn_bind_mut().try_shoot(to, true)
} else {
false
}
}
}
#[derive(Debug, Serialize, Deserialize, Clone)]

View File

@ -7,7 +7,9 @@ pub mod map;
pub mod map_resource;
pub mod net;
pub mod player;
pub mod soldier_mesh;
pub mod ui;
pub mod weapon;
struct MyExtension;

View File

@ -227,6 +227,17 @@ impl INode for NetworkManager {
game.bind_mut().handle_jump(player_id);
}
}
Package::Shoot(player_id, to, transform, look_up) => {
if let Some(game) = &mut Game::singleton() {
game.bind_mut().handle_shoot(
player_id,
to.into(),
transform,
look_up,
false,
);
}
}
_ => {}
},
}
@ -356,13 +367,13 @@ impl INode for NetworkManager {
}
}
}
Package::SelfSync(dir, rot) => {
Package::SelfSync(sync_data) => {
if let Some(game) = &mut Game::singleton() {
if let Some(player) = &mut game
.bind_mut()
.find_player_by_addr_mut(&conn.address)
{
player.apply_self_sync(dir, rot);
player.apply_self_sync(sync_data);
}
}
}
@ -378,6 +389,27 @@ impl INode for NetworkManager {
}
}
}
Package::Shoot(_, to, transform, look_up) => {
if let Some(game) = &mut Game::singleton() {
let player = game
.bind()
.find_player_by_addr(&conn.address)
.cloned();
if let Some(player) = player {
if game.bind_mut().handle_shoot(
player.id,
to.into(),
transform,
look_up,
true,
) {
peer.broadcast_reliable(Package::Shoot(
player.id, to, transform, look_up,
));
}
}
}
}
_ => {}
},
}
@ -505,9 +537,17 @@ pub enum Package {
// Game packages
SpawnPlayer(u16, NetPlayerTransform),
Sync(HashMap<u16, (NetVector3, NetPlayerTransform)>),
SelfSync(NetVector3, NetVector3),
Sync(HashMap<u16, SyncPackage>),
SelfSync(SyncPackage),
Jump(u16),
Shoot(u16, NetVector3, NetPlayerTransform, f32),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SyncPackage {
pub movement_direction: NetVector3,
pub look_up: f32,
pub transform: NetPlayerTransform,
}
pub enum PeerKind {

View File

@ -1,9 +1,9 @@
use std::f32::consts::PI;
use std::{f32::consts::PI, ops::Neg};
use godot::{
classes::{
Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent, InputEventMouseMotion,
input::MouseMode,
AudioStreamPlayer3D, Camera3D, CharacterBody3D, ICharacterBody3D, Input, InputEvent,
InputEventMouseMotion, PhysicsRayQueryParameters3D, input::MouseMode,
},
obj::WithBaseField,
prelude::*,
@ -12,10 +12,16 @@ use serde::{Deserialize, Serialize};
use crate::{
net::{
network_manager::{NetworkManager, Package::Jump, PeerKind},
network_manager::{
NetworkManager,
Package::{Jump, Shoot},
PeerKind,
},
util::NetVector3,
},
soldier_mesh::SoldierMesh,
ui::cli::CommandLinePanel,
weapon::Weapon,
};
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
@ -33,8 +39,11 @@ pub trait IPlayer {
fn get_move_speed(&self) -> f32;
fn apply_transform(&mut self, transform: NetPlayerTransform);
fn apply_rotation(&mut self, rot: Vector3);
fn apply_look_up(&mut self, rot: f32);
fn get_look_up(&self) -> f32;
fn get_transform(&self) -> NetPlayerTransform;
fn jump(&mut self);
fn try_shoot(&mut self, to: Vector3, deal_damage: bool) -> bool;
}
pub trait PlayerMovement {
@ -70,11 +79,17 @@ pub struct LocalPlayer {
camera: Option<Gd<Camera3D>>,
#[export]
move_speed: f32,
#[export]
soldier_mesh: Option<Gd<SoldierMesh>>,
pub player_id: Option<u16>,
pub weapon: Option<Gd<Weapon>>,
movement_dir: Vector3,
y_speed: f32,
look_up: f32,
shoot_cd: f64,
locked: bool,
@ -132,6 +147,24 @@ impl IPlayer for LocalPlayer {
}
}
}
fn get_look_up(&self) -> f32 {
self.look_up
}
fn apply_look_up(&mut self, _look: f32) {}
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(to, deal_damage);
}
self.shoot_cd = 0.2;
true
} else {
false
}
}
}
#[godot_api]
@ -151,9 +184,15 @@ impl ICharacterBody3D for LocalPlayer {
.connect_other(self, |s| {
s.set_lock(true);
});
if let Some(mesh) = &mut self.soldier_mesh {
self.weapon = mesh.bind_mut().spawn_raygun();
}
}
fn process(&mut self, delta: f64) {
self.shoot_cd -= delta;
let input_direction = if self.locked {
let input = Input::singleton();
@ -170,11 +209,72 @@ impl ICharacterBody3D for LocalPlayer {
};
self.movement_dir = input_direction;
if let Some(mesh) = &mut self.soldier_mesh {
mesh.bind_mut().update_y_look(self.look_up);
}
self.player_update(delta);
}
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, pos.into(), self.get_transform(), self.look_up),
);
}
PeerKind::Server(peer, _) => {
if self.try_shoot(pos, true) {
peer.broadcast_reliable(Shoot(
0,
pos.into(),
self.get_transform(),
self.look_up,
));
}
}
}
}
}
}
if let Ok(event) = event.try_cast::<InputEventMouseMotion>() {
let x = event.get_relative().x * 0.001 * self.look_sensitivity;
let y = event.get_relative().y * 0.001 * self.look_sensitivity;
@ -184,6 +284,7 @@ impl ICharacterBody3D for LocalPlayer {
let x_rot =
(curr_rotation.x - y * self.look_sensitivity).clamp(-PI / 2., PI / 2.);
camera.set_rotation(Vector3::RIGHT * x_rot);
self.look_up = x_rot;
}
let y_rot = -x * self.look_sensitivity;
@ -209,11 +310,17 @@ impl LocalPlayer {
pub struct RemotePlayer {
#[export]
move_speed: f32,
#[export]
soldier_mesh: Option<Gd<SoldierMesh>>,
pub player_id: Option<u16>,
pub weapon: Option<Gd<Weapon>>,
movement_dir: Vector3,
y_speed: f32,
look_up: f32,
shoot_cd: f64,
base: Base<CharacterBody3D>,
}
@ -265,11 +372,46 @@ impl IPlayer for RemotePlayer {
fn jump(&mut self) {
self.set_y_speed(5.);
}
fn get_look_up(&self) -> f32 {
self.look_up
}
fn apply_look_up(&mut self, look: f32) {
self.look_up = look;
}
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(to, deal_damage);
}
self.shoot_cd = 0.2;
true
} else {
false
}
}
}
#[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();
}
}
fn process(&mut self, delta: f64) {
self.player_update(delta);
self.shoot_cd -= delta;
if let Some(mesh) = &mut self.soldier_mesh {
mesh.bind_mut()
.update_movement(Vector2::new(self.movement_dir.x, -self.movement_dir.z));
mesh.bind_mut().update_y_look(self.look_up);
}
}
}

63
rust/src/soldier_mesh.rs Normal file
View File

@ -0,0 +1,63 @@
use godot::{
classes::{
AnimationNodeBlendSpace2D, AnimationPlayer, AnimationTree, ISkeletonModifier3D, Skeleton3D,
SkeletonModifier3D,
},
prelude::*,
};
use crate::weapon::Weapon;
#[derive(GodotClass)]
#[class(base=Node3D, init)]
pub struct SoldierMesh {
#[export]
hand_attachment: Option<Gd<Node3D>>,
#[export]
animation_tree: Option<Gd<AnimationTree>>,
#[export]
skeleton: Option<Gd<Skeleton3D>>,
#[export]
raygun: Option<Gd<PackedScene>>,
#[export]
look_at: Option<Gd<Node3D>>,
base: Base<Node3D>,
}
#[godot_api]
impl INode3D for SoldierMesh {
fn ready(&mut self) {}
}
impl SoldierMesh {
pub fn update_movement(&mut self, movement: Vector2) {
if let Some(tree) = &mut self.animation_tree {
tree.set("parameters/Movement/blend_position", &movement.to_variant());
}
}
pub fn update_y_look(&mut self, rotation: f32) {
if let Some(node) = &mut self.look_at {
node.set_rotation(Vector3::RIGHT * -rotation);
}
}
pub fn spawn_raygun(&mut self) -> Option<Gd<Weapon>> {
if let Some(raygun) = &self.raygun {
let node = raygun.instantiate_as::<Weapon>();
self.spawn_weapon(node)
} else {
None
}
}
fn spawn_weapon(&mut self, node: Gd<Weapon>) -> Option<Gd<Weapon>> {
if let Some(hand) = &mut self.hand_attachment {
hand.add_child(&node);
Some(node)
} else {
None
}
}
}

70
rust/src/weapon.rs Normal file
View File

@ -0,0 +1,70 @@
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>,
}
impl Weapon {
pub fn shoot(&mut self, to: Vector3, deal_damage: bool) {
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);
}
}
}
}