1
Fork 0
mirror of https://github.com/Steffo99/nanogolf.git synced 2024-11-25 01:24:18 +00:00
This commit is contained in:
Steffo 2024-03-16 05:25:23 +01:00
parent 5bf510d4c7
commit 76f304613c
Signed by: steffo
GPG key ID: 5ADA3868646C3FC0
19 changed files with 346 additions and 37 deletions

View 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

View file

@ -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():
@ -96,3 +103,7 @@ 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)

View file

@ -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
View 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
View 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

View file

@ -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)

View file

@ -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")

View file

@ -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()

View file

@ -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"]

View file

@ -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")

View file

@ -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()

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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")

View 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

View 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")

View file

@ -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)

View file

@ -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)