diff --git a/entities/components/flag_carry_component.gd b/entities/components/flag_carry_component.gd index d33fcdc..4d869ec 100644 --- a/entities/components/flag_carry_component.gd +++ b/entities/components/flag_carry_component.gd @@ -41,7 +41,7 @@ func throw(inherited_velocity : Vector3, dropper : Player) -> void: _release(inherited_velocity, max_throw_speed, dropper) func _release(inherited_velocity : Vector3, throw_speed : float, dropper : Player) -> void: - if not _is_carrying(): + if not _is_carrying() or !is_inside_tree(): return # update carried flag global rotation based on component global rotation _carried_flag.global_rotation = Vector3(.0, global_rotation.y, .0) diff --git a/entities/flag/flag.tscn b/entities/flag/flag.tscn index 1b1a89a..b014f13 100644 --- a/entities/flag/flag.tscn +++ b/entities/flag/flag.tscn @@ -17,10 +17,10 @@ properties/0/replication_mode = 1 properties/1/path = NodePath(".:linear_velocity") properties/1/spawn = true properties/1/replication_mode = 1 -properties/2/path = NodePath("Smoothing/Mesh:visible") +properties/2/path = NodePath(".:visible") properties/2/spawn = true properties/2/replication_mode = 2 -properties/3/path = NodePath("Flag:state") +properties/3/path = NodePath(".:state") properties/3/spawn = true properties/3/replication_mode = 2 diff --git a/entities/player/player.gd b/entities/player/player.gd index 96d807b..3617bbd 100644 --- a/entities/player/player.gd +++ b/entities/player/player.gd @@ -16,7 +16,10 @@ class_name Player extends RigidBody3D enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD } -@export var iff : Control +signal died(player : Player, killer_id : int) +signal energy_changed(energy : float) + +@export var iff : IFF @export var health_component : HealthComponent @export var flag_carry_component : FlagCarryComponent @export var walkable_surface_sensor : ShapeCast3D @@ -50,12 +53,9 @@ enum PlayerState { PLAYER_ALIVE, PLAYER_DEAD } @onready var hud : CanvasLayer = $HUD @onready var animation_player : AnimationPlayer = $AnimationPlayer @onready var collision_shape : CollisionShape3D = $CollisionShape3D -@onready var jetpack_particles : Array = $Smoothing/ThirdPerson/Mesh/JetpackFX.get_children() +@onready var jetpack_particles : Array = $ThirdPerson/Mesh/JetpackFX.get_children() @onready var match_participant_component : MatchParticipantComponent = $MatchParticipantComponent -signal died(player : Player, killer_id : int) -signal energy_changed(energy : float) - var g : float = ProjectSettings.get_setting("physics/3d/default_gravity") # in m/s² var gravity : Vector3 = g * ProjectSettings.get_setting("physics/3d/default_gravity_vector") var _jumping : bool = false @@ -64,11 +64,14 @@ static var pawn_player : Player func _ready() -> void: match_participant_component.player_id_changed.connect(_setup_pawn) + match_participant_component.nickname_changed.connect(iff._on_username_changed) match_participant_component.player_id_changed.connect(input.update_multiplayer_authority) + health_component.health_changed.connect(hud._on_health_changed) health_component.health_changed.connect(iff._on_health_changed) health_component.health_changed.emit(health_component.health) health_component.health_zeroed.connect(die) + inventory.selection_changed.connect(_on_inventory_selection_changed) input.fired_primary.connect(_trigger) @@ -76,16 +79,14 @@ func _ready() -> void: input.throwed_flag.connect(_throw_flag) func _process(_delta : float) -> void: - if _is_player_dead(): - iff.hide() - return - else: - iff.show() - %Pivot.global_transform.basis = Basis.from_euler(Vector3(input.camera_rotation.y, input.camera_rotation.x, 0.0)) - if not _is_pawn(): tp_mesh.global_transform.basis = Basis.from_euler(Vector3(.0, input.camera_rotation.x + PI, 0.0)) + if match_participant_component and pawn_player: + if pawn_player.match_participant_component.team_id == match_participant_component.team_id: + iff.fill = Color.GREEN + else: + iff.fill = Color.RED func _physics_process(delta : float) -> void: _update_jetpack_energy(delta) @@ -95,8 +96,9 @@ func _setup_pawn(_new_player_id : int) -> void: camera.current = true camera.fov = Settings.get_value("video", "fov") pawn_player = self + iff.hide() else: - $Smoothing/ThirdPerson.show() + $ThirdPerson.show() %Inventory.hide() hud.hide() diff --git a/entities/player/player.tscn b/entities/player/player.tscn index 5ecea45..ae403d8 100644 --- a/entities/player/player.tscn +++ b/entities/player/player.tscn @@ -1,11 +1,11 @@ [gd_scene load_steps=45 format=3 uid="uid://cbhx1xme0sb7k"] [ext_resource type="Script" path="res://entities/player/player.gd" id="1_mk68k"] +[ext_resource type="PackedScene" uid="uid://bbeecp3jusppn" path="res://interfaces/hud/iffs/IFF.tscn" id="2_s5wgp"] [ext_resource type="PackedScene" uid="uid://bcv81ku26xo" path="res://interfaces/hud/hud.tscn" id="3_ccety"] [ext_resource type="Shape3D" uid="uid://cb8esdlnottdn" path="res://entities/player/resources/collider.tres" id="4_8kvcy"] [ext_resource type="Script" path="res://entities/components/match_participant_component.gd" id="6_lrose"] [ext_resource type="Script" path="res://entities/player/player_input.gd" id="6_ymcrr"] -[ext_resource type="PackedScene" uid="uid://dsysi2rd3bu76" path="res://interfaces/hud/iffs/iff.tscn" id="7_8hc80"] [ext_resource type="Script" path="res://entities/components/inventory.gd" id="8_768qh"] [ext_resource type="PackedScene" uid="uid://drbefw6akui2v" path="res://entities/player/vanguard.tscn" id="8_eiy7q"] [ext_resource type="Script" path="res://entities/components/flag_carry_component.gd" id="8_pdfbn"] @@ -217,14 +217,18 @@ physics_material_override = SubResource("PhysicsMaterial_clur0") can_sleep = false continuous_cd = true script = ExtResource("1_mk68k") -iff = NodePath("Smoothing/ThirdPerson/IFFAttachment/IFF") +iff = NodePath("IFF") health_component = NodePath("HealthComponent") flag_carry_component = NodePath("Pivot/FlagCarryComponent") walkable_surface_sensor = NodePath("WalkableSurfaceSensor") inventory = NodePath("Pivot/Inventory") -tp_mesh = NodePath("Smoothing/ThirdPerson/Mesh") +tp_mesh = NodePath("ThirdPerson/Mesh") jump_height = 1.5 +[node name="IFF" parent="." instance=ExtResource("2_s5wgp")] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.1, 0) +fill = Color(0, 1, 0, 1) + [node name="HealthComponent" type="Area3D" parent="." node_paths=PackedStringArray("match_participant_component")] script = ExtResource("14_ctgxn") match_participant_component = NodePath("../MatchParticipantComponent") @@ -300,19 +304,14 @@ mesh = NodePath("FlagMesh") [node name="FlagMesh" parent="Pivot/FlagCarryComponent" instance=ExtResource("18_7nkei")] -[node name="Smoothing" type="Node3D" parent="."] -script = ExtResource("11_k330l") -target = NodePath("..") -flags = 3 - -[node name="ThirdPerson" type="Node3D" parent="Smoothing"] +[node name="ThirdPerson" type="Node3D" parent="."] visible = false -[node name="Mesh" parent="Smoothing/ThirdPerson" node_paths=PackedStringArray("spine_ik_target_attachment") instance=ExtResource("8_eiy7q")] +[node name="Mesh" parent="ThirdPerson" node_paths=PackedStringArray("spine_ik_target_attachment") instance=ExtResource("8_eiy7q")] transform = Transform3D(-1, 0, -8.74228e-08, 0, 1, 0, 8.74228e-08, 0, -1, 0, 0, 0) -spine_ik_target_attachment = NodePath("../../../Pivot/SpineIKTarget") +spine_ik_target_attachment = NodePath("../../Pivot/SpineIKTarget") -[node name="Skeleton3D" parent="Smoothing/ThirdPerson/Mesh/Node" index="0"] +[node name="Skeleton3D" parent="ThirdPerson/Mesh/Node" index="0"] bones/0/position = Vector3(-0.0048219, 0.946668, 0.00678214) bones/0/rotation = Quaternion(-0.0341192, -0.409249, -0.0209221, 0.911545) bones/2/rotation = Quaternion(-0.00595832, -0.0014545, 0.0101407, 0.99993) @@ -365,52 +364,52 @@ bones/122/rotation = Quaternion(-0.494906, -0.0647935, 0.0183973, 0.866332) bones/124/rotation = Quaternion(0.417677, -0.0431149, 0.00625689, 0.90755) bones/126/rotation = Quaternion(0.397818, -0.0427722, -0.00601182, 0.916447) -[node name="HandAttachment" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D" index="0"] +[node name="HandAttachment" parent="ThirdPerson/Mesh/Node/Skeleton3D" index="0"] transform = Transform3D(-0.152214, 0.0548832, 0.986823, 0.933991, 0.334546, 0.125459, -0.323252, 0.94078, -0.102183, -0.261612, 1.14328, 0.0896011) -[node name="grip" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="0"] +[node name="grip" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="0"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.84217e-14, 1.19209e-07, 2.38419e-07) -[node name="main" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="1"] +[node name="main" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="1"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.84217e-14, 1.19209e-07, 2.38419e-07) -[node name="sides" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="2"] +[node name="sides" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh/Armature/Skeleton3D" index="2"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.84217e-14, 1.19209e-07, 2.38419e-07) -[node name="BarrelsInner" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="0"] +[node name="BarrelsInner" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="0"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.692504, 1.30946) -[node name="BarrelsOuter" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="1"] +[node name="BarrelsOuter" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="1"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.692504, 1.30946) -[node name="Base" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="2"] +[node name="Base" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="2"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.692504, 1.30946) -[node name="Grip" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="3"] +[node name="Grip" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun/Armature/Skeleton3D" index="3"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.692504, 1.30946) -[node name="Barrels" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun" index="3"] +[node name="Barrels" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun" index="3"] transform = Transform3D(-1, -1.49012e-08, 8.801e-08, 8.19564e-08, -3.72529e-09, 1, 0, 1, -7.45058e-09, 5.96046e-08, 0, -0.55315) -[node name="Skeleton3D" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature" index="0"] +[node name="Skeleton3D" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature" index="0"] bones/0/rotation = Quaternion(0, 0.707107, 0.707107, 0) bones/1/rotation = Quaternion(0, 0.707107, 0.707107, 0) bones/2/rotation = Quaternion(0, 0.707107, 0.707107, 0) bones/3/rotation = Quaternion(0, 0.707107, 0.707107, 0) -[node name="barrel" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="0"] +[node name="barrel" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="0"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.19209e-07, 0) -[node name="grip" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="1"] +[node name="grip" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="1"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.082471, -0.0653242) -[node name="main" parent="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="2"] +[node name="main" parent="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher/Armature/Skeleton3D" index="2"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.19209e-07, 0) -[node name="JetpackFX" type="Node3D" parent="Smoothing/ThirdPerson/Mesh"] +[node name="JetpackFX" type="Node3D" parent="ThirdPerson/Mesh"] transform = Transform3D(0.467164, -0.312366, -0.827155, -0.12476, 0.902867, -0.41142, 0.875325, 0.295397, 0.382816, 0.143745, 0.353192, -0.140279) -[node name="Smoke1" type="GPUParticles3D" parent="Smoothing/ThirdPerson/Mesh/JetpackFX"] +[node name="Smoke1" type="GPUParticles3D" parent="ThirdPerson/Mesh/JetpackFX"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.150648, 0) emitting = false lifetime = 0.5 @@ -419,7 +418,7 @@ fixed_fps = 60 process_material = SubResource("ParticleProcessMaterial_v556h") draw_pass_1 = SubResource("QuadMesh_hegkl") -[node name="Smoke2" type="GPUParticles3D" parent="Smoothing/ThirdPerson/Mesh/JetpackFX"] +[node name="Smoke2" type="GPUParticles3D" parent="ThirdPerson/Mesh/JetpackFX"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.108846, 0) emitting = false lifetime = 0.5 @@ -428,7 +427,7 @@ fixed_fps = 60 process_material = SubResource("ParticleProcessMaterial_l8e6j") draw_pass_1 = SubResource("QuadMesh_aeure") -[node name="Fire1" type="GPUParticles3D" parent="Smoothing/ThirdPerson/Mesh/JetpackFX"] +[node name="Fire1" type="GPUParticles3D" parent="ThirdPerson/Mesh/JetpackFX"] emitting = false amount = 16 lifetime = 0.3 @@ -437,20 +436,15 @@ fixed_fps = 60 process_material = SubResource("ParticleProcessMaterial_q1vdw") draw_pass_1 = SubResource("QuadMesh_uc7ts") -[node name="IFFAttachment" type="Marker3D" parent="Smoothing/ThirdPerson"] -transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.27457, 0) -visible = false - -[node name="IFF" parent="Smoothing/ThirdPerson/IFFAttachment" node_paths=PackedStringArray("player", "match_participant_component", "attach_point") instance=ExtResource("7_8hc80")] -visible = false -player = NodePath("../../../..") -match_participant_component = NodePath("../../../../MatchParticipantComponent") -attach_point = NodePath("..") +[node name="Smoothing" type="Node3D" parent="."] +script = ExtResource("11_k330l") +target = NodePath("..") +flags = 3 [connection signal="energy_changed" from="." to="HUD" method="_on_player_energy_changed"] -[editable path="Smoothing/ThirdPerson/Mesh"] -[editable path="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun"] -[editable path="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh"] -[editable path="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun"] -[editable path="Smoothing/ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher"] +[editable path="ThirdPerson/Mesh"] +[editable path="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun"] +[editable path="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/SpaceGun/Mesh"] +[editable path="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/ChainGun"] +[editable path="ThirdPerson/Mesh/Node/Skeleton3D/HandAttachment/GrenadeLauncher"] diff --git a/interfaces/hud/iffs/IFF.tscn b/interfaces/hud/iffs/IFF.tscn new file mode 100644 index 0000000..20821b3 --- /dev/null +++ b/interfaces/hud/iffs/IFF.tscn @@ -0,0 +1,50 @@ +[gd_scene load_steps=7 format=3 uid="uid://bbeecp3jusppn"] + +[ext_resource type="Script" path="res://interfaces/hud/iffs/iff.gd" id="1_g6kgb"] +[ext_resource type="Shader" uid="uid://n2dcb4l0qun2" path="res://interfaces/progress_bar/resources/visual_shader.res" id="2_8cjkh"] +[ext_resource type="Script" path="res://interfaces/progress_bar/progress_bar_3d.gd" id="3_vss6w"] +[ext_resource type="Texture2D" uid="uid://cpb6vpa0c74rl" path="res://interfaces/waypoint/assets/waypoint.svg" id="4_lrbtk"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_wrx5m"] +render_priority = 0 +shader = ExtResource("2_8cjkh") + +[sub_resource type="QuadMesh" id="QuadMesh_b6wb8"] +material = SubResource("ShaderMaterial_wrx5m") +size = Vector2(0.35, 0.025) +center_offset = Vector3(0, 0.09, 0) + +[node name="IFF" type="Node3D"] +script = ExtResource("1_g6kgb") +border = 0.4 +billboard = 1 +depth_test = true + +[node name="Username" type="Label3D" parent="."] +transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0) +offset = Vector2(0, 64) +billboard = 1 +fixed_size = true +text = "Username" +font_size = 24 + +[node name="HealthBar" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000610828, 0.0127701, -0.000638008) +instance_shader_parameters/background = Color(0, 0, 0, 0.5) +instance_shader_parameters/billboard = 1 +instance_shader_parameters/border = 0.0 +instance_shader_parameters/fill = Color(1, 1, 1, 1) +instance_shader_parameters/progress = 1.0 +instance_shader_parameters/size = Vector2(0.35, 0.025) +mesh = SubResource("QuadMesh_b6wb8") +script = ExtResource("3_vss6w") +border = 0.0 +billboard = 1 +fill = Color(1, 1, 1, 1) + +[node name="Chevron" type="Sprite3D" parent="."] +transform = Transform3D(0.04, 0, 0, 0, 0.04, 0, 0, 0, 0.04, 0, 0, 0) +offset = Vector2(0, 64) +billboard = 1 +fixed_size = true +texture = ExtResource("4_lrbtk") diff --git a/interfaces/hud/iffs/health_foreground.tres b/interfaces/hud/iffs/health_foreground.tres deleted file mode 100644 index 08a98b0..0000000 --- a/interfaces/hud/iffs/health_foreground.tres +++ /dev/null @@ -1,9 +0,0 @@ -[gd_resource type="StyleBoxFlat" format=3 uid="uid://cgv081wfih7la"] - -[resource] -bg_color = Color(1, 0, 0, 0.25) -corner_radius_top_left = 3 -corner_radius_top_right = 3 -corner_radius_bottom_right = 3 -corner_radius_bottom_left = 3 -anti_aliasing = false diff --git a/interfaces/hud/iffs/iff.gd b/interfaces/hud/iffs/iff.gd index 16a66d0..0fb2032 100644 --- a/interfaces/hud/iffs/iff.gd +++ b/interfaces/hud/iffs/iff.gd @@ -12,92 +12,107 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . -extends Control +@tool +class_name IFF extends Node3D -@export var player : Player -@export var match_participant_component : MatchParticipantComponent -@export var attach_point : Marker3D -@export var healthbar_low_health_color : Color = Color(1 ,0 ,0, 0.78) -@export var healthbar_mid_health_color : Color = Color(1, 1, 0, 0.78) -@export var healthbar_high_health_color : Color = Color(0, 1, 0, 0.78) -@export var iff_in_range_radius_ratio : float = 0.05 +signal health_changed(new_value : float) +signal fill_changed(color : Color) +signal background_changed(color : Color) +signal billboard_changed(new_billboard : int) +signal username_changed(new_username : String) +signal border_changed(new_border : float) +signal depth_test_changed(new_depth_test : bool) -@onready var _iff_container : Control = $IFFContainer -@onready var _iff_in_range_container : Control = $IFFContainer/IFFInRangeContainer -@onready var _player_name_label : Control = $IFFContainer/IFFInRangeContainer/PlayerNameLabel -@onready var _health_bar : ProgressBar = $IFFContainer/IFFInRangeContainer/HealthBar -@onready var is_within_los : bool = false -@onready var healthbar_fill_stylebox : StyleBoxFlat = _health_bar.get_theme_stylebox("fill") +# If `true`, the waypoint fades as the camera get closer. +#@export var fade : bool = true -func set_nickname(new_nickname : String) -> void: - _player_name_label.text = new_nickname +## The current value for the pgroess bar. +@export_range(0., 1.) var value : float = 1.: + set(new_value): + value = new_value + health_changed.emit(value) -func _process(_delta : float) -> void: - # retrieve camera for current viewport - var camera : Camera3D = get_viewport().get_camera_3d() +## The border for the progress bar. +@export_range(0., 1.) var border : float = .2: + set(new_border): + border = new_border + border_changed.emit(border) - # if the player is NOT infront of the camera or camera does NOT have LOS to player - if camera.is_position_behind(attach_point.global_position) or !is_within_los: - _iff_container.hide() - else: - _iff_container.show() +## The username to display on top of this indicator. +@export var username : String = "Username": + set(value): + username = value + username_changed.emit(username) - # Show the correct IFF based on whether the player we're looking at belongs is a friend or a foe - # in other words if their team_ids are the same as the "pawn" player - if player.pawn_player != null: - if player.pawn_player.match_participant_component.team_id == player.match_participant_component.team_id: - %FoeChevron.hide() - %FriendChevron.show() - else: - %FoeChevron.show() - %FriendChevron.hide() +## The foreground color to use for this indicator. +@export var fill : Color = Color.WHITE: + set(value): + fill = value + fill_changed.emit(fill) -func _physics_process(_delta : float) -> void: - # https://docs.godotengine.org/en/stable/tutorials/physics/ray-casting.html - var camera : Camera3D = get_viewport().get_camera_3d() - is_within_los = false # always initialise trace_success as false - var space_state : PhysicsDirectSpaceState3D = camera.get_world_3d().direct_space_state - # do a trace check from camera to towards the player - var query : PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(camera.global_position, player.global_position) - # only collide with Layer 1 (objects) and Layer 32 (terrain/structures) - query.collision_mask = 0b10000000_00000000_00000000_00000001 - # exclude the camera owner nodes from intersecting with the trace check - if player.pawn_player: - query.exclude = [player.pawn_player] - # do trace check and store result - var result : Dictionary = space_state.intersect_ray(query) - # if a result was returned and the hit result is the player - if result and result["collider"] == player: - # the player is in camera LOS - is_within_los = true +## The background color to use for this indicator. +@export var background : Color = Color(0, 0, 0, 0.5): + set(color): + background = color + background_changed.emit(color) - var new_iff_position : Vector2 = camera.unproject_position(attach_point.global_position) # get the screen location of the players head - var viewport_size : Vector2 = get_viewport_rect().size +## The billboard mode to use. See [member BaseMaterial3D.BillboardMode] for possible values. +@export_enum("Disabled", "Enabled", "Y-Billboard") var billboard : int = 2: + set(new_billboard): + billboard = new_billboard + billboard_changed.emit(billboard) - # check if the unprojected point lies inside the viewport - if !Rect2(Vector2(0, 0), viewport_size).has_point(new_iff_position): - _iff_container.hide() # hide the IFF and exit function - return +@export var depth_test : bool = false: + set(new_depth_test): + depth_test = new_depth_test + depth_test_changed.emit(new_depth_test) - # if player is NOT in range to have its healthbar and name drawn - if (new_iff_position - viewport_size / 2).length() > iff_in_range_radius_ratio * viewport_size.length(): - _iff_in_range_container.hide() # hide the in range IFF - else: - _iff_in_range_container.show() +@onready var label : Label3D = $Username +@onready var chevron : Sprite3D = $Chevron +@onready var hbar : ProgressBar3D = $HealthBar - new_iff_position.y -= _iff_container.size.y # move the IFF up so the bottom of it is at the players head - new_iff_position.x -= _iff_container.size.x / 2 # move the IFF left so it's centered horizontally above players head - position = new_iff_position # set the position of the IFF +func _on_billboard_changed(new_billboard : int) -> void: + label.billboard = new_billboard as BaseMaterial3D.BillboardMode + hbar.billboard = new_billboard + chevron.billboard = new_billboard as BaseMaterial3D.BillboardMode -func _update_health_bar(health : float) -> void: - _health_bar.value = health - # modify health_box stylebox depending health value - if health < 75 and health > 40: - healthbar_fill_stylebox.bg_color = healthbar_mid_health_color - elif health <= 40: - healthbar_fill_stylebox.bg_color = healthbar_low_health_color - else: - healthbar_fill_stylebox.bg_color = healthbar_high_health_color +func _on_border_changed(new_border : float) -> void: + hbar.border = new_border -func _on_health_changed(new_health : float) -> void: - _update_health_bar(new_health) +func _on_username_changed(new_username : String) -> void: + # The label's text can only be set once the node is ready. + if is_inside_tree(): + label.text = new_username + +func _on_background_changed(color : Color) -> void: + label.outline_modulate = color + hbar.background = color + +func _on_fill_changed(color : Color) -> void: + label.modulate = color + hbar.fill = color + chevron.modulate = color + +func _on_health_changed(new_value : float) -> void: + hbar.value = new_value + +func _on_depth_test_changed(new_depth_test : bool) -> void: + label.no_depth_test = !new_depth_test + #hbar.no_depth_test = !new_depth_test + chevron.no_depth_test = !new_depth_test + +func _enter_tree() -> void: + if not username_changed.is_connected(_on_username_changed): + username_changed.connect(_on_username_changed) + if not health_changed.is_connected(_on_health_changed): + health_changed.connect(_on_health_changed) + if not fill_changed.is_connected(_on_fill_changed): + fill_changed.connect(_on_fill_changed) + if not background_changed.is_connected(_on_background_changed): + background_changed.connect(_on_background_changed) + if not border_changed.is_connected(_on_border_changed): + border_changed.connect(_on_border_changed) + if not billboard_changed.is_connected(_on_billboard_changed): + billboard_changed.connect(_on_billboard_changed) + if not depth_test_changed.is_connected(_on_depth_test_changed): + depth_test_changed.connect(_on_depth_test_changed) diff --git a/interfaces/hud/iffs/iff.tscn b/interfaces/hud/iffs/iff.tscn deleted file mode 100644 index e26d442..0000000 --- a/interfaces/hud/iffs/iff.tscn +++ /dev/null @@ -1,71 +0,0 @@ -[gd_scene load_steps=4 format=3 uid="uid://dsysi2rd3bu76"] - -[ext_resource type="Script" path="res://interfaces/hud/iffs/iff.gd" id="1_g1wra"] -[ext_resource type="StyleBox" uid="uid://cgv081wfih7la" path="res://interfaces/hud/iffs/health_foreground.tres" id="2_e3xla"] -[ext_resource type="StyleBox" uid="uid://dcn1ll2ra4lwn" path="res://interfaces/hud/vitals/background.tres" id="2_jtos4"] - -[node name="IFF" type="Control"] -layout_mode = 3 -anchors_preset = 0 -script = ExtResource("1_g1wra") - -[node name="IFFContainer" type="MarginContainer" parent="."] -layout_mode = 0 -offset_right = 63.0 -offset_bottom = 42.0 -mouse_filter = 2 - -[node name="IFFInRangeContainer" type="Control" parent="IFFContainer"] -layout_mode = 2 -mouse_filter = 2 - -[node name="PlayerNameLabel" type="Label" parent="IFFContainer/IFFInRangeContainer"] -layout_mode = 2 -offset_right = 63.0 -offset_bottom = 17.0 -theme_override_colors/font_color = Color(1, 1, 1, 1) -theme_override_font_sizes/font_size = 12 -text = "Player" -horizontal_alignment = 1 -metadata/_edit_use_anchors_ = true - -[node name="HealthBar" type="ProgressBar" parent="IFFContainer/IFFInRangeContainer"] -layout_mode = 2 -offset_top = 20.0 -offset_right = 63.0 -offset_bottom = 24.0 -mouse_filter = 2 -theme_override_styles/background = ExtResource("2_jtos4") -theme_override_styles/fill = ExtResource("2_e3xla") -value = 60.0 -show_percentage = false - -[node name="FoeChevron" type="Label" parent="IFFContainer"] -unique_name_in_owner = true -visible = false -layout_direction = 2 -layout_mode = 2 -size_flags_vertical = 1 -theme_override_colors/font_color = Color(1, 0, 0, 0.2) -theme_override_colors/font_outline_color = Color(0, 0, 0, 0.2) -theme_override_constants/outline_size = 3 -theme_override_constants/line_spacing = -20 -theme_override_font_sizes/font_size = 14 -text = "▼" -horizontal_alignment = 1 -vertical_alignment = 2 - -[node name="FriendChevron" type="Label" parent="IFFContainer"] -unique_name_in_owner = true -visible = false -layout_direction = 2 -layout_mode = 2 -size_flags_vertical = 1 -theme_override_colors/font_color = Color(0, 1, 0, 0.2) -theme_override_colors/font_outline_color = Color(0, 0, 0, 0.2) -theme_override_constants/outline_size = 3 -theme_override_constants/line_spacing = -20 -theme_override_font_sizes/font_size = 14 -text = "▼" -horizontal_alignment = 1 -vertical_alignment = 2 diff --git a/interfaces/progress_bar/ProgressBar3D.tscn b/interfaces/progress_bar/ProgressBar3D.tscn new file mode 100644 index 0000000..8b98bb8 --- /dev/null +++ b/interfaces/progress_bar/ProgressBar3D.tscn @@ -0,0 +1,23 @@ +[gd_scene load_steps=5 format=3 uid="uid://chy8tm6hvummq"] + +[ext_resource type="Shader" uid="uid://n2dcb4l0qun2" path="res://interfaces/progress_bar/resources/visual_shader.res" id="1_07e5d"] +[ext_resource type="Script" path="res://interfaces/progress_bar/progress_bar_3d.gd" id="1_kpyfi"] + +[sub_resource type="ShaderMaterial" id="ShaderMaterial_4quui"] +render_priority = 0 +shader = ExtResource("1_07e5d") + +[sub_resource type="QuadMesh" id="QuadMesh_fwm7g"] +material = SubResource("ShaderMaterial_4quui") +size = Vector2(1, 0.1) + +[node name="ProgressBar3D" type="MeshInstance3D"] +cast_shadow = 0 +instance_shader_parameters/background = Color(0, 0, 0, 0.5) +instance_shader_parameters/billboard = 2 +instance_shader_parameters/border = 0.2 +instance_shader_parameters/fill = Color(0, 1, 0, 1) +instance_shader_parameters/progress = 1.0 +instance_shader_parameters/size = Vector2(1, 0.1) +mesh = SubResource("QuadMesh_fwm7g") +script = ExtResource("1_kpyfi") diff --git a/interfaces/progress_bar/progress_bar_3d.gd b/interfaces/progress_bar/progress_bar_3d.gd new file mode 100644 index 0000000..2bc1b43 --- /dev/null +++ b/interfaces/progress_bar/progress_bar_3d.gd @@ -0,0 +1,83 @@ +# This file is part of open-fpsz. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +## A progress bar using a single quad mesh and a shader. +@tool +class_name ProgressBar3D extends MeshInstance3D + +## Emitted when value has been changed. +signal value_changed(new_value : float) + +const progress_bar_shader : VisualShader = preload( + "res://interfaces/progress_bar/resources/visual_shader.res") + +## Current value. +@export_range(0., 1.) var value : float = 1.: + set(new_value): + value = new_value + _update_shader_params() + value_changed.emit(value) + +@export_range(0., 1.) var border : float = .2: + set(new_border): + border = new_border + _update_shader_params() + +@export_enum("Disabled", "Enabled", "Y-Billboard") var billboard : int = 2: + set(new_billboard): + billboard = new_billboard + _update_shader_params() + +## Fill color. +@export var fill : Color = Color.GREEN: + set(value): + fill = value + _update_shader_params() + +## Background color. +@export var background : Color = Color(0, 0, 0, 0.5): + set(value): + background = value + _update_shader_params() + +## setup mesh, material and shader when entering the node tree +func _enter_tree() -> void: + # set default mesh + if not mesh: + mesh = QuadMesh.new() + mesh.size = Vector2(1, .1) + + # set default material + if not mesh.material or not mesh.material is ShaderMaterial: + # @NOTE: Per-instance uniforms allow for better shader reuse and are + # therefore faster, so they should be preferred over duplicating the + # ShaderMaterial when possible. + mesh.material = ShaderMaterial.new() + + # set default shader + mesh.material.shader = progress_bar_shader + if not mesh.changed.is_connected(_update_shader_params): + mesh.changed.connect(_update_shader_params) + + # update shader params once + mesh.emit_changed() + +## This method updates shader params +func _update_shader_params() -> void: + set_instance_shader_parameter("background", background) + set_instance_shader_parameter("billboard", billboard) + set_instance_shader_parameter("border", border) + set_instance_shader_parameter("fill", fill) + set_instance_shader_parameter("progress", value) + set_instance_shader_parameter("size", mesh.size) diff --git a/interfaces/progress_bar/resources/visual_shader.res b/interfaces/progress_bar/resources/visual_shader.res new file mode 100644 index 0000000..b1f30fa Binary files /dev/null and b/interfaces/progress_bar/resources/visual_shader.res differ diff --git a/modes/multiplayer/multiplayer.gd b/modes/multiplayer/multiplayer.gd index d64b163..ef386fe 100644 --- a/modes/multiplayer/multiplayer.gd +++ b/modes/multiplayer/multiplayer.gd @@ -106,6 +106,8 @@ func _join_match(nickname : String) -> void: add_player(multiplayer.get_remote_sender_id(), nickname) func _exit_tree() -> void: - if is_multiplayer_authority(): - multiplayer.peer_disconnected.disconnect(remove_player) + # @NOTE: The `is_multiplayer_authority` method in `_exit_tree` push an error + # about the multiplayer instance not being the currently active one. + # see https://github.com/godotengine/godot/issues/77723 + multiplayer.multiplayer_peer.close() multiplayer.multiplayer_peer = OfflineMultiplayerPeer.new() diff --git a/modes/multiplayer/multiplayer.tscn b/modes/multiplayer/multiplayer.tscn index eafe09f..7871900 100644 --- a/modes/multiplayer/multiplayer.tscn +++ b/modes/multiplayer/multiplayer.tscn @@ -15,7 +15,7 @@ FLAG = ExtResource("3_h0rie") [node name="Map" type="Node" parent="."] [node name="MapSpawner" type="MultiplayerSpawner" parent="."] -_spawnable_scenes = PackedStringArray("res://maps/genesis/genesis.tscn", "res://maps/desert/desert.tscn") +_spawnable_scenes = PackedStringArray("res://maps/desert/desert.tscn") spawn_path = NodePath("../Map") spawn_limit = 1