mirror of
https://github.com/Steffo99/nanogolf.git
synced 2024-11-21 15:44:21 +00:00
Have the server distribute the GolfLevel to clients
This commit is contained in:
parent
dd0ab7ee54
commit
c252fe13fc
17 changed files with 379 additions and 107 deletions
18
.vscode/launch.json
vendored
Normal file
18
.vscode/launch.json
vendored
Normal 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": ""
|
||||
}
|
||||
]
|
||||
}
|
|
@ -2,9 +2,9 @@ extends Camera2D
|
|||
class_name FollowCamera
|
||||
|
||||
|
||||
@export var target: Node2D
|
||||
@export var target: Node2D = null
|
||||
|
||||
|
||||
func _physics_process(_delta):
|
||||
if target:
|
||||
if target != null:
|
||||
position = target.position
|
||||
|
|
|
@ -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"]
|
||||
editor_draw_limits = true
|
||||
editor_draw_drag_margin = true
|
||||
script = ExtResource("1_kvu2h")
|
||||
|
|
|
@ -9,13 +9,16 @@ var local_player_color: Color
|
|||
|
||||
|
||||
## 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.
|
||||
@onready var player_dir: PlayerNodeDirectory = $"PlayerNodeDirectory"
|
||||
@export var player_dir: PlayerNodeDirectory = null
|
||||
|
||||
## 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.
|
||||
|
@ -92,3 +95,4 @@ func _on_playerdir_playernode_possessed(old: int, new: int, playernode: PlayerNo
|
|||
func _on_main_start_confirmed() -> void:
|
||||
if multiplayer.is_server():
|
||||
phase_tracker.rpc_set_phase.rpc(PhaseTracker.Phase.PLAYING)
|
||||
level_manager.rpc_next_level.rpc()
|
|
@ -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="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://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")
|
||||
peer_dir = NodePath("PeerNodeDirectory")
|
||||
player_dir = NodePath("PlayerNodeDirectory")
|
||||
phase_tracker = NodePath("PhaseTracker")
|
||||
level_manager = NodePath("LevelManager")
|
||||
|
||||
[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="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_exiting_tree" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_destroyed"]
|
||||
[connection signal="peernode_identified" from="PeerNodeDirectory" to="." method="_on_peerdir_peernode_identified"]
|
||||
|
|
|
@ -34,7 +34,8 @@ var player_name: String = "Player":
|
|||
return player_name
|
||||
set(value):
|
||||
player_name = value
|
||||
player_label.text = value
|
||||
if player_label:
|
||||
player_label.text = value
|
||||
|
||||
## The color of the player represented by this scene.
|
||||
var player_color: Color = Color.WHITE:
|
||||
|
@ -45,12 +46,12 @@ var player_color: Color = Color.WHITE:
|
|||
modulate = value
|
||||
|
||||
|
||||
func _on_putt(putt_vector: Vector2):
|
||||
func _on_putt(putt_vector: Vector2) -> void:
|
||||
strokes += 1
|
||||
velocity += putt_vector
|
||||
|
||||
|
||||
func do_movement(delta: float):
|
||||
func do_movement(delta: float) -> void:
|
||||
# How much the body should move in this physics step.
|
||||
var movement = velocity * delta
|
||||
# How many times the body collided in the current physics step.
|
||||
|
@ -87,7 +88,7 @@ func do_movement(delta: float):
|
|||
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)
|
||||
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
|
||||
|
||||
|
||||
func enter_hole():
|
||||
func enter_hole() -> void:
|
||||
in_hole = true
|
||||
visible = false
|
||||
hole_sound.play()
|
||||
|
@ -108,7 +109,11 @@ func enter_hole():
|
|||
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:
|
||||
do_movement(delta)
|
||||
apply_friction(delta)
|
||||
|
|
174
scenes/golf_level.gd
Normal file
174
scenes/golf_level.gd
Normal 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
6
scenes/golf_level.tscn
Normal 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")
|
|
@ -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="PackedScene" uid="uid://ca06elq8io5wu" path="res://scenes/golf_ball.tscn" id="2_ek6nk"]
|
||||
[ext_resource type="Script" path="res://scenes/golf_level.gd" id="1_qljh7"]
|
||||
[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://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="."]
|
||||
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")]
|
||||
[node name="GolfTee" parent="." instance=ExtResource("2_arnp6")]
|
||||
position = Vector2(0, -112)
|
||||
|
||||
[node name="GolfHole" parent="." instance=ExtResource("3_mxcvd")]
|
||||
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)
|
||||
|
|
|
@ -1,19 +1,30 @@
|
|||
[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="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="PackedScene" uid="uid://ca06elq8io5wu" path="res://scenes/golf_ball.tscn" id="2_244ns"]
|
||||
[ext_resource type="Script" path="res://scenes/follow_camera.gd" id="2_l7nsy"]
|
||||
[ext_resource type="PackedScene" uid="uid://c5vbxqhevocy7" path="res://scenes/golf_tee.tscn" id="3_6q2yk"]
|
||||
[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")]
|
||||
process_callback = 0
|
||||
position_smoothing_enabled = true
|
||||
drag_vertical_enabled = true
|
||||
script = ExtResource("2_l7nsy")
|
||||
target = NodePath("../GolfBall")
|
||||
target = NodePath("")
|
||||
|
||||
[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="."]
|
||||
scale = Vector2(0.125, 0.125)
|
||||
|
@ -21,9 +32,3 @@ tile_set = ExtResource("1_h4d2b")
|
|||
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)
|
||||
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)
|
||||
|
|
|
@ -1,2 +1,46 @@
|
|||
extends Node2D
|
||||
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)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
[ext_resource type="TileSet" uid="uid://17esn8g8xqik" path="res://tiles/hole_tile_set.tres" id="1_uf2u7"]
|
||||
|
||||
[node name="TileMap" type="TileMap"]
|
||||
scale = Vector2(0.125, 0.125)
|
||||
tile_set = ExtResource("1_uf2u7")
|
||||
format = 2
|
||||
layer_0/name = "Walls"
|
||||
|
|
|
@ -1,74 +1,39 @@
|
|||
extends Node
|
||||
class_name LevelManager
|
||||
|
||||
## The levels that should be loaded by the server and sent to the clients.
|
||||
const levels: Array[PackedScene] = [
|
||||
preload("res://scenes/golf_level_1.tscn"),
|
||||
preload("res://scenes/golf_level_2.tscn"),
|
||||
]
|
||||
## The blank [GolfLevel] to initialize on clients.
|
||||
const base_scene: PackedScene = preload("res://scenes/golf_level.tscn")
|
||||
|
||||
## The index of the current level in [field levels].
|
||||
var level_idx: int = -1
|
||||
## The [LevelPlaylist] to use to load [GolfLevel]s from.
|
||||
@export var playlist: LevelPlaylist = null
|
||||
|
||||
## Class containing the components of a level.
|
||||
class Components:
|
||||
## 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 [PlayerNodeDirectory] to use to determine which players to spawn on clients.
|
||||
@export var player_dir: PlayerNodeDirectory = null
|
||||
|
||||
|
||||
|
||||
func get_current_level() -> PackedScene:
|
||||
return levels[level_idx]
|
||||
## The currently instantiated [GolfLevel].
|
||||
var level: GolfLevel = null
|
||||
|
||||
|
||||
func load_level_components() -> Components:
|
||||
return Components.from_scene(get_current_level())
|
||||
|
||||
## Create the empty [GolfLevel] object everywhere.
|
||||
@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()
|
||||
|
|
|
@ -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"]
|
||||
script = ExtResource("1_bv1lx")
|
||||
|
|
20
scenes/level_playlist.gd
Normal file
20
scenes/level_playlist.gd
Normal 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]
|
3
scenes/level_playlist.tscn
Normal file
3
scenes/level_playlist.tscn
Normal file
|
@ -0,0 +1,3 @@
|
|||
[gd_scene format=3 uid="uid://g03qgetpy6b5"]
|
||||
|
||||
[node name="LevelPlaylist" type="Node"]
|
|
@ -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"]
|
||||
script = ExtResource("1_k51gn")
|
||||
|
|
Loading…
Reference in a new issue