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/PersonalUI.gd" id="2_u54jc"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_5lewf"]
|
||||
|
||||
|
@ -16,3 +17,26 @@ margin = 0.5
|
|||
|
||||
[node name="Camera3D" type="Camera3D" parent="SpringArm3D"]
|
||||
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
|
||||
|
||||
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 safe_player: Player
|
||||
var game_tagger: Player
|
||||
|
||||
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_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_2 := "Game is starting soon, {tagger_username} is it!"
|
||||
const global_msg_3 := "{tagger_username} is it! Run!"
|
||||
const global_msg_4 := "{old_tagger_username} caught {tagger_username}!"
|
||||
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):
|
||||
if v and game_state == GameState.TAGGER_CHANGE:
|
||||
_change_state(GameState.TAGGER_GROUNDED)
|
||||
|
@ -40,12 +46,14 @@ func set_tagger_grounded(v: bool):
|
|||
|
||||
func not_enough_players() -> bool:
|
||||
if %Players.get_children().size() < MIN_PLAYERS:
|
||||
game_tagger = null
|
||||
_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 false
|
||||
|
||||
func change_to_random_tagger():
|
||||
safe_player = null
|
||||
game_tagger = %Players.get_children().pick_random()
|
||||
_change_state(GameState.TAGGER_CHANGE)
|
||||
|
||||
|
@ -55,19 +63,32 @@ func tagger_left_game():
|
|||
var old_tagger_username := game_tagger.username
|
||||
change_to_random_tagger()
|
||||
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,
|
||||
"tagger_username": tagger_username})
|
||||
"tagger_username": tagger_username}))
|
||||
|
||||
func set_tagger(who: Player):
|
||||
if game_state == GameState.WAITING:
|
||||
return
|
||||
game_tagger.tree_exiting.disconnect(tagger_left_game)
|
||||
who.tree_exiting.connect(tagger_left_game)
|
||||
safe_player = game_tagger
|
||||
game_tagger = who
|
||||
_change_state(GameState.TAGGER_CHANGE)
|
||||
|
||||
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:
|
||||
return
|
||||
if new_state == GameState.WAITING:
|
||||
|
@ -89,22 +110,66 @@ func _change_state(new_state: GameState):
|
|||
state_leave_tagger_ungrounded.emit()
|
||||
if old_state == GameState.TAGGER_CHANGE:
|
||||
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():
|
||||
# Hacky way to start level without going though multiplayer screens
|
||||
if get_parent() == get_tree().root:
|
||||
%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
|
||||
func server_add_player(id: int):
|
||||
%PlayerSpawner.spawn(id)
|
||||
|
||||
if not not_enough_players() and game_state == GameState.WAITING:
|
||||
start_game()
|
||||
|
||||
|
||||
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:
|
||||
while not (node is Level):
|
||||
node = node.get_parent()
|
||||
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="SceneReplicationConfig" id="SceneReplicationConfig_285vp"]
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_kefm0"]
|
||||
size = Vector3(6.87, 1, 1)
|
||||
|
||||
|
@ -95,6 +96,20 @@ shape = SubResource("BoxShape3D_m3lo5")
|
|||
|
||||
[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"]
|
||||
transform = Transform3D(1.5, 0, 0, 0, 3.2, 0, 0, 0, 10, 5.01694, 11.1202, -5.176)
|
||||
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
|
||||
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
|
||||
# Memory management substantially since nodes are not GC'd
|
||||
# Connected nodes are the colliding nodes
|
||||
signal is_bumping(src: Player)
|
||||
signal check_bumping(src: Player)
|
||||
var _is_grounded := false
|
||||
signal is_grounded
|
||||
signal check_grounded
|
||||
|
||||
func _ready():
|
||||
if username == "":
|
||||
|
@ -25,7 +36,7 @@ func _ready():
|
|||
|
||||
func is_on_ground() -> bool:
|
||||
_is_grounded = false
|
||||
is_grounded.emit(self)
|
||||
check_grounded.emit(self)
|
||||
var v := _is_grounded
|
||||
_is_grounded = false
|
||||
return v
|
||||
|
@ -55,7 +66,7 @@ func _bump_check(src: Player):
|
|||
|
||||
func get_first_bumper() -> Player:
|
||||
_first_bumper = null
|
||||
is_bumping.emit(self)
|
||||
check_bumping.emit(self)
|
||||
var player := _first_bumper
|
||||
_first_bumper = null
|
||||
return player
|
||||
|
@ -64,26 +75,26 @@ func _on_tag_detection_area_entered(area):
|
|||
if not (area.get_parent() is Player):
|
||||
return
|
||||
var _other_player: Player = area.get_parent()
|
||||
if is_bumping.is_connected(_bump_check):
|
||||
if check_bumping.is_connected(_bump_check):
|
||||
return
|
||||
is_bumping.connect(_bump_check)
|
||||
check_bumping.connect(_bump_check)
|
||||
|
||||
func _on_tag_detection_area_exited(area):
|
||||
if not (area.get_parent() is Player):
|
||||
return
|
||||
var _other_player: Player = area.get_parent()
|
||||
if not is_bumping.is_connected(_bump_check):
|
||||
if not check_bumping.is_connected(_bump_check):
|
||||
return
|
||||
is_bumping.disconnect(_bump_check)
|
||||
check_bumping.disconnect(_bump_check)
|
||||
|
||||
|
||||
func _on_tag_detection_body_entered(body):
|
||||
if "grounded" in body:
|
||||
if not is_grounded.is_connected(body.grounded):
|
||||
is_grounded.connect(body.grounded)
|
||||
if not check_grounded.is_connected(body.grounded):
|
||||
check_grounded.connect(body.grounded)
|
||||
|
||||
|
||||
func _on_tag_detection_body_exited(body):
|
||||
if "grounded" in body:
|
||||
if is_grounded.is_connected(body.grounded):
|
||||
is_grounded.disconnect(body.grounded)
|
||||
if check_grounded.is_connected(body.grounded):
|
||||
check_grounded.disconnect(body.grounded)
|
||||
|
|
Loading…
Reference in New Issue