From a9dad02fb9209c0903cb2133511268ed6d202036 Mon Sep 17 00:00:00 2001 From: Spencer Killen Date: Fri, 31 May 2024 11:59:57 -0600 Subject: [PATCH] partial tagging system --- level/StaticBody3D.gd | 4 +++ level/level.gd | 67 +++++++++++++++++++++++++++++++++++++ level/level.tscn | 6 ++-- player/player.gd | 57 +++++++++++++++++++++++++++++++ player/player.tscn | 17 +++++++++- project.godot | 1 - server/MultiplayerEvents.gd | 2 -- 7 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 level/StaticBody3D.gd delete mode 100644 server/MultiplayerEvents.gd diff --git a/level/StaticBody3D.gd b/level/StaticBody3D.gd new file mode 100644 index 0000000..4533590 --- /dev/null +++ b/level/StaticBody3D.gd @@ -0,0 +1,4 @@ +extends StaticBody3D + +func grounded(src: Player): + src._is_grounded = true diff --git a/level/level.gd b/level/level.gd index 636cf57..2f74c9f 100644 --- a/level/level.gd +++ b/level/level.gd @@ -1,4 +1,65 @@ extends Node3D +class_name Level + +enum GameState { + WAITING, # Stop state to be used by default, nothing should react to this + TAGGER_GROUNDED, # Tagger is on the ground + TAGGER_UNGROUNDED, # Tagger is off the ground + TAGGER_CHANGE, # Tagger has caught someone, and new person must go to ground +} + +var game_state: GameState = GameState.WAITING +var game_tagger: Player + +signal state_change(old: GameState, new: GameState) +signal state_enter_tagger_grounded +signal state_leave_tagger_grounded +signal state_enter_tagger_ungrounded +signal state_leave_tagger_ungrounded +signal state_enter_tagger_change(new_tagger: Player) +signal state_leave_tagger_change + +func set_tagger_grounded(v: bool): + if v and game_state == GameState.TAGGER_CHANGE: + _change_state(GameState.TAGGER_GROUNDED) + return + if not (game_state == GameState.TAGGER_GROUNDED or game_state == GameState.TAGGER_UNGROUNDED): + return + if (not v) and game_state == GameState.TAGGER_GROUNDED: + _change_state(GameState.TAGGER_UNGROUNDED) + if v and game_state == GameState.TAGGER_UNGROUNDED: + _change_state(GameState.TAGGER_GROUNDED) + +func set_tagger(who: Player): + if game_state == GameState.WAITING: + return + game_tagger = who + _change_state(GameState.TAGGER_CHANGE) + +func _change_state(new_state: GameState): + if game_state == new_state: + return + if new_state == GameState.WAITING: + game_tagger = null + state_change.emit(game_state, new_state) + if new_state == GameState.TAGGER_GROUNDED: + state_enter_tagger_grounded.emit() + if new_state == GameState.TAGGER_UNGROUNDED: + state_enter_tagger_ungrounded.emit() + if new_state == GameState.TAGGER_CHANGE: + state_enter_tagger_change.emit(game_tagger) + + var old_state = game_state + game_state = new_state + + if old_state == GameState.TAGGER_GROUNDED: + state_leave_tagger_grounded.emit() + if old_state == GameState.TAGGER_UNGROUNDED: + state_leave_tagger_ungrounded.emit() + if old_state == GameState.TAGGER_CHANGE: + state_leave_tagger_change.emit() + + func _ready(): # Hacky way to start level without going though multiplayer screens @@ -8,3 +69,9 @@ func _ready(): # Called from the server func server_add_player(id: int): %PlayerSpawner.spawn(id) + +static func find_level(node: Node) -> Level: + var parent := node + while not (node is Level): + node = node.get_parent() + return node diff --git a/level/level.tscn b/level/level.tscn index 7f0187c..470a8b5 100644 --- a/level/level.tscn +++ b/level/level.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=9 format=3 uid="uid://b00brfkibo5cj"] +[gd_scene load_steps=10 format=3 uid="uid://b00brfkibo5cj"] [ext_resource type="PackedScene" uid="uid://bq654gwim6col" path="res://level/level.glb" id="1_s37in"] [ext_resource type="Environment" uid="uid://covjrwmk4rplw" path="res://level/world_environment.tres" id="2_ptkl6"] [ext_resource type="Script" path="res://level/level.gd" id="2_s1bx6"] +[ext_resource type="Script" path="res://level/StaticBody3D.gd" id="4_6rwm2"] [ext_resource type="Script" path="res://addons/smoother/smoother.gd" id="5_2tyle"] [ext_resource type="Script" path="res://level/PlayerSpawner.gd" id="6_7ww0m"] [ext_resource type="MeshLibrary" uid="uid://cgh6y5j8wgi36" path="res://level/mesh_library/level_mesh_library.glb" id="6_d34iv"] @@ -22,7 +23,8 @@ environment = ExtResource("2_ptkl6") [node name="DirectionalLight3D" type="DirectionalLight3D" parent="WorldEnvironment" index="0"] transform = Transform3D(1, 0, 0, 0, 0.566018, 0.824393, 0, -0.824393, 0.566018, 0, 13.4573, 0) -[node name="StaticBody3D" type="StaticBody3D" parent="Plane" index="0"] +[node name="StaticBody3D" type="StaticBody3D" parent="Plane" index="0" groups=["ground"]] +script = ExtResource("4_6rwm2") [node name="CollisionShape3D" type="CollisionShape3D" parent="Plane/StaticBody3D" index="0"] transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0) diff --git a/player/player.gd b/player/player.gd index fb03c80..87c3616 100644 --- a/player/player.gd +++ b/player/player.gd @@ -1,6 +1,7 @@ # Automatically Generated From Builtin CharacterBody Template extends CharacterBody3D +class_name Player @export var SPEED = 5.0 @export var JUMP_VELOCITY = 4.5 @@ -10,6 +11,21 @@ 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 +# 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) +var _is_grounded := false +signal is_grounded + +func is_on_ground() -> bool: + _is_grounded = false + is_grounded.emit() + var v := _is_grounded + _is_grounded = false + return v + + func _physics_process(delta): if not is_on_floor(): velocity.y -= gravity * delta @@ -25,3 +41,44 @@ func _physics_process(delta): velocity.z = move_toward(velocity.z, 0, SPEED) move_and_slide() + +var _first_bumper: Player = null + +func _bump_check(src: Player): + if src._first_bumper == null: + src._first_bumper = self + +func get_first_bumper() -> Player: + _first_bumper = null + is_bumping.emit(self) + var player := _first_bumper + _first_bumper = null + return player + +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): + return + is_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): + return + is_bumping.disconnect(_bump_check) + + +func _on_tag_detection_body_entered(body): + if body.is_in_group("ground"): + if not is_grounded.is_connected(body.grounded): + is_grounded.connect(body.grounded) + + +func _on_tag_detection_body_exited(body): + if body.is_in_group("ground"): + if is_grounded.is_connected(body.grounded): + is_grounded.disconnect(body.grounded) diff --git a/player/player.tscn b/player/player.tscn index 42d7e11..8a88c08 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=5 format=3 uid="uid://do25xvpy80iio"] +[gd_scene load_steps=6 format=3 uid="uid://do25xvpy80iio"] [ext_resource type="PackedScene" uid="uid://bwg2jkbq7gada" path="res://player/player.glb" id="1_0u2un"] [ext_resource type="Script" path="res://player/player.gd" id="1_gh340"] @@ -11,6 +11,9 @@ properties/0/replication_mode = 1 [sub_resource type="SphereShape3D" id="SphereShape3D_t1htn"] radius = 0.986757 +[sub_resource type="SphereShape3D" id="SphereShape3D_ylark"] +radius = 1.0605 + [node name="player" instance=ExtResource("1_0u2un")] floor_max_angle = 1.32121 script = ExtResource("1_gh340") @@ -21,3 +24,15 @@ replication_config = SubResource("SceneReplicationConfig_u4bmc") [node name="CollisionShape3D" type="CollisionShape3D" parent="." index="2"] shape = SubResource("SphereShape3D_t1htn") + +[node name="TagDetection" type="Area3D" parent="." index="3"] +collision_layer = 8388608 +collision_mask = 8388608 + +[node name="CollisionShape3D" type="CollisionShape3D" parent="TagDetection" index="0"] +shape = SubResource("SphereShape3D_ylark") + +[connection signal="area_entered" from="TagDetection" to="." method="_on_tag_detection_area_entered"] +[connection signal="area_exited" from="TagDetection" to="." method="_on_tag_detection_area_exited"] +[connection signal="body_entered" from="TagDetection" to="." method="_on_tag_detection_body_entered"] +[connection signal="body_exited" from="TagDetection" to="." method="_on_tag_detection_body_exited"] diff --git a/project.godot b/project.godot index 31e6bd1..d3ad153 100644 --- a/project.godot +++ b/project.godot @@ -35,7 +35,6 @@ config/icon="res://icon.svg" [autoload] -MultiplayerEvents="*res://server/MultiplayerEvents.gd" FmodManager="*res://addons/fmod/FmodManager.gd" [editor_plugins] diff --git a/server/MultiplayerEvents.gd b/server/MultiplayerEvents.gd deleted file mode 100644 index 487b284..0000000 --- a/server/MultiplayerEvents.gd +++ /dev/null @@ -1,2 +0,0 @@ -extends Node -