diff --git a/godot/assets/Arrow.fbx b/godot/assets/Arrow.fbx new file mode 100644 index 0000000..8da886d Binary files /dev/null and b/godot/assets/Arrow.fbx differ diff --git a/godot/assets/Arrow.fbx.import b/godot/assets/Arrow.fbx.import new file mode 100644 index 0000000..7355480 --- /dev/null +++ b/godot/assets/Arrow.fbx.import @@ -0,0 +1,46 @@ +[remap] + +importer="scene" +importer_version=1 +type="PackedScene" +uid="uid://menoxw82ftvs" +path="res://.godot/imported/Arrow.fbx-6f0fbbfeb10245e69032bac7eca9b96f.scn" + +[deps] + +source_file="res://assets/Arrow.fbx" +dest_files=["res://.godot/imported/Arrow.fbx-6f0fbbfeb10245e69032bac7eca9b96f.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 diff --git a/godot/mesh/arrow.tscn b/godot/mesh/arrow.tscn new file mode 100644 index 0000000..0c74635 --- /dev/null +++ b/godot/mesh/arrow.tscn @@ -0,0 +1,15 @@ +[gd_scene format=3 uid="uid://d1audvg1rgiil"] + +[ext_resource type="PackedScene" uid="uid://menoxw82ftvs" path="res://assets/Arrow.fbx" id="1_5xuuv"] +[ext_resource type="Shader" uid="uid://dvevqws3wm717" path="res://shaders/arrow_shader.tres" id="2_jlas5"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_y75oq"] +render_priority = 0 +shader = ExtResource("2_jlas5") +shader_parameter/ColorParameter = Color(0, 0, 1, 1) +shader_parameter/MaxDistance = 40.0 + +[node name="Arrow" unique_id=2098940646 instance=ExtResource("1_5xuuv")] + +[node name="Cube" parent="." index="0" unique_id=1659384323] +surface_material_override/0 = SubResource("ShaderMaterial_y75oq") diff --git a/godot/raw_assets/Arrow/Arrow.blend b/godot/raw_assets/Arrow/Arrow.blend new file mode 100644 index 0000000..0cc5a46 Binary files /dev/null and b/godot/raw_assets/Arrow/Arrow.blend differ diff --git a/godot/raw_assets/Arrow/Arrow.blend1 b/godot/raw_assets/Arrow/Arrow.blend1 new file mode 100644 index 0000000..a97a30b Binary files /dev/null and b/godot/raw_assets/Arrow/Arrow.blend1 differ diff --git a/godot/scenes/misc/arrow.tscn b/godot/scenes/misc/arrow.tscn new file mode 100644 index 0000000..3c70c28 --- /dev/null +++ b/godot/scenes/misc/arrow.tscn @@ -0,0 +1,9 @@ +[gd_scene format=3 uid="uid://bnha3gon4700q"] + +[ext_resource type="PackedScene" uid="uid://d1audvg1rgiil" path="res://mesh/arrow.tscn" id="1_w20fr"] + +[node name="arrow" type="Arrow" unique_id=1231591993 node_paths=PackedStringArray("mesh")] +mesh = NodePath("Arrow") + +[node name="Arrow" parent="." unique_id=2098940646 instance=ExtResource("1_w20fr")] +transform = Transform3D(0.8991433, 0, -0.43765438, 0, 1, 0, 0.43765438, 0, 0.8991433, 0, -0.07870276, 0) diff --git a/godot/scenes/misc/ball.tscn b/godot/scenes/misc/ball.tscn index 004c71b..0390a43 100644 --- a/godot/scenes/misc/ball.tscn +++ b/godot/scenes/misc/ball.tscn @@ -11,6 +11,7 @@ [ext_resource type="AudioStream" uid="uid://ca2x04htf0mpi" path="res://raw_assets/sfx/ball/7.ogg" id="8_xuvta"] [ext_resource type="AudioStream" uid="uid://ba5rkh12mwy7o" path="res://raw_assets/sfx/ball/8.ogg" id="9_yu13l"] [ext_resource type="AudioStream" uid="uid://0vmjtq6uxsqe" path="res://raw_assets/sfx/ball/9.ogg" id="10_p4exv"] +[ext_resource type="PackedScene" uid="uid://bnha3gon4700q" path="res://scenes/misc/arrow.tscn" id="12_of30w"] [sub_resource type="SphereShape3D" id="SphereShape3D_1cgct"] @@ -44,3 +45,5 @@ bus = &"SFX" [node name="SkeletonHead" parent="." unique_id=1848024401 instance=ExtResource("3_thun5")] transform = Transform3D(0.45, 0, 0, 0, 0.45, 0, 0, 0, 0.45, 0, 0, -0.046112746) + +[node name="arrow" parent="." unique_id=1231591993 instance=ExtResource("12_of30w")] diff --git a/godot/scenes/player/remote_player.tscn b/godot/scenes/player/remote_player.tscn index 80ac201..d891a5c 100644 --- a/godot/scenes/player/remote_player.tscn +++ b/godot/scenes/player/remote_player.tscn @@ -4,6 +4,7 @@ [ext_resource type="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/effects.tscn" id="2_orxjf"] [ext_resource type="AudioStream" uid="uid://cl416orgv11vj" path="res://raw_assets/sfx/ball/little_robot_sound_factory_fantasy_Inventory_Open_00.mp3" id="3_840kl"] [ext_resource type="AudioStream" uid="uid://uq0o8gkpqhfa" path="res://raw_assets/sfx/ball/zapsplat_foley_stick_swing_air_whoosh_very_fast_hard_003_110413.mp3" id="4_qn18y"] +[ext_resource type="PackedScene" uid="uid://bnha3gon4700q" path="res://scenes/misc/arrow.tscn" id="5_qn18y"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"] @@ -37,7 +38,7 @@ curve = SubResource("Curve_qn18y") [sub_resource type="ViewportTexture" id="ViewportTexture_rmxnb"] viewport_path = NodePath("double_health_bar_sprite/health_bar_viewport") -[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "camera_origin", "name_label", "health_bar", "double_health_bar", "health_bar_sprite", "double_health_bar_sprite", "ball_pickup_sfx", "ball_throw_sfx")] +[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "camera_origin", "name_label", "health_bar", "double_health_bar", "health_bar_sprite", "double_health_bar_sprite", "ball_pickup_sfx", "ball_throw_sfx", "arrow")] move_speed = 7.0 soldier_mesh = NodePath("soldier_m") collider = NodePath("collision_shape_3d") @@ -53,6 +54,7 @@ health_bar_sprite = NodePath("health_bar_sprite") double_health_bar_sprite = NodePath("double_health_bar_sprite") ball_pickup_sfx = NodePath("ball_pickup_sfx") ball_throw_sfx = NodePath("ball_throw_sfx") +arrow = NodePath("arrow") telegrenade_cd = 10.0 collision_layer = 2 collision_mask = 4 @@ -140,3 +142,6 @@ bus = &"SFX" [node name="ball_throw_sfx" type="AudioStreamPlayer3D" parent="." unique_id=198255565] stream = ExtResource("4_qn18y") bus = &"SFX" + +[node name="arrow" parent="." unique_id=1231591993 instance=ExtResource("5_qn18y")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6812112, 0) diff --git a/godot/scenes/player/replay_player.tscn b/godot/scenes/player/replay_player.tscn index 168e7f1..e49faab 100644 --- a/godot/scenes/player/replay_player.tscn +++ b/godot/scenes/player/replay_player.tscn @@ -4,6 +4,7 @@ [ext_resource type="PackedScene" uid="uid://cl66unms2gim0" path="res://scenes/player/effects.tscn" id="2_rejks"] [ext_resource type="AudioStream" uid="uid://cl416orgv11vj" path="res://raw_assets/sfx/ball/little_robot_sound_factory_fantasy_Inventory_Open_00.mp3" id="3_o85ek"] [ext_resource type="AudioStream" uid="uid://uq0o8gkpqhfa" path="res://raw_assets/sfx/ball/zapsplat_foley_stick_swing_air_whoosh_very_fast_hard_003_110413.mp3" id="4_fwayu"] +[ext_resource type="PackedScene" uid="uid://bnha3gon4700q" path="res://scenes/misc/arrow.tscn" id="5_fwayu"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_1cgct"] @@ -37,7 +38,7 @@ curve = SubResource("Curve_qn18y") [sub_resource type="ViewportTexture" id="ViewportTexture_bfcd3"] viewport_path = NodePath("double_health_bar_sprite/double_health_bar_viewport") -[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "camera_origin", "name_label", "health_bar", "double_health_bar", "health_bar_sprite", "double_health_bar_sprite", "ball_pickup_sfx", "ball_throw_sfx")] +[node name="player" type="RemotePlayer" unique_id=845968872 node_paths=PackedStringArray("soldier_mesh", "collider", "effects", "spectator_camera", "camera_origin", "name_label", "health_bar", "double_health_bar", "health_bar_sprite", "double_health_bar_sprite", "ball_pickup_sfx", "ball_throw_sfx", "arrow")] move_speed = 5.0 soldier_mesh = NodePath("soldier_m") collider = NodePath("collision_shape_3d") @@ -53,6 +54,7 @@ health_bar_sprite = NodePath("health_bar_sprite") double_health_bar_sprite = NodePath("double_health_bar_sprite") ball_pickup_sfx = NodePath("ball_pickup_sfx") ball_throw_sfx = NodePath("ball_throw_sfx") +arrow = NodePath("arrow") collision_layer = 16 collision_mask = 4 @@ -137,3 +139,6 @@ bus = &"SFX" [node name="ball_throw_sfx" type="AudioStreamPlayer3D" parent="." unique_id=1825805271] stream = ExtResource("4_fwayu") bus = &"SFX" + +[node name="arrow" parent="." unique_id=1231591993 instance=ExtResource("5_fwayu")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.6812112, 0) diff --git a/godot/shaders/arrow_shader.tres b/godot/shaders/arrow_shader.tres new file mode 100644 index 0000000..457fe2b --- /dev/null +++ b/godot/shaders/arrow_shader.tres @@ -0,0 +1,70 @@ +[gd_resource type="VisualShader" format=3 uid="uid://dvevqws3wm717"] + +[sub_resource type="VisualShaderNodeColorParameter" id="VisualShaderNodeColorParameter_lero3"] +parameter_name = "ColorParameter" +default_value_enabled = true + +[sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_krsme"] +default_input_values = [0, 0.0, 1, 1.0] +operator = 7 + +[sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_krsme"] +input_name = "camera_position_world" + +[sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_ed1nm"] +input_name = "vertex" + +[sub_resource type="VisualShaderNodeVectorOp" id="VisualShaderNodeVectorOp_j5yvs"] +operator = 1 + +[sub_resource type="VisualShaderNodeVectorDistance" id="VisualShaderNodeVectorDistance_511aq"] + +[sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_uhsfa"] +default_input_values = [0, 0.0, 1, 30.0] +operator = 3 + +[sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_mkhfx"] +default_input_values = [0, 0.0, 1, 10.0] +operator = 1 + +[sub_resource type="VisualShaderNodeFloatOp" id="VisualShaderNodeFloatOp_7bf0g"] +operator = 6 + +[sub_resource type="VisualShaderNodeFloatParameter" id="VisualShaderNodeFloatParameter_jxonh"] +parameter_name = "MaxDistance" +default_value_enabled = true +default_value = 100.0 + +[sub_resource type="VisualShaderNodeInput" id="VisualShaderNodeInput_lero3"] +input_name = "vertex" + +[resource] +flags/depth_test_disabled = true +flags/unshaded = true +flags/world_vertex_coords = true +nodes/vertex/0/position = Vector2(630, 150) +nodes/vertex/2/node = SubResource("VisualShaderNodeInput_lero3") +nodes/vertex/2/position = Vector2(307.9943, 117.82249) +nodes/vertex/connections = PackedInt32Array(2, 0, 0, 0) +nodes/fragment/0/position = Vector2(1000, 110) +nodes/fragment/2/node = SubResource("VisualShaderNodeInput_krsme") +nodes/fragment/2/position = Vector2(-890, 120) +nodes/fragment/3/node = SubResource("VisualShaderNodeInput_ed1nm") +nodes/fragment/3/position = Vector2(-890, -10) +nodes/fragment/4/node = SubResource("VisualShaderNodeVectorOp_j5yvs") +nodes/fragment/4/position = Vector2(-550, -30) +nodes/fragment/5/node = SubResource("VisualShaderNodeVectorDistance_511aq") +nodes/fragment/5/position = Vector2(-360, 0) +nodes/fragment/6/node = SubResource("VisualShaderNodeFloatOp_uhsfa") +nodes/fragment/6/position = Vector2(400, 150) +nodes/fragment/7/node = SubResource("VisualShaderNodeFloatOp_mkhfx") +nodes/fragment/7/position = Vector2(-80, 100) +nodes/fragment/8/node = SubResource("VisualShaderNodeFloatOp_7bf0g") +nodes/fragment/8/position = Vector2(120, 100) +nodes/fragment/9/node = SubResource("VisualShaderNodeFloatParameter_jxonh") +nodes/fragment/9/position = Vector2(-460, 310) +nodes/fragment/11/node = SubResource("VisualShaderNodeColorParameter_lero3") +nodes/fragment/11/position = Vector2(310, -110) +nodes/fragment/12/node = SubResource("VisualShaderNodeFloatOp_krsme") +nodes/fragment/12/position = Vector2(690, 190) +nodes/fragment/connections = PackedInt32Array(3, 0, 4, 0, 2, 0, 4, 1, 4, 0, 5, 0, 5, 0, 7, 0, 7, 0, 8, 0, 8, 0, 6, 0, 9, 0, 7, 1, 11, 0, 0, 0, 6, 0, 12, 0, 12, 0, 0, 1) diff --git a/rust/src/arrow.rs b/rust/src/arrow.rs new file mode 100644 index 0000000..4281306 --- /dev/null +++ b/rust/src/arrow.rs @@ -0,0 +1,28 @@ +use godot::{classes::MeshInstance3D, prelude::*}; + +#[derive(GodotClass)] +#[class(base=Node3D, init, tool)] +pub struct Arrow { + #[export] + mesh: Option>, + elapsed: f64, + + base: Base, +} + +#[godot_api] +impl INode3D for Arrow { + fn process(&mut self, delta: f64) { + self.elapsed += delta; + + let global_pos = self.base().get_global_position(); + if let Some(mesh) = &mut self.mesh { + mesh.set_global_position( + global_pos + + Vector3::UP * 2. + + Vector3::UP * (self.elapsed * 2.).sin() as f32 / 10., + ); + mesh.set_global_rotation(Vector3::UP * self.elapsed as f32); + } + } +} diff --git a/rust/src/lib.rs b/rust/src/lib.rs index c9b4d1b..855e515 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -1,6 +1,7 @@ use godot::prelude::*; pub mod announcer; +pub mod arrow; pub mod bgm; pub mod chat; pub mod cli_parser; diff --git a/rust/src/player/remote_player.rs b/rust/src/player/remote_player.rs index b02ff1f..cc37862 100644 --- a/rust/src/player/remote_player.rs +++ b/rust/src/player/remote_player.rs @@ -55,6 +55,8 @@ pub struct RemotePlayer { ball_pickup_sfx: Option>, #[export] ball_throw_sfx: Option>, + #[export] + arrow: Option>, pub player_id: Option, pub player_name: String, @@ -238,19 +240,26 @@ impl IPlayer for RemotePlayer { self.drop_ball(true); } + if let Some(arrow) = &mut self.arrow { + arrow.set_visible(false); + } + if let Some(mesh) = &mut self.soldier_mesh { match weapon { WeaponType::Raygun => { mesh.bind_mut().spawn_raygun(); - if let Some(ball_pickup_sfx) = &mut self.ball_pickup_sfx { - ball_pickup_sfx.play(); - } } WeaponType::Shotgun => { mesh.bind_mut().spawn_shotgun(); } WeaponType::Ball => { mesh.bind_mut().spawn_ball(); + if let Some(ball_pickup_sfx) = &mut self.ball_pickup_sfx { + ball_pickup_sfx.play(); + } + if let Some(arrow) = &mut self.arrow { + arrow.set_visible(true); + } } }; } @@ -373,6 +382,10 @@ impl ICharacterBody3D for RemotePlayer { }; }); + if let Some(arrow) = &mut self.arrow { + arrow.set_visible(false); + } + self.buffs.clone().update_effects(self); }