mirror of
https://github.com/Steffo99/nanogolf.git
synced 2024-11-21 15:44:21 +00:00
HUD!
This commit is contained in:
parent
5bf510d4c7
commit
76f304613c
19 changed files with 346 additions and 37 deletions
6
scenes/complete_timer.tscn
Normal file
6
scenes/complete_timer.tscn
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[gd_scene format=3 uid="uid://d3xiiqurxhmfc"]
|
||||||
|
|
||||||
|
[node name="CompleteTimer" type="Timer"]
|
||||||
|
wait_time = 3.0
|
||||||
|
one_shot = true
|
||||||
|
autostart = true
|
|
@ -48,6 +48,7 @@ func _on_multiplayer_peer_connected(peer_id: int) -> void:
|
||||||
player_dir.rpc_possess_playernode.rpc_id(peer_id, playernode.player_name, playernode.get_multiplayer_authority())
|
player_dir.rpc_possess_playernode.rpc_id(peer_id, playernode.player_name, playernode.get_multiplayer_authority())
|
||||||
playernode.rpc_query_name.rpc_id(playernode.get_multiplayer_authority())
|
playernode.rpc_query_name.rpc_id(playernode.get_multiplayer_authority())
|
||||||
playernode.rpc_query_color.rpc_id(playernode.get_multiplayer_authority())
|
playernode.rpc_query_color.rpc_id(playernode.get_multiplayer_authority())
|
||||||
|
playernode.rpc_query_scores.rpc_id(playernode.get_multiplayer_authority())
|
||||||
peer_dir.rpc_create_peernode.rpc(peer_id)
|
peer_dir.rpc_create_peernode.rpc(peer_id)
|
||||||
phase_tracker.rpc_set_phase.rpc_id(peer_id, phase_tracker.phase)
|
phase_tracker.rpc_set_phase.rpc_id(peer_id, phase_tracker.phase)
|
||||||
|
|
||||||
|
@ -85,6 +86,12 @@ func _on_playerdir_playernode_name_changed(old: String, new: String, playernode:
|
||||||
func _on_playerdir_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode) -> void:
|
func _on_playerdir_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode) -> void:
|
||||||
Log.peer(self, "Playernode `%s` changed color: %s (was %s)" % [playernode.player_name, new, old])
|
Log.peer(self, "Playernode `%s` changed color: %s (was %s)" % [playernode.player_name, new, old])
|
||||||
|
|
||||||
|
func _on_playerdir_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
|
||||||
|
Log.peer(self, "Playernode `%s` reported score: %d" % [playernode.player_name, strokes])
|
||||||
|
|
||||||
|
func _on_playerdir_playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode) -> void:
|
||||||
|
Log.peer(self, "Playernode `%s` changed scores: %s (was %s)" % [playernode.player_name, new, old])
|
||||||
|
|
||||||
func _on_playerdir_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
|
func _on_playerdir_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
|
||||||
Log.peer(self, "Playernode `%s` possessed: %d (was %d)" % [playernode.player_name, new, old])
|
Log.peer(self, "Playernode `%s` possessed: %d (was %d)" % [playernode.player_name, new, old])
|
||||||
if playernode.is_multiplayer_authority() and not multiplayer.is_server():
|
if playernode.is_multiplayer_authority() and not multiplayer.is_server():
|
||||||
|
@ -95,4 +102,8 @@ func _on_playerdir_playernode_possessed(old: int, new: int, playernode: PlayerNo
|
||||||
func _on_main_start_confirmed() -> void:
|
func _on_main_start_confirmed() -> void:
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.PLAYING)
|
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.PLAYING)
|
||||||
level_manager.rpc_next_level.rpc()
|
level_manager.rpc_next_level.rpc()
|
||||||
|
|
||||||
|
func _on_level_manager_playlist_complete(_playlist: LevelPlaylist) -> void:
|
||||||
|
if multiplayer.is_server():
|
||||||
|
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.ENDED)
|
||||||
|
|
|
@ -39,3 +39,6 @@ levels = Array[PackedScene]([ExtResource("8_h8dsk"), ExtResource("9_2kliu")])
|
||||||
[connection signal="playernode_color_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_color_changed"]
|
[connection signal="playernode_color_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_color_changed"]
|
||||||
[connection signal="playernode_name_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_name_changed"]
|
[connection signal="playernode_name_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_name_changed"]
|
||||||
[connection signal="playernode_possessed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_possessed"]
|
[connection signal="playernode_possessed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_possessed"]
|
||||||
|
[connection signal="playernode_score_reported" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_score_reported"]
|
||||||
|
[connection signal="playernode_scores_changed" from="PlayerNodeDirectory" to="." method="_on_playerdir_playernode_scores_changed"]
|
||||||
|
[connection signal="playlist_complete" from="LevelManager" to="." method="_on_level_manager_playlist_complete"]
|
||||||
|
|
50
scenes/game_hud.gd
Normal file
50
scenes/game_hud.gd
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
extends Control
|
||||||
|
class_name GameHUD
|
||||||
|
|
||||||
|
|
||||||
|
@export var strokes_label: Label
|
||||||
|
|
||||||
|
@export var scores_panel: PanelContainer
|
||||||
|
|
||||||
|
@export var scores_container: Control
|
||||||
|
|
||||||
|
|
||||||
|
const score_scene = preload("res://scenes/player_score_label.tscn")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_level_completed(_level: GolfLevel) -> void:
|
||||||
|
strokes_label.text = "0"
|
||||||
|
for child in scores_container.get_children():
|
||||||
|
child.queue_free()
|
||||||
|
scores_panel.hide()
|
||||||
|
|
||||||
|
func _on_playernode_name_changed(old: String, new: String, playernode: PlayerNode) -> void:
|
||||||
|
var instance = get_node_or_null("PlayerScoreLabel__%s" % old)
|
||||||
|
if instance != null:
|
||||||
|
instance.from_score(playernode)
|
||||||
|
instance.name = "PlayerScoreLabel__%s" % new
|
||||||
|
|
||||||
|
func _on_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode) -> void:
|
||||||
|
var instance = get_node_or_null("PlayerScoreLabel__%s" % playernode.player_name)
|
||||||
|
if instance != null:
|
||||||
|
instance.from_score(playernode)
|
||||||
|
|
||||||
|
func _on_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
|
||||||
|
var instance = get_node_or_null("PlayerScoreLabel__%s" % playernode.player_name)
|
||||||
|
if instance != null:
|
||||||
|
instance.from_score(playernode)
|
||||||
|
|
||||||
|
func _on_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
|
||||||
|
var score_instance = score_scene.instantiate()
|
||||||
|
score_instance.from_score(strokes, playernode)
|
||||||
|
score_instance.name = "PlayerScoreLabel__%s" % playernode.player_name
|
||||||
|
scores_container.add_child(score_instance)
|
||||||
|
scores_panel.show()
|
||||||
|
|
||||||
|
func _on_playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode) -> void:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func _on_strokes_changed(strokes: int) -> void:
|
||||||
|
strokes_label.text = "%s" % strokes
|
82
scenes/game_hud.tscn
Normal file
82
scenes/game_hud.tscn
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://cfma7kdxh8jn2"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scenes/game_hud.gd" id="1_x04no"]
|
||||||
|
|
||||||
|
[node name="GameHUD" type="Control" node_paths=PackedStringArray("strokes_label", "scores_panel", "scores_container")]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
script = ExtResource("1_x04no")
|
||||||
|
strokes_label = NodePath("GridContainer/TopLeft/StrokesPanel/Margin/Label")
|
||||||
|
scores_panel = NodePath("GridContainer/TopRight/ScoresPanel")
|
||||||
|
scores_container = NodePath("GridContainer/TopRight/ScoresPanel/Margin/Scores")
|
||||||
|
|
||||||
|
[node name="GridContainer" type="GridContainer" parent="."]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 15
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 2
|
||||||
|
columns = 2
|
||||||
|
|
||||||
|
[node name="TopLeft" type="Control" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="StrokesPanel" type="PanelContainer" parent="GridContainer/TopLeft"]
|
||||||
|
layout_mode = 2
|
||||||
|
offset_right = 18.0
|
||||||
|
offset_bottom = 31.0
|
||||||
|
size_flags_horizontal = 0
|
||||||
|
|
||||||
|
[node name="Margin" type="MarginContainer" parent="GridContainer/TopLeft/StrokesPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 4
|
||||||
|
theme_override_constants/margin_top = 4
|
||||||
|
theme_override_constants/margin_right = 4
|
||||||
|
theme_override_constants/margin_bottom = 4
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="GridContainer/TopLeft/StrokesPanel/Margin"]
|
||||||
|
layout_mode = 2
|
||||||
|
text = "0"
|
||||||
|
|
||||||
|
[node name="TopRight" type="Control" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="ScoresPanel" type="PanelContainer" parent="GridContainer/TopRight"]
|
||||||
|
visible = false
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 1
|
||||||
|
anchor_left = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
offset_left = -60.0
|
||||||
|
offset_bottom = 25.0
|
||||||
|
grow_horizontal = 0
|
||||||
|
size_flags_horizontal = 8
|
||||||
|
|
||||||
|
[node name="Margin" type="MarginContainer" parent="GridContainer/TopRight/ScoresPanel"]
|
||||||
|
layout_mode = 2
|
||||||
|
theme_override_constants/margin_left = 4
|
||||||
|
theme_override_constants/margin_top = 4
|
||||||
|
theme_override_constants/margin_right = 4
|
||||||
|
theme_override_constants/margin_bottom = 4
|
||||||
|
|
||||||
|
[node name="Scores" type="VBoxContainer" parent="GridContainer/TopRight/ScoresPanel/Margin"]
|
||||||
|
layout_mode = 2
|
||||||
|
|
||||||
|
[node name="BottomLeft" type="Control" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
||||||
|
|
||||||
|
[node name="BottomRight" type="Control" parent="GridContainer"]
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
size_flags_vertical = 3
|
|
@ -136,7 +136,6 @@ func rpc_sync_enter_hole():
|
||||||
visible = false
|
visible = false
|
||||||
hole_sound.play()
|
hole_sound.play()
|
||||||
entered_hole.emit(strokes)
|
entered_hole.emit(strokes)
|
||||||
Log.peer(self, "Entered hole in: %d" % strokes)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -152,7 +151,7 @@ func _ready() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta) -> void:
|
func _physics_process(delta) -> void:
|
||||||
if is_multiplayer_authority():
|
if not multiplayer.is_server() and is_multiplayer_authority():
|
||||||
if not in_hole:
|
if not in_hole:
|
||||||
do_movement(delta)
|
do_movement(delta)
|
||||||
rpc_sync_global_position.rpc(global_position)
|
rpc_sync_global_position.rpc(global_position)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
[gd_scene load_steps=2 format=3 uid="uid://cywer226gp6vt"]
|
|
||||||
|
|
||||||
[sub_resource type="GDScript" id="GDScript_ek5xt"]
|
|
||||||
script/source = "extends Node
|
|
||||||
class_name GolfBallDirectory
|
|
||||||
|
|
||||||
"
|
|
||||||
|
|
||||||
[node name="GolfBallDirectory" type="Node"]
|
|
||||||
script = SubResource("GDScript_ek5xt")
|
|
|
@ -6,6 +6,7 @@ class_name GolfLevel
|
||||||
signal level_completed
|
signal level_completed
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@export_category("Level Data")
|
@export_category("Level Data")
|
||||||
|
|
||||||
## Whether the [field camera] follows the active player or not.
|
## Whether the [field camera] follows the active player or not.
|
||||||
|
@ -27,6 +28,9 @@ signal level_completed
|
||||||
## The [TileMap] of this level.
|
## The [TileMap] of this level.
|
||||||
@export var map: TileMap = null
|
@export var map: TileMap = null
|
||||||
|
|
||||||
|
## If active, the [Timer] between emissions of [signal everyone_entered_hole] and [signal level_completed].
|
||||||
|
var complete_timer: Timer = null
|
||||||
|
|
||||||
|
|
||||||
## If on server, this variable indicates the [GolfLevel] to replicate.
|
## If on server, this variable indicates the [GolfLevel] to replicate.
|
||||||
##
|
##
|
||||||
|
@ -54,6 +58,9 @@ const hole_scene: PackedScene = preload("res://scenes/golf_hole.tscn")
|
||||||
## The [PackedScene] to initialize as [Camera2D].
|
## The [PackedScene] to initialize as [Camera2D].
|
||||||
const camera_scene: PackedScene = preload("res://scenes/follow_camera.tscn")
|
const camera_scene: PackedScene = preload("res://scenes/follow_camera.tscn")
|
||||||
|
|
||||||
|
## The [PackedScene] to initialize as [Timer] between emissions of [signal everyone_entered_hole] and [signal level_completed].
|
||||||
|
const complete_timer_scene: PackedScene = preload("res://scenes/complete_timer.tscn")
|
||||||
|
|
||||||
|
|
||||||
## Replicate the [field target] from the server to the clients via RPC.
|
## Replicate the [field target] from the server to the clients via RPC.
|
||||||
func build() -> void:
|
func build() -> void:
|
||||||
|
@ -193,7 +200,14 @@ func _on_playernode_created(node: Node) -> void:
|
||||||
rpc_build_ball.rpc(playernode.player_name)
|
rpc_build_ball.rpc(playernode.player_name)
|
||||||
|
|
||||||
|
|
||||||
func _on_everyone_entered_hole() -> void:
|
func _on_everyone_entered_hole():
|
||||||
|
complete_timer = complete_timer_scene.instantiate()
|
||||||
|
complete_timer.timeout.connect(_on_complete_timer_timeout)
|
||||||
|
add_child(complete_timer)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_complete_timer_timeout():
|
||||||
|
complete_timer.queue_free()
|
||||||
level_completed.emit()
|
level_completed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,5 @@
|
||||||
|
|
||||||
[node name="GolfLevel" type="Node2D"]
|
[node name="GolfLevel" type="Node2D"]
|
||||||
script = ExtResource("1_evup0")
|
script = ExtResource("1_evup0")
|
||||||
camera_follows_player = null
|
|
||||||
|
|
||||||
[connection signal="tree_exiting" from="." to="." method="_on_tree_exiting"]
|
[connection signal="tree_exiting" from="." to="." method="_on_tree_exiting"]
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
[node name="GolfLevel" type="Node2D" node_paths=PackedStringArray("camera", "tee", "hole", "map")]
|
[node name="GolfLevel" type="Node2D" node_paths=PackedStringArray("camera", "tee", "hole", "map")]
|
||||||
script = ExtResource("1_qljh7")
|
script = ExtResource("1_qljh7")
|
||||||
camera_follows_player = null
|
|
||||||
camera = NodePath("FollowCamera")
|
camera = NodePath("FollowCamera")
|
||||||
tee = NodePath("GolfTee")
|
tee = NodePath("GolfTee")
|
||||||
hole = NodePath("GolfHole")
|
hole = NodePath("GolfHole")
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
extends Node2D
|
extends Node2D
|
||||||
class_name GolfTee
|
class_name GolfTee
|
||||||
|
|
||||||
## Emitted when all connected [GolfBall]s have their [field GolfBall.in_hole] parameter set to true.
|
|
||||||
|
## Emitted when all connected [GolfBall]s have entered the hole.
|
||||||
signal everyone_entered_hole
|
signal everyone_entered_hole
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +20,7 @@ func spawn(playernode: PlayerNode) -> GolfBall:
|
||||||
obj.player_name = playernode.player_name
|
obj.player_name = playernode.player_name
|
||||||
obj.player_color = playernode.player_color
|
obj.player_color = playernode.player_color
|
||||||
obj.set_multiplayer_authority(playernode.get_multiplayer_authority())
|
obj.set_multiplayer_authority(playernode.get_multiplayer_authority())
|
||||||
obj.putt_controller.can_putt = is_multiplayer_authority()
|
obj.putt_controller.can_putt = not multiplayer.is_server() and playernode.is_multiplayer_authority()
|
||||||
# Create callables to be able to cleanup signals on destruction
|
# Create callables to be able to cleanup signals on destruction
|
||||||
var on_name_changed: Callable = _on_name_changed.bind(obj)
|
var on_name_changed: Callable = _on_name_changed.bind(obj)
|
||||||
var on_color_changed: Callable = _on_color_changed.bind(obj)
|
var on_color_changed: Callable = _on_color_changed.bind(obj)
|
||||||
|
@ -30,12 +31,13 @@ func spawn(playernode: PlayerNode) -> GolfBall:
|
||||||
playernode.color_changed.connect(on_color_changed)
|
playernode.color_changed.connect(on_color_changed)
|
||||||
playernode.possessed.connect(on_possessed)
|
playernode.possessed.connect(on_possessed)
|
||||||
obj.tree_exiting.connect(on_cleanup)
|
obj.tree_exiting.connect(on_cleanup)
|
||||||
obj.entered_hole.connect(_on_entered_hole)
|
obj.entered_hole.connect(_on_entered_hole.bind(playernode))
|
||||||
# Add the golf ball as a child of the tee
|
# Add the golf ball as a child of the tee
|
||||||
add_child(obj)
|
add_child(obj)
|
||||||
# Return the created [GolfBall]
|
# Return the created [GolfBall]
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
||||||
func is_everyone_in_hole() -> bool:
|
func is_everyone_in_hole() -> bool:
|
||||||
for child in get_children():
|
for child in get_children():
|
||||||
var ball: GolfBall = child as GolfBall
|
var ball: GolfBall = child as GolfBall
|
||||||
|
@ -65,6 +67,8 @@ func _on_cleanup(playernode: PlayerNode, on_name_changed: Callable, on_color_cha
|
||||||
playernode.color_changed.disconnect(on_color_changed)
|
playernode.color_changed.disconnect(on_color_changed)
|
||||||
playernode.possessed.disconnect(on_possessed)
|
playernode.possessed.disconnect(on_possessed)
|
||||||
|
|
||||||
func _on_entered_hole(_strokes: int) -> void:
|
func _on_entered_hole(strokes: int, playernode: PlayerNode) -> void:
|
||||||
|
if playernode.is_multiplayer_authority():
|
||||||
|
playernode.report_score(strokes)
|
||||||
if is_everyone_in_hole():
|
if is_everyone_in_hole():
|
||||||
everyone_entered_hole.emit()
|
everyone_entered_hole.emit()
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
extends Node
|
extends Node
|
||||||
class_name LevelManager
|
class_name LevelManager
|
||||||
|
|
||||||
## The blank [GolfLevel] to initialize on clients.
|
|
||||||
const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
|
|
||||||
|
@export_category("References")
|
||||||
|
|
||||||
## The [LevelPlaylist] to use to load [GolfLevel]s from.
|
## The [LevelPlaylist] to use to load [GolfLevel]s from.
|
||||||
@export var playlist: LevelPlaylist = null
|
@export var playlist: LevelPlaylist = null
|
||||||
|
@ -11,6 +12,25 @@ const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
|
||||||
@export var player_dir: PlayerNodeDirectory = null
|
@export var player_dir: PlayerNodeDirectory = null
|
||||||
|
|
||||||
|
|
||||||
|
## Emitted when the current level is about to be destroyed.
|
||||||
|
signal level_destroying(level: GolfLevel)
|
||||||
|
|
||||||
|
## Emitted when the next level has been determined by calling [LevelPlaylist.advance].
|
||||||
|
signal level_determined(scene: PackedScene)
|
||||||
|
|
||||||
|
## Emitted when the new level has been added to the tree, but not built.
|
||||||
|
signal level_created(level: GolfLevel)
|
||||||
|
|
||||||
|
## Emitted when a level has been completed.
|
||||||
|
signal level_completed(level: GolfLevel)
|
||||||
|
|
||||||
|
## Emitted when all levels in the [field playlist] have been exausted.
|
||||||
|
signal playlist_complete(playlist: LevelPlaylist)
|
||||||
|
|
||||||
|
|
||||||
|
## The blank [GolfLevel] to initialize on clients.
|
||||||
|
const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
|
||||||
|
|
||||||
## The currently instantiated [GolfLevel].
|
## The currently instantiated [GolfLevel].
|
||||||
var level: GolfLevel = null
|
var level: GolfLevel = null
|
||||||
|
|
||||||
|
@ -18,25 +38,47 @@ var level: GolfLevel = null
|
||||||
## Create the empty [GolfLevel] object everywhere.
|
## Create the empty [GolfLevel] object everywhere.
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func rpc_next_level():
|
func rpc_next_level():
|
||||||
|
Log.peer(self, "Advancinng to the next level!")
|
||||||
# Destroy the current level
|
# Destroy the current level
|
||||||
if level != null:
|
if level != null:
|
||||||
|
Log.peer(self, "Destroying the current level: %s" % level)
|
||||||
|
level_destroying.emit(level)
|
||||||
level.queue_free()
|
level.queue_free()
|
||||||
level = null
|
level = null
|
||||||
|
# Determine the next level
|
||||||
|
Log.peer(self, "Determining the next level...")
|
||||||
|
var next = playlist.advance()
|
||||||
|
Log.peer(self, "Determined the next level: %s" % next)
|
||||||
|
level_determined.emit(next)
|
||||||
|
## Make sure the playlist hasn't been exausted
|
||||||
|
if next == null:
|
||||||
|
Log.peer(self, "Playlist is complete, not doing anything.")
|
||||||
|
playlist_complete.emit(playlist)
|
||||||
|
return
|
||||||
# Create the new level
|
# Create the new level
|
||||||
|
Log.peer(self, "Instantiating empty level template...")
|
||||||
level = base_scene.instantiate()
|
level = base_scene.instantiate()
|
||||||
|
Log.peer(self, "Instantiated empty level template: %s" % level)
|
||||||
|
# Configure the new level
|
||||||
|
Log.peer(self, "Configuring level variables...")
|
||||||
level.player_dir = player_dir
|
level.player_dir = player_dir
|
||||||
level.level_completed.connect(_on_level_completed)
|
level.level_completed.connect(_on_level_completed)
|
||||||
# Determine the next level
|
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
var target = playlist.advance().instantiate()
|
Log.peer(self, "Instantiating the target level scene...")
|
||||||
level.target = target
|
level.target = next.instantiate()
|
||||||
|
Log.peer(self, "Instantiated the target level scene: %s" % level.target)
|
||||||
# Add the level to the tree
|
# Add the level to the tree
|
||||||
|
Log.peer(self, "Adding level to the tree...")
|
||||||
add_child(level, true)
|
add_child(level, true)
|
||||||
|
level_created.emit(level)
|
||||||
# Start the replication
|
# Start the replication
|
||||||
if multiplayer.is_server():
|
if multiplayer.is_server():
|
||||||
|
Log.peer(self, "Building level...")
|
||||||
level.build()
|
level.build()
|
||||||
|
|
||||||
|
|
||||||
func _on_level_completed() -> void:
|
func _on_level_completed() -> void:
|
||||||
if multiplayer.is_server():
|
Log.peer(self, "Level completed!")
|
||||||
|
level_completed.emit(level)
|
||||||
|
if is_multiplayer_authority():
|
||||||
rpc_next_level.rpc()
|
rpc_next_level.rpc()
|
||||||
|
|
|
@ -6,6 +6,10 @@ class_name LevelPlaylist
|
||||||
@export var levels: Array[PackedScene] = []
|
@export var levels: Array[PackedScene] = []
|
||||||
|
|
||||||
|
|
||||||
|
## Emitted when the playlist has advanced to a new level, but before it is returned by [method advanced].
|
||||||
|
signal advanced(level: PackedScene)
|
||||||
|
|
||||||
|
|
||||||
## The index of the current level in [field levels].
|
## The index of the current level in [field levels].
|
||||||
var idx: int = -1
|
var idx: int = -1
|
||||||
|
|
||||||
|
@ -17,4 +21,6 @@ func advance() -> PackedScene:
|
||||||
idx += 1
|
idx += 1
|
||||||
if idx >= len(levels):
|
if idx >= len(levels):
|
||||||
return null
|
return null
|
||||||
return levels[idx]
|
var level = levels[idx]
|
||||||
|
advanced.emit(level)
|
||||||
|
return level
|
||||||
|
|
|
@ -3,7 +3,8 @@ class_name Main
|
||||||
|
|
||||||
|
|
||||||
@onready var scene_tree: SceneTree = get_tree()
|
@onready var scene_tree: SceneTree = get_tree()
|
||||||
@onready var interface_instance: MarginContainer = $"Interface"
|
|
||||||
|
@export var interface_instance: Interface
|
||||||
|
|
||||||
const main_menu_scene: PackedScene = preload("res://scenes/main_menu.tscn")
|
const main_menu_scene: PackedScene = preload("res://scenes/main_menu.tscn")
|
||||||
var main_menu_instance: MainMenu = null
|
var main_menu_instance: MainMenu = null
|
||||||
|
@ -15,6 +16,9 @@ var client_game_instance: Game = null
|
||||||
const lobby_menu_scene: PackedScene = preload("res://scenes/lobby_menu.tscn")
|
const lobby_menu_scene: PackedScene = preload("res://scenes/lobby_menu.tscn")
|
||||||
var lobby_menu_instance: LobbyMenu = null
|
var lobby_menu_instance: LobbyMenu = null
|
||||||
|
|
||||||
|
const game_hud_scene: PackedScene = preload("res://scenes/game_hud.tscn")
|
||||||
|
var game_hud_instance: GameHUD = null
|
||||||
|
|
||||||
func init_main_menu() -> void:
|
func init_main_menu() -> void:
|
||||||
main_menu_instance = main_menu_scene.instantiate()
|
main_menu_instance = main_menu_scene.instantiate()
|
||||||
main_menu_instance.hosting_confirmed.connect(_on_hosting_confirmed)
|
main_menu_instance.hosting_confirmed.connect(_on_hosting_confirmed)
|
||||||
|
@ -23,6 +27,7 @@ func init_main_menu() -> void:
|
||||||
|
|
||||||
func deinit_main_menu() -> void:
|
func deinit_main_menu() -> void:
|
||||||
main_menu_instance.queue_free()
|
main_menu_instance.queue_free()
|
||||||
|
main_menu_instance = null
|
||||||
|
|
||||||
func init_server_game(server_port: int) -> void:
|
func init_server_game(server_port: int) -> void:
|
||||||
server_game_instance = game_scene.instantiate()
|
server_game_instance = game_scene.instantiate()
|
||||||
|
@ -45,6 +50,7 @@ func deinit_server_game() -> void:
|
||||||
server_game_instance.multiplayer.multiplayer_peer = null
|
server_game_instance.multiplayer.multiplayer_peer = null
|
||||||
scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Server")
|
scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Server")
|
||||||
server_game_instance.queue_free()
|
server_game_instance.queue_free()
|
||||||
|
server_game_instance = null
|
||||||
|
|
||||||
func init_client_game(player_name: String, player_color: Color, server_address: String, server_port: int) -> void:
|
func init_client_game(player_name: String, player_color: Color, server_address: String, server_port: int) -> void:
|
||||||
client_game_instance = game_scene.instantiate()
|
client_game_instance = game_scene.instantiate()
|
||||||
|
@ -69,6 +75,7 @@ func deinit_client_game() -> void:
|
||||||
client_game_instance.multiplayer.multiplayer_peer = null
|
client_game_instance.multiplayer.multiplayer_peer = null
|
||||||
scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Client")
|
scene_tree.set_multiplayer(multiplayer, ^"/root/Main/Client")
|
||||||
client_game_instance.queue_free()
|
client_game_instance.queue_free()
|
||||||
|
client_game_instance = null
|
||||||
|
|
||||||
func init_lobby_menu() -> void:
|
func init_lobby_menu() -> void:
|
||||||
lobby_menu_instance = lobby_menu_scene.instantiate()
|
lobby_menu_instance = lobby_menu_scene.instantiate()
|
||||||
|
@ -98,6 +105,27 @@ func deinit_lobby_menu() -> void:
|
||||||
client_game_instance.player_dir.playernode_possessed.disconnect(lobby_menu_instance.players_list._on_playernode_possessed)
|
client_game_instance.player_dir.playernode_possessed.disconnect(lobby_menu_instance.players_list._on_playernode_possessed)
|
||||||
client_game_instance.phase_tracker.phase_changed.disconnect(_on_phase_changed)
|
client_game_instance.phase_tracker.phase_changed.disconnect(_on_phase_changed)
|
||||||
lobby_menu_instance.queue_free()
|
lobby_menu_instance.queue_free()
|
||||||
|
lobby_menu_instance = null
|
||||||
|
|
||||||
|
func init_game_hud() -> void:
|
||||||
|
game_hud_instance = game_hud_scene.instantiate()
|
||||||
|
client_game_instance.level_manager.level_completed.connect(game_hud_instance._on_level_completed)
|
||||||
|
client_game_instance.player_dir.playernode_name_changed.connect(game_hud_instance._on_playernode_name_changed)
|
||||||
|
client_game_instance.player_dir.playernode_color_changed.connect(game_hud_instance._on_playernode_color_changed)
|
||||||
|
client_game_instance.player_dir.playernode_possessed.connect(game_hud_instance._on_playernode_possessed)
|
||||||
|
client_game_instance.player_dir.playernode_score_reported.connect(game_hud_instance._on_playernode_score_reported)
|
||||||
|
client_game_instance.player_dir.playernode_scores_changed.connect(game_hud_instance._on_playernode_scores_changed)
|
||||||
|
interface_instance.add_child(game_hud_instance)
|
||||||
|
|
||||||
|
func deinit_game_hud() -> void:
|
||||||
|
client_game_instance.level_manager.level_completed.disconnect(game_hud_instance._on_level_completed)
|
||||||
|
client_game_instance.player_dir.playernode_name_changed.disconnect(game_hud_instance._on_playernode_name_changed)
|
||||||
|
client_game_instance.player_dir.playernode_color_changed.disconnect(game_hud_instance._on_playernode_color_changed)
|
||||||
|
client_game_instance.player_dir.playernode_possessed.disconnect(game_hud_instance._on_playernode_possessed)
|
||||||
|
client_game_instance.player_dir.playernode_score_reported.disconnect(game_hud_instance._on_playernode_score_reported)
|
||||||
|
client_game_instance.player_dir.playernode_scores_changed.disconnect(game_hud_instance._on_playernode_scores_changed)
|
||||||
|
game_hud_instance.queue_free()
|
||||||
|
game_hud_instance = null
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
init_main_menu()
|
init_main_menu()
|
||||||
|
@ -128,7 +156,7 @@ func _on_phase_changed(old: PhaseTracker.Phase, new: PhaseTracker.Phase) -> void
|
||||||
PhaseTracker.Phase.LOBBY:
|
PhaseTracker.Phase.LOBBY:
|
||||||
deinit_lobby_menu()
|
deinit_lobby_menu()
|
||||||
PhaseTracker.Phase.PLAYING:
|
PhaseTracker.Phase.PLAYING:
|
||||||
pass # TODO
|
deinit_game_hud()
|
||||||
PhaseTracker.Phase.ENDED:
|
PhaseTracker.Phase.ENDED:
|
||||||
pass # TODO
|
pass # TODO
|
||||||
# Then, initialize the new one
|
# Then, initialize the new one
|
||||||
|
@ -136,6 +164,6 @@ func _on_phase_changed(old: PhaseTracker.Phase, new: PhaseTracker.Phase) -> void
|
||||||
PhaseTracker.Phase.LOBBY:
|
PhaseTracker.Phase.LOBBY:
|
||||||
init_lobby_menu()
|
init_lobby_menu()
|
||||||
PhaseTracker.Phase.PLAYING:
|
PhaseTracker.Phase.PLAYING:
|
||||||
pass # TODO
|
init_game_hud()
|
||||||
PhaseTracker.Phase.ENDED:
|
PhaseTracker.Phase.ENDED:
|
||||||
pass # TODO
|
pass # TODO
|
||||||
|
|
|
@ -4,8 +4,11 @@
|
||||||
[ext_resource type="PackedScene" uid="uid://dtwi2nyjbvr82" path="res://scenes/interface.tscn" id="1_bd856"]
|
[ext_resource type="PackedScene" uid="uid://dtwi2nyjbvr82" path="res://scenes/interface.tscn" id="1_bd856"]
|
||||||
[ext_resource type="Theme" uid="uid://mau3moiintkp" path="res://themes/nanogolf_theme.tres" id="2_oe7am"]
|
[ext_resource type="Theme" uid="uid://mau3moiintkp" path="res://themes/nanogolf_theme.tres" id="2_oe7am"]
|
||||||
|
|
||||||
[node name="Main" type="Node"]
|
[node name="Main" type="Node" node_paths=PackedStringArray("interface_instance")]
|
||||||
script = ExtResource("1_a2cl7")
|
script = ExtResource("1_a2cl7")
|
||||||
|
interface_instance = NodePath("CanvasLayer/Interface")
|
||||||
|
|
||||||
[node name="Interface" parent="." instance=ExtResource("1_bd856")]
|
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
||||||
|
|
||||||
|
[node name="Interface" parent="CanvasLayer" instance=ExtResource("1_bd856")]
|
||||||
theme = ExtResource("2_oe7am")
|
theme = ExtResource("2_oe7am")
|
||||||
|
|
8
scenes/player_score_label.gd
Normal file
8
scenes/player_score_label.gd
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
extends Label
|
||||||
|
class_name PlayerScoreLabel
|
||||||
|
|
||||||
|
|
||||||
|
func from_score(strokes: int, playernode: PlayerNode) -> void:
|
||||||
|
text = "%s - %d" % [playernode.player_name, strokes]
|
||||||
|
modulate = playernode.player_color
|
||||||
|
modulate.a = 0.3 if playernode.get_multiplayer_authority() == 1 else 1.0
|
10
scenes/player_score_label.tscn
Normal file
10
scenes/player_score_label.tscn
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[gd_scene load_steps=2 format=3 uid="uid://duu2uo362yfnb"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://scenes/player_score_label.gd" id="1_b8kiv"]
|
||||||
|
|
||||||
|
[node name="PlayerScoreLabel" type="Label"]
|
||||||
|
size_flags_horizontal = 8
|
||||||
|
theme_override_font_sizes/font_size = 12
|
||||||
|
text = "Steffo - 0"
|
||||||
|
horizontal_alignment = 2
|
||||||
|
script = ExtResource("1_b8kiv")
|
|
@ -13,6 +13,9 @@ var player_name: String
|
||||||
## The color of the player represented by this node.
|
## The color of the player represented by this node.
|
||||||
var player_color: Color
|
var player_color: Color
|
||||||
|
|
||||||
|
## The scores of the player in all holes.
|
||||||
|
var hole_scores: Array = []
|
||||||
|
|
||||||
## Change the [field player_name] everywhere.
|
## Change the [field player_name] everywhere.
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func rpc_set_name(value: String):
|
func rpc_set_name(value: String):
|
||||||
|
@ -39,7 +42,6 @@ func possess(value: int) -> void:
|
||||||
set_multiplayer_authority(value)
|
set_multiplayer_authority(value)
|
||||||
possessed.emit(old_value, value)
|
possessed.emit(old_value, value)
|
||||||
|
|
||||||
|
|
||||||
## Prompt the multiplayer authority for this node to call [method rpc_set_name] again with the current value.
|
## Prompt the multiplayer authority for this node to call [method rpc_set_name] again with the current value.
|
||||||
##
|
##
|
||||||
## Used to repeat [field player_name] to new peers.
|
## Used to repeat [field player_name] to new peers.
|
||||||
|
@ -57,6 +59,39 @@ func rpc_query_color():
|
||||||
rpc_set_color.rpc(player_color)
|
rpc_set_color.rpc(player_color)
|
||||||
|
|
||||||
|
|
||||||
|
## Add a new score entry to the [field hole_scores].
|
||||||
|
func report_score(strokes: int) -> void:
|
||||||
|
assert(is_multiplayer_authority())
|
||||||
|
rpc_report_score.rpc(strokes)
|
||||||
|
var tscores = hole_scores.duplicate(true)
|
||||||
|
tscores.push_back(strokes)
|
||||||
|
rpc_set_scores.rpc(tscores)
|
||||||
|
|
||||||
|
## Emit [signal score_reported] everywhere.
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func rpc_report_score(strokes: int):
|
||||||
|
score_reported.emit(strokes)
|
||||||
|
|
||||||
|
|
||||||
|
## Change the [field hole_scores] everywhere.
|
||||||
|
@rpc("authority", "call_local", "reliable")
|
||||||
|
func rpc_set_scores(value: Array):
|
||||||
|
var old_value: Array = hole_scores
|
||||||
|
if old_value != value: # How does this behave?
|
||||||
|
hole_scores = value
|
||||||
|
scores_changed.emit(old_value, value)
|
||||||
|
|
||||||
|
|
||||||
|
## Prompt the multiplayer authority for this node to call [method rpc_set_scores] again with the current value.
|
||||||
|
##
|
||||||
|
## Used to repeat [field hole_scores] to new peers.
|
||||||
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
|
func rpc_query_scores():
|
||||||
|
if is_multiplayer_authority():
|
||||||
|
rpc_set_scores.rpc(hole_scores)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Emitted when the name changes on the local scene because of [method rpc_set_name].
|
## Emitted when the name changes on the local scene because of [method rpc_set_name].
|
||||||
signal name_changed(old: String, new: String)
|
signal name_changed(old: String, new: String)
|
||||||
|
|
||||||
|
@ -65,3 +100,9 @@ signal color_changed(old: Color, new: Color)
|
||||||
|
|
||||||
## Emitted when the multiplayer authority of this [Node] is changed via [method possess].
|
## Emitted when the multiplayer authority of this [Node] is changed via [method possess].
|
||||||
signal possessed(old: int, new: int)
|
signal possessed(old: int, new: int)
|
||||||
|
|
||||||
|
## Emitted when a new hole score has been reported.
|
||||||
|
signal score_reported(strokes: int)
|
||||||
|
|
||||||
|
## Emitted when the hole scores have changed because of [method rpc_set_scores].
|
||||||
|
signal scores_changed(old: Array, new: Array)
|
||||||
|
|
|
@ -26,6 +26,8 @@ func rpc_possess_playernode(player_name: String, peer_id: int):
|
||||||
playernode.name_changed.connect(_on_playernode_name_changed.bind(playernode))
|
playernode.name_changed.connect(_on_playernode_name_changed.bind(playernode))
|
||||||
playernode.color_changed.connect(_on_playernode_color_changed.bind(playernode))
|
playernode.color_changed.connect(_on_playernode_color_changed.bind(playernode))
|
||||||
playernode.possessed.connect(_on_playernode_possessed.bind(playernode))
|
playernode.possessed.connect(_on_playernode_possessed.bind(playernode))
|
||||||
|
playernode.score_reported.connect(_on_playernode_score_reported.bind(playernode))
|
||||||
|
playernode.scores_changed.connect(_on_playernode_scores_changed.bind(playernode))
|
||||||
var sanitized_player_name = PlayerNode.sanitize_player_name(player_name)
|
var sanitized_player_name = PlayerNode.sanitize_player_name(player_name)
|
||||||
playernode.player_name = sanitized_player_name
|
playernode.player_name = sanitized_player_name
|
||||||
playernode.name = sanitized_player_name
|
playernode.name = sanitized_player_name
|
||||||
|
@ -35,21 +37,33 @@ func rpc_possess_playernode(player_name: String, peer_id: int):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _on_playernode_name_changed(old: String, new: String, playernode: PlayerNode):
|
func _on_playernode_name_changed(old: String, new: String, playernode: PlayerNode) -> void:
|
||||||
playernode_name_changed.emit(old, new, playernode)
|
playernode_name_changed.emit(old, new, playernode)
|
||||||
|
|
||||||
func _on_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode):
|
func _on_playernode_color_changed(old: Color, new: Color, playernode: PlayerNode) -> void:
|
||||||
playernode_color_changed.emit(old, new, playernode)
|
playernode_color_changed.emit(old, new, playernode)
|
||||||
|
|
||||||
func _on_playernode_possessed(old: int, new: int, playernode: PlayerNode):
|
func _on_playernode_possessed(old: int, new: int, playernode: PlayerNode) -> void:
|
||||||
playernode_possessed.emit(old, new, playernode)
|
playernode_possessed.emit(old, new, playernode)
|
||||||
|
|
||||||
|
func _on_playernode_score_reported(strokes: int, playernode: PlayerNode) -> void:
|
||||||
|
playernode_score_reported.emit(strokes, playernode)
|
||||||
|
|
||||||
|
func _on_playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode) -> void:
|
||||||
|
playernode_scores_changed.emit(old, new, playernode)
|
||||||
|
|
||||||
|
|
||||||
## Emitted when the name of one of the children [PlayerNode]s changes on the local scene.
|
## Emitted when the name of one of the children [PlayerNode]s changes on the local scene.
|
||||||
signal playernode_name_changed(old: String, new: String, playernode: PlayerNode)
|
signal playernode_name_changed(old: String, new: String, playernode: PlayerNode)
|
||||||
|
|
||||||
## Emitted when the name of one of the children [PlayerNode]s changes on the local scene.
|
## Emitted when the color of one of the children [PlayerNode]s changes on the local scene.
|
||||||
signal playernode_color_changed(old: Color, new: Color, playernode: PlayerNode)
|
signal playernode_color_changed(old: Color, new: Color, playernode: PlayerNode)
|
||||||
|
|
||||||
## Emitted everywhere when one of the children [PlayerNode]s has changed multiplayer authority.
|
## Emitted everywhere when one of the children [PlayerNode]s has changed multiplayer authority.
|
||||||
signal playernode_possessed(old: int, new: int, playernode: PlayerNode)
|
signal playernode_possessed(old: int, new: int, playernode: PlayerNode)
|
||||||
|
|
||||||
|
## Emitted when a [PlayerNode] reports a score.
|
||||||
|
signal playernode_score_reported(strokes: int, playernode: PlayerNode)
|
||||||
|
|
||||||
|
## Emitted when the scores of one of the children [PlayerNode]s change on the local scene.
|
||||||
|
signal playernode_scores_changed(old: Array, new: Array, playernode: PlayerNode)
|
||||||
|
|
Loading…
Reference in a new issue