Compare commits
2 Commits
c9edb73c50
...
00ff4fd9c5
Author | SHA1 | Date |
---|---|---|
Spencer Killen | 00ff4fd9c5 | |
Spencer Killen | c3e5073011 |
|
@ -0,0 +1,19 @@
|
||||||
|
extends Control
|
||||||
|
|
||||||
|
@onready var level := Level.find_level(self)
|
||||||
|
|
||||||
|
const personal_msg_1 := "You're not it, run!"
|
||||||
|
const personal_msg_2 := "You're it, run!"
|
||||||
|
|
||||||
|
func get_player() -> Player:
|
||||||
|
return owner.get_parent()
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
level.state_enter_tagger_change.connect(tagger_change)
|
||||||
|
|
||||||
|
func tagger_change(next: Player):
|
||||||
|
if get_player() == next:
|
||||||
|
$Label.text = personal_msg_2
|
||||||
|
else:
|
||||||
|
$Label.text = personal_msg_1
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
[gd_scene load_steps=3 format=3 uid="uid://brgqf2ebuyhuy"]
|
[gd_scene load_steps=4 format=3 uid="uid://brgqf2ebuyhuy"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://camera/camera.gd" id="1_veqr4"]
|
[ext_resource type="Script" path="res://camera/camera.gd" id="1_veqr4"]
|
||||||
|
[ext_resource type="Script" path="res://camera/PersonalUI.gd" id="2_u54jc"]
|
||||||
|
|
||||||
[sub_resource type="SphereShape3D" id="SphereShape3D_5lewf"]
|
[sub_resource type="SphereShape3D" id="SphereShape3D_5lewf"]
|
||||||
|
|
||||||
|
@ -16,3 +17,26 @@ margin = 0.5
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="SpringArm3D"]
|
[node name="Camera3D" type="Camera3D" parent="SpringArm3D"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
|
[node name="PersonalUI" type="Control" parent="."]
|
||||||
|
layout_mode = 3
|
||||||
|
anchors_preset = 12
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 1.0
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_top = -126.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 0
|
||||||
|
size_flags_vertical = 8
|
||||||
|
script = ExtResource("2_u54jc")
|
||||||
|
|
||||||
|
[node name="Label" type="Label" parent="PersonalUI"]
|
||||||
|
layout_mode = 1
|
||||||
|
anchors_preset = 5
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_right = 0.5
|
||||||
|
offset_left = -20.0
|
||||||
|
offset_right = 20.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
theme_override_colors/font_color = Color(1, 0, 0, 1)
|
||||||
|
|
|
@ -14,4 +14,6 @@ func spawn_player(owner_id: int):
|
||||||
return player
|
return player
|
||||||
|
|
||||||
func despawn_player(owner_id: int):
|
func despawn_player(owner_id: int):
|
||||||
get_node(spawn_path).get_node(str(owner_id)).queue_free()
|
var node := get_node(spawn_path).get_node(str(owner_id))
|
||||||
|
node.queue_free()
|
||||||
|
await node.tree_exited
|
||||||
|
|
|
@ -9,6 +9,7 @@ enum GameState {
|
||||||
}
|
}
|
||||||
|
|
||||||
var game_state: GameState = GameState.WAITING
|
var game_state: GameState = GameState.WAITING
|
||||||
|
var safe_player: Player
|
||||||
var game_tagger: Player
|
var game_tagger: Player
|
||||||
|
|
||||||
signal state_change(old: GameState, new: GameState)
|
signal state_change(old: GameState, new: GameState)
|
||||||
|
@ -19,13 +20,18 @@ signal state_leave_tagger_ungrounded
|
||||||
signal state_enter_tagger_change(new_tagger: Player)
|
signal state_enter_tagger_change(new_tagger: Player)
|
||||||
signal state_leave_tagger_change
|
signal state_leave_tagger_change
|
||||||
|
|
||||||
const MIN_PLAYERS := 2
|
const MIN_PLAYERS := 3
|
||||||
const global_msg_1 := "Waiting for at least {min_players} players to join"
|
const global_msg_1 := "Waiting for at least {min_players} players to join"
|
||||||
const global_msg_2 := "Game is starting soon, {tagger_username} is it!"
|
const global_msg_2 := "Game is starting soon, {tagger_username} is it!"
|
||||||
const global_msg_3 := "{tagger_username} is it! Run!"
|
const global_msg_3 := "{tagger_username} is it! Run!"
|
||||||
const global_msg_4 := "{old_tagger_username} caught {tagger_username}!"
|
const global_msg_4 := "{old_tagger_username} caught {tagger_username}!"
|
||||||
const global_msg_5 := "{old_tagger_username} left. {tagger_username} is now it!"
|
const global_msg_5 := "{old_tagger_username} left. {tagger_username} is now it!"
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable", "call_local")
|
||||||
|
func push_global_message(msg: String):
|
||||||
|
%GlobalMessage.text = msg
|
||||||
|
print(msg)
|
||||||
|
|
||||||
func set_tagger_grounded(v: bool):
|
func set_tagger_grounded(v: bool):
|
||||||
if v and game_state == GameState.TAGGER_CHANGE:
|
if v and game_state == GameState.TAGGER_CHANGE:
|
||||||
_change_state(GameState.TAGGER_GROUNDED)
|
_change_state(GameState.TAGGER_GROUNDED)
|
||||||
|
@ -40,12 +46,14 @@ func set_tagger_grounded(v: bool):
|
||||||
|
|
||||||
func not_enough_players() -> bool:
|
func not_enough_players() -> bool:
|
||||||
if %Players.get_children().size() < MIN_PLAYERS:
|
if %Players.get_children().size() < MIN_PLAYERS:
|
||||||
|
game_tagger = null
|
||||||
_change_state(GameState.WAITING)
|
_change_state(GameState.WAITING)
|
||||||
%GlobalMessage.text = global_msg_1.format({"min_players": MIN_PLAYERS})
|
push_global_message.rpc(global_msg_1.format({"min_players": MIN_PLAYERS}))
|
||||||
return true
|
return true
|
||||||
return false
|
return false
|
||||||
|
|
||||||
func change_to_random_tagger():
|
func change_to_random_tagger():
|
||||||
|
safe_player = null
|
||||||
game_tagger = %Players.get_children().pick_random()
|
game_tagger = %Players.get_children().pick_random()
|
||||||
_change_state(GameState.TAGGER_CHANGE)
|
_change_state(GameState.TAGGER_CHANGE)
|
||||||
|
|
||||||
|
@ -55,19 +63,32 @@ func tagger_left_game():
|
||||||
var old_tagger_username := game_tagger.username
|
var old_tagger_username := game_tagger.username
|
||||||
change_to_random_tagger()
|
change_to_random_tagger()
|
||||||
var tagger_username := game_tagger.username
|
var tagger_username := game_tagger.username
|
||||||
%GlobalMessage.text = global_msg_5.format({
|
push_global_message.rpc(global_msg_5.format({
|
||||||
"old_tagger_username": old_tagger_username,
|
"old_tagger_username": old_tagger_username,
|
||||||
"tagger_username": tagger_username})
|
"tagger_username": tagger_username}))
|
||||||
|
|
||||||
func set_tagger(who: Player):
|
func set_tagger(who: Player):
|
||||||
if game_state == GameState.WAITING:
|
safe_player = game_tagger
|
||||||
return
|
|
||||||
game_tagger.tree_exiting.disconnect(tagger_left_game)
|
|
||||||
who.tree_exiting.connect(tagger_left_game)
|
|
||||||
game_tagger = who
|
game_tagger = who
|
||||||
_change_state(GameState.TAGGER_CHANGE)
|
_change_state(GameState.TAGGER_CHANGE)
|
||||||
|
|
||||||
func _change_state(new_state: GameState):
|
func _change_state(new_state: GameState):
|
||||||
|
var id := -1
|
||||||
|
if game_tagger != null:
|
||||||
|
id = game_tagger.get_multiplayer_authority()
|
||||||
|
var safe_player_id := -1
|
||||||
|
if safe_player != null:
|
||||||
|
safe_player_id = safe_player.get_multiplayer_authority()
|
||||||
|
_change_state_full.rpc(new_state, id, safe_player_id)
|
||||||
|
|
||||||
|
@rpc("any_peer", "reliable", "call_local")
|
||||||
|
func _change_state_full(new_state: GameState, new_tagger_id: int, new_safe_player_id: int):
|
||||||
|
game_tagger = null
|
||||||
|
safe_player = null
|
||||||
|
if new_tagger_id != -1:
|
||||||
|
game_tagger = find_player_by_id(new_tagger_id)
|
||||||
|
if new_safe_player_id != -1:
|
||||||
|
safe_player = find_player_by_id(new_safe_player_id)
|
||||||
if game_state == new_state:
|
if game_state == new_state:
|
||||||
return
|
return
|
||||||
if new_state == GameState.WAITING:
|
if new_state == GameState.WAITING:
|
||||||
|
@ -89,22 +110,66 @@ func _change_state(new_state: GameState):
|
||||||
state_leave_tagger_ungrounded.emit()
|
state_leave_tagger_ungrounded.emit()
|
||||||
if old_state == GameState.TAGGER_CHANGE:
|
if old_state == GameState.TAGGER_CHANGE:
|
||||||
state_leave_tagger_change.emit()
|
state_leave_tagger_change.emit()
|
||||||
|
|
||||||
|
|
||||||
|
func tagging_possible(_tagger: Player, tagee: Player) -> bool:
|
||||||
|
if game_state != GameState.TAGGER_GROUNDED and game_state != GameState.TAGGER_UNGROUNDED:
|
||||||
|
return false
|
||||||
|
return safe_player != tagee
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
# Hacky way to start level without going though multiplayer screens
|
# Hacky way to start level without going though multiplayer screens
|
||||||
if get_parent() == get_tree().root:
|
if get_parent() == get_tree().root:
|
||||||
%PlayerSpawner.spawn(multiplayer.get_unique_id())
|
%PlayerSpawner.spawn(multiplayer.get_unique_id())
|
||||||
|
|
||||||
|
|
||||||
|
func player_ground(v: bool, player: Player):
|
||||||
|
if game_tagger == player:
|
||||||
|
set_tagger_grounded(v)
|
||||||
|
|
||||||
|
func player_tag(who: Player, player: Player):
|
||||||
|
if not tagging_possible(player, who) or game_tagger != player:
|
||||||
|
return
|
||||||
|
var old_tagger_username := game_tagger.username
|
||||||
|
var tagger_username := player.username
|
||||||
|
push_global_message.rpc(global_msg_4.format({
|
||||||
|
"old_tagger_username": old_tagger_username,
|
||||||
|
"tagger_username": tagger_username}))
|
||||||
|
set_tagger(who)
|
||||||
|
|
||||||
|
func start_game():
|
||||||
|
change_to_random_tagger()
|
||||||
|
push_global_message.rpc(global_msg_3.format({"tagger_username" : game_tagger.username}))
|
||||||
|
|
||||||
# Called from the server
|
# Called from the server
|
||||||
func server_add_player(id: int):
|
func server_add_player(id: int):
|
||||||
%PlayerSpawner.spawn(id)
|
%PlayerSpawner.spawn(id)
|
||||||
|
if not not_enough_players() and game_state == GameState.WAITING:
|
||||||
|
start_game()
|
||||||
|
|
||||||
|
|
||||||
func server_remove_player(id: int):
|
func server_remove_player(id: int):
|
||||||
%PlayerSpawner.despawn_player(id)
|
var player := find_player_by_id(id)
|
||||||
|
var tagger_left := (game_tagger == player)
|
||||||
|
await %PlayerSpawner.despawn_player(id)
|
||||||
|
if not_enough_players():
|
||||||
|
return
|
||||||
|
if tagger_left:
|
||||||
|
tagger_left_game()
|
||||||
|
|
||||||
|
func client_add_player(player: Player):
|
||||||
|
if not player.is_multiplayer_authority():
|
||||||
|
return
|
||||||
|
player.ground.connect(player_ground.bind(player))
|
||||||
|
player.tag.connect(player_tag.bind(player))
|
||||||
|
|
||||||
|
|
||||||
|
func client_remove_player(_node):
|
||||||
|
pass
|
||||||
|
|
||||||
static func find_level(node: Node) -> Level:
|
static func find_level(node: Node) -> Level:
|
||||||
while not (node is Level):
|
while not (node is Level):
|
||||||
node = node.get_parent()
|
node = node.get_parent()
|
||||||
return node
|
return node
|
||||||
|
|
||||||
|
func find_player_by_id(id: int) -> Player:
|
||||||
|
return %Players.get_node(str(id))
|
||||||
|
|
|
@ -20,6 +20,7 @@ size = Vector2(100, 100)
|
||||||
|
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_m3lo5"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_m3lo5"]
|
||||||
|
|
||||||
|
[sub_resource type="SceneReplicationConfig" id="SceneReplicationConfig_285vp"]
|
||||||
[sub_resource type="BoxShape3D" id="BoxShape3D_kefm0"]
|
[sub_resource type="BoxShape3D" id="BoxShape3D_kefm0"]
|
||||||
size = Vector3(6.87, 1, 1)
|
size = Vector3(6.87, 1, 1)
|
||||||
|
|
||||||
|
@ -95,6 +96,20 @@ shape = SubResource("BoxShape3D_m3lo5")
|
||||||
|
|
||||||
[node name="StaticBody3D" type="StaticBody3D" parent="." index="9"]
|
[node name="StaticBody3D" type="StaticBody3D" parent="." index="9"]
|
||||||
|
|
||||||
|
[node name="GlobalMessage" type="Label" parent="SharedUI" index="0"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
offset_right = 1152.0
|
||||||
|
offset_bottom = 23.0
|
||||||
|
theme_override_colors/font_color = Color(1, 0, 0, 1)
|
||||||
|
text = "Waiting for at least 2 players to join"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="." index="10"]
|
||||||
|
replication_config = SubResource("SceneReplicationConfig_285vp")
|
||||||
|
|
||||||
|
[connection signal="despawned" from="PlayerSpawner" to="." method="client_remove_player"]
|
||||||
|
[connection signal="spawned" from="PlayerSpawner" to="." method="client_add_player"]
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"]
|
||||||
transform = Transform3D(1.5, 0, 0, 0, 3.2, 0, 0, 0, 10, 5.01694, 11.1202, -5.176)
|
transform = Transform3D(1.5, 0, 0, 0, 3.2, 0, 0, 0, 10, 5.01694, 11.1202, -5.176)
|
||||||
shape = SubResource("BoxShape3D_kefm0")
|
shape = SubResource("BoxShape3D_kefm0")
|
||||||
|
|
|
@ -12,12 +12,23 @@ var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||||
# Set by camera child, switch to signals if becomes too spaghetti
|
# Set by camera child, switch to signals if becomes too spaghetti
|
||||||
var movement_dir: Vector2 = Vector2.ZERO
|
var movement_dir: Vector2 = Vector2.ZERO
|
||||||
|
|
||||||
|
|
||||||
|
# Signals fire continously every frame they're true
|
||||||
|
signal tag(player: Player)
|
||||||
|
signal ground(v: bool)
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
ground.emit(is_on_ground())
|
||||||
|
var player := get_first_bumper()
|
||||||
|
if player != null:
|
||||||
|
tag.emit(player)
|
||||||
|
|
||||||
# Using signals to maintain a list of currently colliding players because it simplifies
|
# Using signals to maintain a list of currently colliding players because it simplifies
|
||||||
# Memory management substantially since nodes are not GC'd
|
# Memory management substantially since nodes are not GC'd
|
||||||
# Connected nodes are the colliding nodes
|
# Connected nodes are the colliding nodes
|
||||||
signal is_bumping(src: Player)
|
signal check_bumping(src: Player)
|
||||||
var _is_grounded := false
|
var _is_grounded := false
|
||||||
signal is_grounded
|
signal check_grounded
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
if username == "":
|
if username == "":
|
||||||
|
@ -25,7 +36,7 @@ func _ready():
|
||||||
|
|
||||||
func is_on_ground() -> bool:
|
func is_on_ground() -> bool:
|
||||||
_is_grounded = false
|
_is_grounded = false
|
||||||
is_grounded.emit(self)
|
check_grounded.emit(self)
|
||||||
var v := _is_grounded
|
var v := _is_grounded
|
||||||
_is_grounded = false
|
_is_grounded = false
|
||||||
return v
|
return v
|
||||||
|
@ -55,7 +66,7 @@ func _bump_check(src: Player):
|
||||||
|
|
||||||
func get_first_bumper() -> Player:
|
func get_first_bumper() -> Player:
|
||||||
_first_bumper = null
|
_first_bumper = null
|
||||||
is_bumping.emit(self)
|
check_bumping.emit(self)
|
||||||
var player := _first_bumper
|
var player := _first_bumper
|
||||||
_first_bumper = null
|
_first_bumper = null
|
||||||
return player
|
return player
|
||||||
|
@ -64,26 +75,26 @@ func _on_tag_detection_area_entered(area):
|
||||||
if not (area.get_parent() is Player):
|
if not (area.get_parent() is Player):
|
||||||
return
|
return
|
||||||
var _other_player: Player = area.get_parent()
|
var _other_player: Player = area.get_parent()
|
||||||
if is_bumping.is_connected(_bump_check):
|
if check_bumping.is_connected(_bump_check):
|
||||||
return
|
return
|
||||||
is_bumping.connect(_bump_check)
|
check_bumping.connect(_bump_check)
|
||||||
|
|
||||||
func _on_tag_detection_area_exited(area):
|
func _on_tag_detection_area_exited(area):
|
||||||
if not (area.get_parent() is Player):
|
if not (area.get_parent() is Player):
|
||||||
return
|
return
|
||||||
var _other_player: Player = area.get_parent()
|
var _other_player: Player = area.get_parent()
|
||||||
if not is_bumping.is_connected(_bump_check):
|
if not check_bumping.is_connected(_bump_check):
|
||||||
return
|
return
|
||||||
is_bumping.disconnect(_bump_check)
|
check_bumping.disconnect(_bump_check)
|
||||||
|
|
||||||
|
|
||||||
func _on_tag_detection_body_entered(body):
|
func _on_tag_detection_body_entered(body):
|
||||||
if "grounded" in body:
|
if "grounded" in body:
|
||||||
if not is_grounded.is_connected(body.grounded):
|
if not check_grounded.is_connected(body.grounded):
|
||||||
is_grounded.connect(body.grounded)
|
check_grounded.connect(body.grounded)
|
||||||
|
|
||||||
|
|
||||||
func _on_tag_detection_body_exited(body):
|
func _on_tag_detection_body_exited(body):
|
||||||
if "grounded" in body:
|
if "grounded" in body:
|
||||||
if is_grounded.is_connected(body.grounded):
|
if check_grounded.is_connected(body.grounded):
|
||||||
is_grounded.disconnect(body.grounded)
|
check_grounded.disconnect(body.grounded)
|
||||||
|
|
Loading…
Reference in New Issue