1
Fork 0
mirror of https://github.com/Steffo99/nanogolf.git synced 2024-11-24 09:04:19 +00:00

Have the server distribute the GolfLevel to clients

This commit is contained in:
Steffo 2024-03-14 05:17:00 +01:00
parent dd0ab7ee54
commit c252fe13fc
Signed by: steffo
GPG key ID: 5ADA3868646C3FC0
17 changed files with 379 additions and 107 deletions

18
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,18 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "GDScript: Launch Project",
"type": "godot",
"request": "launch",
"project": "${workspaceFolder}",
"debug_collisions": false,
"debug_paths": false,
"debug_navigation": false,
"additional_options": ""
}
]
}

View file

@ -2,9 +2,9 @@ extends Camera2D
class_name FollowCamera class_name FollowCamera
@export var target: Node2D @export var target: Node2D = null
func _physics_process(_delta): func _physics_process(_delta):
if target: if target != null:
position = target.position position = target.position

View file

@ -1,5 +1,6 @@
[gd_scene format=3 uid="uid://c5ck3dhekpwb8"] [gd_scene load_steps=2 format=3 uid="uid://c5ck3dhekpwb8"]
[ext_resource type="Script" path="res://scenes/follow_camera.gd" id="1_kvu2h"]
[node name="FollowCamera" type="Camera2D"] [node name="FollowCamera" type="Camera2D"]
editor_draw_limits = true script = ExtResource("1_kvu2h")
editor_draw_drag_margin = true

View file

@ -9,13 +9,16 @@ var local_player_color: Color
## The [PeerNodeDirectory] instance child of this node. ## The [PeerNodeDirectory] instance child of this node.
@onready var peer_dir: PeerNodeDirectory = $"PeerNodeDirectory" @export var peer_dir: PeerNodeDirectory = null
## The [PlayerNodeDirectory] instance child of this node. ## The [PlayerNodeDirectory] instance child of this node.
@onready var player_dir: PlayerNodeDirectory = $"PlayerNodeDirectory" @export var player_dir: PlayerNodeDirectory = null
## The [PhaseTracker] instance child of this node. ## The [PhaseTracker] instance child of this node.
@onready var phase_tracker: PhaseTracker = $"PhaseTracker" @export var phase_tracker: PhaseTracker = null
## The [LevelManager] instance child of this node.
@export var level_manager: LevelManager = null
## Initialize some signals needed by this node to function properly. ## Initialize some signals needed by this node to function properly.
@ -92,3 +95,4 @@ 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()

View file

@ -1,12 +1,21 @@
[gd_scene load_steps=5 format=3 uid="uid://dyxwp5rnxiff7"] [gd_scene load_steps=10 format=3 uid="uid://dyxwp5rnxiff7"]
[ext_resource type="Script" path="res://scenes/game.gd" id="1_cdtng"] [ext_resource type="Script" path="res://scenes/game.gd" id="1_cdtng"]
[ext_resource type="PackedScene" uid="uid://7ux0cl08c2ho" path="res://scenes/peernode_directory.tscn" id="1_p0gju"] [ext_resource type="PackedScene" uid="uid://7ux0cl08c2ho" path="res://scenes/peernode_directory.tscn" id="1_p0gju"]
[ext_resource type="PackedScene" uid="uid://d3jo4swi2c7ae" path="res://scenes/playernode_directory.tscn" id="2_pvlqw"] [ext_resource type="PackedScene" uid="uid://d3jo4swi2c7ae" path="res://scenes/playernode_directory.tscn" id="2_pvlqw"]
[ext_resource type="PackedScene" uid="uid://dc8pe5dnk8kbv" path="res://scenes/phase_tracker.tscn" id="4_kab4c"] [ext_resource type="PackedScene" uid="uid://dc8pe5dnk8kbv" path="res://scenes/phase_tracker.tscn" id="4_kab4c"]
[ext_resource type="PackedScene" uid="uid://dnryhtnk21ep1" path="res://scenes/level_manager.tscn" id="5_tdqk1"]
[ext_resource type="PackedScene" uid="uid://g03qgetpy6b5" path="res://scenes/level_playlist.tscn" id="6_bk2n3"]
[ext_resource type="Script" path="res://scenes/level_playlist.gd" id="7_akb5s"]
[ext_resource type="PackedScene" uid="uid://coh35s53wjxoa" path="res://scenes/golf_level_1.tscn" id="8_h8dsk"]
[ext_resource type="PackedScene" uid="uid://dts4o84p3vj5c" path="res://scenes/golf_level_2.tscn" id="9_2kliu"]
[node name="Game" type="Node"] [node name="Game" type="Node" node_paths=PackedStringArray("peer_dir", "player_dir", "phase_tracker", "level_manager")]
script = ExtResource("1_cdtng") script = ExtResource("1_cdtng")
peer_dir = NodePath("PeerNodeDirectory")
player_dir = NodePath("PlayerNodeDirectory")
phase_tracker = NodePath("PhaseTracker")
level_manager = NodePath("LevelManager")
[node name="PeerNodeDirectory" parent="." instance=ExtResource("1_p0gju")] [node name="PeerNodeDirectory" parent="." instance=ExtResource("1_p0gju")]
@ -14,6 +23,14 @@ script = ExtResource("1_cdtng")
[node name="PhaseTracker" parent="." instance=ExtResource("4_kab4c")] [node name="PhaseTracker" parent="." instance=ExtResource("4_kab4c")]
[node name="LevelManager" parent="." node_paths=PackedStringArray("playlist", "player_dir") instance=ExtResource("5_tdqk1")]
playlist = NodePath("LevelPlaylist")
player_dir = NodePath("../PlayerNodeDirectory")
[node name="LevelPlaylist" parent="LevelManager" instance=ExtResource("6_bk2n3")]
script = ExtResource("7_akb5s")
levels = Array[PackedScene]([ExtResource("8_h8dsk"), ExtResource("9_2kliu")])
[connection signal="child_entered_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_created"] [connection signal="child_entered_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_created"]
[connection signal="child_exiting_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_destroyed"] [connection signal="child_exiting_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_destroyed"]
[connection signal="peernode_identified" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_identified"] [connection signal="peernode_identified" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_identified"]

View file

@ -34,7 +34,8 @@ var player_name: String = "Player":
return player_name return player_name
set(value): set(value):
player_name = value player_name = value
player_label.text = value if player_label:
player_label.text = value
## The color of the player represented by this scene. ## The color of the player represented by this scene.
var player_color: Color = Color.WHITE: var player_color: Color = Color.WHITE:
@ -45,12 +46,12 @@ var player_color: Color = Color.WHITE:
modulate = value modulate = value
func _on_putt(putt_vector: Vector2): func _on_putt(putt_vector: Vector2) -> void:
strokes += 1 strokes += 1
velocity += putt_vector velocity += putt_vector
func do_movement(delta: float): func do_movement(delta: float) -> void:
# How much the body should move in this physics step. # How much the body should move in this physics step.
var movement = velocity * delta var movement = velocity * delta
# How many times the body collided in the current physics step. # How many times the body collided in the current physics step.
@ -87,7 +88,7 @@ func do_movement(delta: float):
velocity *= physics_bounce_coefficient velocity *= physics_bounce_coefficient
func apply_friction(delta): func apply_friction(delta) -> void:
var new_velocity_length = max(0.0, velocity.length() - physics_friction * delta) var new_velocity_length = max(0.0, velocity.length() - physics_friction * delta)
velocity = velocity.normalized() * new_velocity_length velocity = velocity.normalized() * new_velocity_length
@ -100,7 +101,7 @@ func check_has_entered_hole() -> bool:
return check_has_stopped() and hole_controller.over_hole return check_has_stopped() and hole_controller.over_hole
func enter_hole(): func enter_hole() -> void:
in_hole = true in_hole = true
visible = false visible = false
hole_sound.play() hole_sound.play()
@ -108,7 +109,11 @@ func enter_hole():
print("[GolfBall] Entered hole in: ", strokes) print("[GolfBall] Entered hole in: ", strokes)
func _physics_process(delta): func _ready() -> void:
player_label.text = player_name
func _physics_process(delta) -> void:
if not in_hole: if not in_hole:
do_movement(delta) do_movement(delta)
apply_friction(delta) apply_friction(delta)

174
scenes/golf_level.gd Normal file
View file

@ -0,0 +1,174 @@
extends Node2D
class_name GolfLevel
@export_category("Level Data")
## Whether the [field camera] follows the active player or not.
@export var camera_follows_player: bool = false
@export_category("References")
## The [Camera2D] of this level.
@export var camera: Camera2D = null
## The [GolfTee] of this level.
@export var tee: GolfTee = null
## The [GolfHole] of this level.
@export var hole: GolfHole = null
## The [TileMap] of this level.
@export var map: TileMap = null
## If on server, this variable indicates the [GolfLevel] to replicate on clients.
##
## The [GolfLevel] in question should not be added to the scene tree, or it will cause problems on the client acting as server.
##
## On clients, this variable is ignored.
var target: GolfLevel = null
## The [PlayerNodeDirectory] to use to determine which players to spawn on clients.
##
## It should be set on instantiation of a new [GolfLevel].
var player_dir: PlayerNodeDirectory = null
## The [PackedScene] to initialize on clients as [TileMap].
const tilemap_scene: PackedScene = preload("res://scenes/golf_tilemap.tscn")
## The [PackedScene] to initialize on clients as [GolfTee].
const tee_scene: PackedScene = preload("res://scenes/golf_tee.tscn")
## The [PackedScene] to initialize on clients as [GolfHole].
const hole_scene: PackedScene = preload("res://scenes/golf_hole.tscn")
## The [PackedScene] to initialize on clients as [Camera2D].
const camera_scene: PackedScene = preload("res://scenes/follow_camera.tscn")
## Replicate the [field target] from the server to the clients via RPC.
func build() -> void:
build_tilemap()
build_tilemap_cells()
build_tee()
build_hole()
build_camera()
## Replicate the [field map] of the [field target] to the remote [field map].
func build_tilemap() -> void:
Log.peer(self, "Replicating map...")
var tmap: TileMap = target.map
rpc_build_tilemap.rpc(tmap.global_position, tmap.global_rotation, tmap.global_scale)
## Create the [field map] on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tilemap(tposition: Vector2, trotation: float, tscale: Vector2):
Log.peer(self, "Building map...")
map = tilemap_scene.instantiate()
map.global_position = tposition
map.global_rotation = trotation
map.global_scale = tscale
add_child(map)
## Replicate the cells of [field target]'s [field map] to the remote [field map].
##
## The [field map] must be already created on clients.
##
## Only takes layer 0 into consideration.
func build_tilemap_cells() -> void:
Log.peer(self, "Replicating map cells...")
var tmap: TileMap = target.map
const layer = 0
for coords in tmap.get_used_cells(layer):
var source_id: int = tmap.get_cell_source_id(0, coords)
var atlas_coords: Vector2i = tmap.get_cell_atlas_coords(0, coords)
var alternative_tile: int = tmap.get_cell_alternative_tile(0, coords)
rpc_build_tilemap_cell.rpc(layer, coords, source_id, atlas_coords, alternative_tile)
## Create a cell of [field map] on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tilemap_cell(
layer: int,
coords: Vector2i,
source_id: int,
atlas_coords: Vector2i = Vector2i(-1, -1),
alternative_tile: int = 0
):
Log.peer(self, "Building map cell: %s" % coords)
map.set_cell(layer, coords, source_id, atlas_coords, alternative_tile)
## Replicate the [field tee] of the [field target] to the remote [field tee].
func build_tee() -> void:
Log.peer(self, "Replicating tee...")
var ttee: GolfTee = target.tee
rpc_build_tee.rpc(ttee.global_position)
rpc_build_tee_balls.rpc()
## Create the [GolfTee] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tee(tposition: Vector2):
Log.peer(self, "Building tee...")
tee = tee_scene.instantiate()
tee.global_position = tposition
add_child(tee)
## Create and initialize the [GolfBall] object on clients, at the [GolfTee]'s position.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tee_balls():
Log.peer(self, "Building tee balls...")
for playernode in player_dir.get_children():
var ball: GolfBall = tee.create(playernode)
add_child(ball)
## Create and initialize a [GolfBall] for a single [PlayerNode] with the given name.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tee_ball(player_name: String):
Log.peer(self, "Building tee ball for: %s" % player_name)
var playernode: PlayerNode = player_dir.get_playernode(player_name)
var ball: GolfBall = tee.create(playernode)
add_child(ball)
## Replicate the [field hole] of the [field target] to the remote [field hole].
func build_hole() -> void:
Log.peer(self, "Replicating hole...")
var thole: GolfHole = target.hole
rpc_build_hole.rpc(thole.global_position, thole.global_scale)
## Create the [GolfHole] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_hole(tposition: Vector2, tscale: Vector2):
Log.peer(self, "Building hole...")
hole = hole_scene.instantiate()
hole.global_position = tposition
hole.global_scale = tscale
add_child(hole)
## Replicate the [field camera] of the [field target] to the remote [field camera].
func build_camera() -> void:
Log.peer(self, "Replicating camera...")
var tcamera: FollowCamera = target.camera
rpc_build_camera.rpc(tcamera.global_position, target.camera_follows_player)
## Create the [Camera2D] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_camera(tposition: Vector2, tfocus: bool):
Log.peer(self, "Building camera...")
camera = camera_scene.instantiate()
camera.global_position = tposition
if tfocus:
camera.target = null # TODO: Find local player
add_child(camera)
func _on_playernode_created(node: Node):
Log.peer(self, "Spawning new player...")
var playernode: PlayerNode = node as PlayerNode
rpc_build_tee_ball.rpc(playernode.player_name)

6
scenes/golf_level.tscn Normal file
View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://bph5j1gd6gnap"]
[ext_resource type="Script" path="res://scenes/golf_level.gd" id="1_evup0"]
[node name="GolfLevel" type="Node2D"]
script = ExtResource("1_evup0")

View file

@ -1,22 +1,25 @@
[gd_scene load_steps=4 format=3 uid="uid://coh35s53wjxoa"] [gd_scene load_steps=6 format=3 uid="uid://coh35s53wjxoa"]
[ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_r070t"] [ext_resource type="Script" path="res://scenes/golf_level.gd" id="1_qljh7"]
[ext_resource type="PackedScene" uid="uid://ca06elq8io5wu" path="res://scenes/golf_ball.tscn" id="2_ek6nk"] [ext_resource type="PackedScene" uid="uid://c5vbxqhevocy7" path="res://scenes/golf_tee.tscn" id="2_arnp6"]
[ext_resource type="PackedScene" uid="uid://c5ck3dhekpwb8" path="res://scenes/follow_camera.tscn" id="2_xa6so"]
[ext_resource type="PackedScene" uid="uid://df7t70153a3bb" path="res://scenes/golf_hole.tscn" id="3_mxcvd"] [ext_resource type="PackedScene" uid="uid://df7t70153a3bb" path="res://scenes/golf_hole.tscn" id="3_mxcvd"]
[ext_resource type="PackedScene" uid="uid://dck5lkoxskrel" path="res://scenes/golf_tilemap.tscn" id="4_1xa4t"]
[node name="GolfLevel1" type="Node2D"] [node name="GolfLevel" type="Node2D" node_paths=PackedStringArray("camera", "tee", "hole", "map")]
script = ExtResource("1_qljh7")
camera = NodePath("FollowCamera")
tee = NodePath("GolfTee")
hole = NodePath("GolfHole")
map = NodePath("TileMap")
[node name="Camera" type="Camera2D" parent="."] [node name="FollowCamera" parent="." instance=ExtResource("2_xa6so")]
[node name="TileMap" type="TileMap" parent="."] [node name="GolfTee" parent="." instance=ExtResource("2_arnp6")]
scale = Vector2(0.125, 0.125)
tile_set = ExtResource("1_r070t")
format = 2
layer_0/tile_data = PackedInt32Array(131067, 2, 0, 196603, 2, 0, 262139, 2, 0, 327675, 2, 0, 393211, 2, 0, 458747, 2, 0, -196612, 1, 0, -524291, 2, 0, -458755, 2, 0, -393219, 2, 0, -327683, 2, 0, -262147, 1, 0, -589822, 2, 0, -524286, 2, 0, 65540, 2, 0, 131076, 2, 0, 196612, 2, 0, 262148, 2, 0, 327684, 2, 0, 393220, 2, 0, -196613, 1, 805306368, -262148, 1, 805306368, -589827, 2, 0, -589826, 2, 0, 655358, 2, 0, -589825, 2, 0, 655359, 2, 0, -655360, 2, 0, 589824, 2, 0, -655359, 2, 0, 589825, 2, 0, -655358, 2, 0, 524284, 1, 536870912, 458755, 1, 805306368, 589821, 1, 536870912, 524283, 1, 268435456, 589820, 1, 268435456, 655357, 1, 268435456, 589826, 1, 0, 524291, 1, 0, 458756, 1, 0, 524290, 1, 805306368, -196604, 2, 0, -131068, 2, 0, -65532, 2, 0, 4, 2, 0, -262140, 1, 536870912, -327677, 1, 536870912, -327678, 1, 268435456, -393214, 2, 0, -262141, 1, 268435456, -458750, 2, 0, -5, 2, 0, 65531, 2, 0, -131077, 2, 0, -65541, 2, 0, 65535, 1, 805306368, 131071, 1, 268435456, 0, 1, 536870912, 65536, 1, 0)
metadata/_edit_lock_ = true
[node name="GolfBall" parent="." instance=ExtResource("2_ek6nk")]
position = Vector2(0, -112) position = Vector2(0, -112)
[node name="GolfHole" parent="." instance=ExtResource("3_mxcvd")] [node name="GolfHole" parent="." instance=ExtResource("3_mxcvd")]
position = Vector2(0, 100) position = Vector2(0, 100)
[node name="TileMap" parent="." instance=ExtResource("4_1xa4t")]
layer_0/tile_data = PackedInt32Array(-458748, 2, 0, -524284, 2, 0, -589820, 2, 0, -655356, 2, 0, -655357, 2, 0, -655358, 2, 0, -655359, 2, 0, -655360, 2, 0, -589825, 2, 0, -589826, 2, 0, -589827, 2, 0, -589828, 2, 0, -589829, 2, 0, -524293, 2, 0, -458757, 2, 0, -393221, 2, 0, -327685, 2, 0, -262149, 2, 0, -393212, 2, 0, -327676, 2, 0, -262140, 2, 0, -196604, 2, 0, -131068, 2, 0, -65532, 2, 0, -196613, 2, 0, -131077, 2, 0, -65541, 2, 0, -5, 2, 0, 65531, 2, 0, 131067, 2, 0, 196603, 2, 0, 262139, 2, 0, 327675, 2, 0, 393211, 2, 0, 458747, 2, 0, 524283, 2, 0, 589819, 2, 0, 589820, 2, 0, 589821, 2, 0, 589822, 2, 0, 589823, 2, 0, 524288, 2, 0, 524289, 2, 0, 524290, 2, 0, 524291, 2, 0, 524292, 2, 0, 4, 2, 0, 65540, 2, 0, 131076, 2, 0, 196612, 2, 0, 262148, 2, 0, 327684, 2, 0, 393220, 2, 0, 458756, 2, 0)

View file

@ -1,19 +1,30 @@
[gd_scene load_steps=6 format=3 uid="uid://dts4o84p3vj5c"] [gd_scene load_steps=6 format=3 uid="uid://dts4o84p3vj5c"]
[ext_resource type="PackedScene" uid="uid://c5ck3dhekpwb8" path="res://scenes/follow_camera.tscn" id="1_3a7ly"] [ext_resource type="PackedScene" uid="uid://c5ck3dhekpwb8" path="res://scenes/follow_camera.tscn" id="1_3a7ly"]
[ext_resource type="Script" path="res://scenes/golf_level.gd" id="1_ac6s6"]
[ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_h4d2b"] [ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_h4d2b"]
[ext_resource type="PackedScene" uid="uid://ca06elq8io5wu" path="res://scenes/golf_ball.tscn" id="2_244ns"] [ext_resource type="PackedScene" uid="uid://c5vbxqhevocy7" path="res://scenes/golf_tee.tscn" id="3_6q2yk"]
[ext_resource type="Script" path="res://scenes/follow_camera.gd" id="2_l7nsy"]
[ext_resource type="PackedScene" uid="uid://df7t70153a3bb" path="res://scenes/golf_hole.tscn" id="3_kt60g"] [ext_resource type="PackedScene" uid="uid://df7t70153a3bb" path="res://scenes/golf_hole.tscn" id="3_kt60g"]
[node name="GolfLevel2" type="Node2D"] [node name="GolfLevel" type="Node2D" node_paths=PackedStringArray("camera", "tee", "hole", "map")]
script = ExtResource("1_ac6s6")
camera_follows_player = true
camera = NodePath("FollowCamera")
tee = NodePath("GolfTee")
hole = NodePath("GolfHole")
map = NodePath("TileMap")
[node name="FollowCamera" parent="." node_paths=PackedStringArray("target") instance=ExtResource("1_3a7ly")] [node name="FollowCamera" parent="." node_paths=PackedStringArray("target") instance=ExtResource("1_3a7ly")]
process_callback = 0 process_callback = 0
position_smoothing_enabled = true position_smoothing_enabled = true
drag_vertical_enabled = true drag_vertical_enabled = true
script = ExtResource("2_l7nsy") target = NodePath("")
target = NodePath("../GolfBall")
[node name="GolfTee" parent="." instance=ExtResource("3_6q2yk")]
position = Vector2(0, -112)
[node name="GolfHole" parent="." instance=ExtResource("3_kt60g")]
position = Vector2(0, 488)
[node name="TileMap" type="TileMap" parent="."] [node name="TileMap" type="TileMap" parent="."]
scale = Vector2(0.125, 0.125) scale = Vector2(0.125, 0.125)
@ -21,9 +32,3 @@ tile_set = ExtResource("1_h4d2b")
format = 2 format = 2
layer_0/tile_data = PackedInt32Array(131067, 2, 0, 196603, 2, 0, 262139, 2, 0, 327675, 2, 0, 393211, 2, 0, 458747, 2, 0, -196612, 1, 0, -524291, 2, 0, -458755, 2, 0, -393219, 2, 0, -327683, 2, 0, -262147, 1, 0, -589822, 2, 0, -524286, 2, 0, 65540, 2, 0, 131076, 2, 0, 196612, 2, 0, 262148, 2, 0, 327684, 2, 0, 393220, 2, 0, -196613, 1, 805306368, -262148, 1, 805306368, -589827, 2, 0, -589826, 2, 0, -589825, 2, 0, -655360, 2, 0, -655359, 2, 0, -655358, 2, 0, 524284, 1, 536870912, 458755, 1, 805306368, 589821, 1, 536870912, 524283, 1, 268435456, 589820, 1, 268435456, 524291, 1, 0, 458756, 1, 0, 524290, 1, 805306368, -196604, 2, 0, -131068, 2, 0, -65532, 2, 0, 4, 2, 0, -262140, 1, 536870912, -327677, 1, 536870912, -327678, 1, 268435456, -393214, 2, 0, -262141, 1, 268435456, -458750, 2, 0, -5, 2, 0, 65531, 2, 0, -131077, 2, 0, -65541, 2, 0, 655357, 2, 0, 720893, 2, 0, 786429, 2, 0, 851965, 2, 0, 589826, 2, 0, 655362, 2, 0, 720898, 2, 0, 786434, 2, 0, 851970, 2, 0, 917506, 2, 0, 983042, 2, 0, 917501, 2, 0, 983037, 2, 0, 1048573, 2, 0, 1114109, 1, 0, 1179644, 1, 0, 1245179, 1, 0, 1048578, 1, 268435456, 1114115, 1, 268435456, 1179652, 1, 268435456, 1114116, 1, 536870912, 1179653, 1, 536870912, 1048579, 1, 536870912, 1114108, 1, 805306368, 1179643, 1, 805306368, 1245178, 1, 805306368, 1441783, 1, 805306368, 1376248, 1, 805306368, 1441784, 1, 0, 1310713, 1, 805306368, 1376249, 1, 0, 1310714, 1, 0, 1245189, 1, 268435456, 1245190, 1, 536870912, 1310726, 1, 268435456, 1310727, 1, 536870912, 1376263, 1, 268435456, 1376264, 1, 536870912, 1441800, 1, 268435456, 1441801, 1, 536870912, 1507337, 1, 268435456, 1507338, 1, 536870912, 1572874, 1, 268435456, 1572875, 1, 536870912, 1638411, 1, 268435456, 1638412, 1, 536870912, 1703948, 1, 268435456, 1703949, 1, 536870912, 1769485, 1, 268435456, 1769486, 1, 536870912, 1834993, 1, 805306368, 1769458, 1, 805306368, 1834994, 1, 0, 1703923, 1, 805306368, 1769459, 1, 0, 1638388, 1, 805306368, 1703924, 1, 0, 1572853, 1, 805306368, 1638389, 1, 0, 1507318, 1, 805306368, 1572854, 1, 0, 1507319, 1, 0, 1900529, 2, 0, 1966065, 2, 0, 2031601, 2, 0, 2097137, 2, 0, 2162673, 2, 0, 1835022, 2, 0, 1900558, 2, 0, 1966094, 2, 0, 2031630, 2, 0, 2097166, 2, 0, 2162702, 2, 0, 2162701, 2, 0, 2162700, 2, 0, 2162699, 2, 0, 2162698, 2, 0, 2162697, 2, 0, 2162696, 2, 0, 2162695, 2, 0, 2162694, 2, 0, 2162693, 2, 0, 2162692, 2, 0, 2162691, 2, 0, 2162690, 2, 0, 2162689, 2, 0, 2162688, 2, 0, 2228223, 2, 0, 2228222, 2, 0, 2228221, 2, 0, 2228220, 2, 0, 2228219, 2, 0, 2228218, 2, 0, 2228217, 2, 0, 2228216, 2, 0, 2228215, 2, 0, 2228214, 2, 0, 2228213, 2, 0, 2228212, 2, 0, 2228211, 2, 0, 2228210, 2, 0, 2228209, 2, 0, 1245184, 3, 805306368, 1441791, 3, 805306368, 1507328, 3, 805306368, 1703935, 3, 805306368, 1769472, 3, 805306368, 1835005, 3, 805306368, 1572861, 3, 805306368, 1376258, 3, 805306368, 1638402, 3, 805306368, 1703931, 3, 805306368, 1507332, 3, 805306368) layer_0/tile_data = PackedInt32Array(131067, 2, 0, 196603, 2, 0, 262139, 2, 0, 327675, 2, 0, 393211, 2, 0, 458747, 2, 0, -196612, 1, 0, -524291, 2, 0, -458755, 2, 0, -393219, 2, 0, -327683, 2, 0, -262147, 1, 0, -589822, 2, 0, -524286, 2, 0, 65540, 2, 0, 131076, 2, 0, 196612, 2, 0, 262148, 2, 0, 327684, 2, 0, 393220, 2, 0, -196613, 1, 805306368, -262148, 1, 805306368, -589827, 2, 0, -589826, 2, 0, -589825, 2, 0, -655360, 2, 0, -655359, 2, 0, -655358, 2, 0, 524284, 1, 536870912, 458755, 1, 805306368, 589821, 1, 536870912, 524283, 1, 268435456, 589820, 1, 268435456, 524291, 1, 0, 458756, 1, 0, 524290, 1, 805306368, -196604, 2, 0, -131068, 2, 0, -65532, 2, 0, 4, 2, 0, -262140, 1, 536870912, -327677, 1, 536870912, -327678, 1, 268435456, -393214, 2, 0, -262141, 1, 268435456, -458750, 2, 0, -5, 2, 0, 65531, 2, 0, -131077, 2, 0, -65541, 2, 0, 655357, 2, 0, 720893, 2, 0, 786429, 2, 0, 851965, 2, 0, 589826, 2, 0, 655362, 2, 0, 720898, 2, 0, 786434, 2, 0, 851970, 2, 0, 917506, 2, 0, 983042, 2, 0, 917501, 2, 0, 983037, 2, 0, 1048573, 2, 0, 1114109, 1, 0, 1179644, 1, 0, 1245179, 1, 0, 1048578, 1, 268435456, 1114115, 1, 268435456, 1179652, 1, 268435456, 1114116, 1, 536870912, 1179653, 1, 536870912, 1048579, 1, 536870912, 1114108, 1, 805306368, 1179643, 1, 805306368, 1245178, 1, 805306368, 1441783, 1, 805306368, 1376248, 1, 805306368, 1441784, 1, 0, 1310713, 1, 805306368, 1376249, 1, 0, 1310714, 1, 0, 1245189, 1, 268435456, 1245190, 1, 536870912, 1310726, 1, 268435456, 1310727, 1, 536870912, 1376263, 1, 268435456, 1376264, 1, 536870912, 1441800, 1, 268435456, 1441801, 1, 536870912, 1507337, 1, 268435456, 1507338, 1, 536870912, 1572874, 1, 268435456, 1572875, 1, 536870912, 1638411, 1, 268435456, 1638412, 1, 536870912, 1703948, 1, 268435456, 1703949, 1, 536870912, 1769485, 1, 268435456, 1769486, 1, 536870912, 1834993, 1, 805306368, 1769458, 1, 805306368, 1834994, 1, 0, 1703923, 1, 805306368, 1769459, 1, 0, 1638388, 1, 805306368, 1703924, 1, 0, 1572853, 1, 805306368, 1638389, 1, 0, 1507318, 1, 805306368, 1572854, 1, 0, 1507319, 1, 0, 1900529, 2, 0, 1966065, 2, 0, 2031601, 2, 0, 2097137, 2, 0, 2162673, 2, 0, 1835022, 2, 0, 1900558, 2, 0, 1966094, 2, 0, 2031630, 2, 0, 2097166, 2, 0, 2162702, 2, 0, 2162701, 2, 0, 2162700, 2, 0, 2162699, 2, 0, 2162698, 2, 0, 2162697, 2, 0, 2162696, 2, 0, 2162695, 2, 0, 2162694, 2, 0, 2162693, 2, 0, 2162692, 2, 0, 2162691, 2, 0, 2162690, 2, 0, 2162689, 2, 0, 2162688, 2, 0, 2228223, 2, 0, 2228222, 2, 0, 2228221, 2, 0, 2228220, 2, 0, 2228219, 2, 0, 2228218, 2, 0, 2228217, 2, 0, 2228216, 2, 0, 2228215, 2, 0, 2228214, 2, 0, 2228213, 2, 0, 2228212, 2, 0, 2228211, 2, 0, 2228210, 2, 0, 2228209, 2, 0, 1245184, 3, 805306368, 1441791, 3, 805306368, 1507328, 3, 805306368, 1703935, 3, 805306368, 1769472, 3, 805306368, 1835005, 3, 805306368, 1572861, 3, 805306368, 1376258, 3, 805306368, 1638402, 3, 805306368, 1703931, 3, 805306368, 1507332, 3, 805306368)
metadata/_edit_lock_ = true metadata/_edit_lock_ = true
[node name="GolfBall" parent="." instance=ExtResource("2_244ns")]
position = Vector2(0, -112)
[node name="GolfHole" parent="." instance=ExtResource("3_kt60g")]
position = Vector2(0, 488)

View file

@ -1,2 +1,46 @@
extends Node2D extends Node2D
class_name GolfTee class_name GolfTee
## The [GolfBall] [PackedScene] to [method spawn].
const ball_scene: PackedScene = preload("res://scenes/golf_ball.tscn")
## Create a new [GolfBall] from [field ball_scene], initialize it with details from the given [PlayerNode], and return it.
##
## Note that this does not add the [GolfBall] to the scene tree, as it is the [GolfLevel]'s responsibility to do so.
func create(playernode: PlayerNode) -> GolfBall:
# Create the [GolfBall]
var obj: GolfBall = ball_scene.instantiate()
# Setup the initial values
obj.global_position = global_position
obj.player_name = playernode.player_name
obj.player_color = playernode.player_color
obj.set_multiplayer_authority(playernode.get_multiplayer_authority())
# Create callables to be able to cleanup signals on destruction
var on_name_changed: Callable = _on_name_changed.bind(obj)
var on_color_changed: Callable = _on_color_changed.bind(obj)
var on_possessed: Callable = _on_possessed.bind(obj)
var on_cleanup: Callable = _on_cleanup.bind(playernode, on_name_changed, on_color_changed, on_possessed)
# Setup signals to keep properties updated
playernode.name_changed.connect(on_name_changed)
playernode.color_changed.connect(on_color_changed)
playernode.possessed.connect(on_possessed)
obj.tree_exiting.connect(on_cleanup)
# Return the created [GolfBall]
return obj
func _on_name_changed(_old: String, new: String, obj: GolfBall) -> void:
obj.player_name = new
func _on_color_changed(_old: Color, new: Color, obj: GolfBall) -> void:
obj.player_color = new
func _on_possessed(_old: int, new: int, obj: GolfBall) -> void:
obj.set_multiplayer_authority(new)
func _on_cleanup(playernode: PlayerNode, on_name_changed: Callable, on_color_changed: Callable, on_possessed: Callable) -> void:
playernode.name_changed.disconnect(on_name_changed)
playernode.color_changed.disconnect(on_color_changed)
playernode.possessed.disconnect(on_possessed)

View file

@ -3,6 +3,7 @@
[ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_uf2u7"] [ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_uf2u7"]
[node name="TileMap" type="TileMap"] [node name="TileMap" type="TileMap"]
scale = Vector2(0.125, 0.125)
tile_set = ExtResource("1_uf2u7") tile_set = ExtResource("1_uf2u7")
format = 2 format = 2
layer_0/name = "Walls" layer_0/name = "Walls"

View file

@ -1,74 +1,39 @@
extends Node extends Node
class_name LevelManager class_name LevelManager
## The levels that should be loaded by the server and sent to the clients. ## The blank [GolfLevel] to initialize on clients.
const levels: Array[PackedScene] = [ const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
preload("res://scenes/golf_level_1.tscn"),
preload("res://scenes/golf_level_2.tscn"),
]
## The index of the current level in [field levels]. ## The [LevelPlaylist] to use to load [GolfLevel]s from.
var level_idx: int = -1 @export var playlist: LevelPlaylist = null
## Class containing the components of a level. ## The [PlayerNodeDirectory] to use to determine which players to spawn on clients.
class Components: @export var player_dir: PlayerNodeDirectory = null
## All levels must include a [TileMap] named "TileMap".
var tilemap: TileMap = null
## The [PackedScene] to initialize on clients as [TileMap].
const tilemap_scene: PackedScene = preload("res://scenes/golf_tilemap.tscn")
## All levels must include a [GolfTee] named "GolfTee".
##
## It will be used to spawn the player
var tee: GolfTee = null
## The [PackedScene] to initialize on clients as [GolfTee].
const tee_scene: PackedScene = preload("res://scenes/golf_tee.tscn")
## All levels must include a [GolfHole] named "GolfHole".
var hole: GolfHole = null
## The [PackedScene] to initialize on clients as [GolfHole].
const hole_scene = preload("res://scenes/golf_hole.tscn")
## Create a new [Components] instance from a [PackedScene].
static func from_scene(scene: PackedScene) -> Components:
var obj = new()
obj.tilemap = scene.get_node("TileMap")
obj.tee = scene.get_node("GolfTee")
obj.hole = scene.get_node("GolfHole")
return obj
## Create the [TileMap] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tilemap(parent: Node):
var obj = tilemap_scene.instantiate()
parent.add_child(obj)
## Create the [GolfTee] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_tee(parent: Node, position: Vector2):
var obj = tee_scene.instantiate()
obj.position = position
parent.add_child(obj)
## Create the [GolfHole] object on clients.
@rpc("authority", "call_remote", "reliable")
func rpc_build_hole(parent: Node, position: Vector2, scale: Vector2):
var obj = hole_scene.instantiate()
obj.position = position
obj.scale = scale
parent.add_child(obj)
## TODO: Place tiles
## The currently instantiated [GolfLevel].
func get_current_level() -> PackedScene: var level: GolfLevel = null
return levels[level_idx]
func load_level_components() -> Components: ## Create the empty [GolfLevel] object everywhere.
return Components.from_scene(get_current_level()) @rpc("authority", "call_local", "reliable")
func rpc_next_level():
# Destroy the current level
if level != null:
level.target.queue_free()
player_dir.child_entered_tree.disconnect(level._on_playernode_created)
level.queue_free()
level = null
# Create the new level
level = base_scene.instantiate()
level.player_dir = player_dir
# Determine the next level
if multiplayer.is_server():
var target = playlist.advance().instantiate()
level.target = target
player_dir.child_entered_tree.connect(level._on_playernode_created)
# Add the level to the tree
add_child(level)
# Start the replication
if multiplayer.is_server():
level.build()

View file

@ -1,3 +1,6 @@
[gd_scene format=3 uid="uid://dnryhtnk21ep1"] [gd_scene load_steps=2 format=3 uid="uid://dnryhtnk21ep1"]
[ext_resource type="Script" path="res://scenes/level_manager.gd" id="1_bv1lx"]
[node name="LevelManager" type="Node"] [node name="LevelManager" type="Node"]
script = ExtResource("1_bv1lx")

20
scenes/level_playlist.gd Normal file
View file

@ -0,0 +1,20 @@
extends Node
class_name LevelPlaylist
## The [GolfLevel]s that should be sequentially loaded on the [LevelManager].
@export var levels: Array[PackedScene] = []
## The index of the current level in [field levels].
var idx: int = -1
## Advances to the next level in the playlist and returns it as a [PackedScene].
##
## Returns null when the playlist is complete.
func advance() -> PackedScene:
idx += 1
if idx >= len(levels):
return null
return levels[idx]

View file

@ -0,0 +1,3 @@
[gd_scene format=3 uid="uid://g03qgetpy6b5"]
[node name="LevelPlaylist" type="Node"]

View file

@ -1,3 +1,6 @@
[gd_scene format=3 uid="uid://dc8pe5dnk8kbv"] [gd_scene load_steps=2 format=3 uid="uid://dc8pe5dnk8kbv"]
[ext_resource type="Script" path="res://scenes/phase_tracker.gd" id="1_k51gn"]
[node name="PhaseTracker" type="Node"] [node name="PhaseTracker" type="Node"]
script = ExtResource("1_k51gn")