From e9bc30fd13cee0106850163941c2ee744f88a4b4 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Sun, 14 Apr 2024 22:21:54 +0900 Subject: [PATCH] Work Game now reaches the end after the guardian battle. Work on parry system, battle system. --- DungeonEntrance.tscn | 30 ++++-- DungeonGuard.gd | 23 +++++ MainLogic.gd | 147 +++++++++++++++++++++++++++- audio/LD55_sfx_enemy_hit.mp3 | Bin 0 -> 56050 bytes audio/LD55_sfx_enemy_hit.mp3.import | 19 ++++ audio/LD55_sfx_parry.mp3 | Bin 0 -> 56050 bytes audio/LD55_sfx_parry.mp3.import | 19 ++++ gander_schwartz.gd | 136 ++++++++++++++++++++++++- gander_schwartz.tscn | 32 +++++- 9 files changed, 387 insertions(+), 19 deletions(-) create mode 100644 DungeonGuard.gd create mode 100644 audio/LD55_sfx_enemy_hit.mp3 create mode 100644 audio/LD55_sfx_enemy_hit.mp3.import create mode 100644 audio/LD55_sfx_parry.mp3 create mode 100644 audio/LD55_sfx_parry.mp3.import diff --git a/DungeonEntrance.tscn b/DungeonEntrance.tscn index 10dc03d..d7915b5 100644 --- a/DungeonEntrance.tscn +++ b/DungeonEntrance.tscn @@ -1,11 +1,14 @@ -[gd_scene load_steps=7 format=3 uid="uid://b55f770t7xs6a"] +[gd_scene load_steps=9 format=3 uid="uid://b55f770t7xs6a"] [ext_resource type="Texture2D" uid="uid://npjqgc3tdgs1" path="res://gimp/DungeonEntrance.png" id="1_vo6aq"] [ext_resource type="Texture2D" uid="uid://nocjsuuft8qx" path="res://gimp/DungeonGuard.png" id="2_nujkm"] +[ext_resource type="Script" path="res://DungeonGuard.gd" id="3_hisk5"] -[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_18p8i"] -radius = 15.0 -height = 32.0 +[sub_resource type="RectangleShape2D" id="RectangleShape2D_fey6x"] +size = Vector2(30.4094, 31.5789) + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_0v5y2"] +size = Vector2(30.4094, 31.5789) [sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_ocep5"] normal = Vector2(1, 0) @@ -35,13 +38,22 @@ texture_filter = 1 position = Vector2(0, -552) scale = Vector2(1.71, 1.71) texture = ExtResource("2_nujkm") +script = ExtResource("3_hisk5") -[node name="DungeonGuardStaticBody" type="StaticBody2D" parent="DungeonGuard"] -visible = false +[node name="DungeonGuardBody" type="StaticBody2D" parent="DungeonGuard"] -[node name="DungeonGuardCollider" type="CollisionShape2D" parent="DungeonGuard/DungeonGuardStaticBody"] -visible = false -shape = SubResource("CapsuleShape2D_18p8i") +[node name="DungeonGuardCollider" type="CollisionShape2D" parent="DungeonGuard/DungeonGuardBody"] +shape = SubResource("RectangleShape2D_fey6x") + +[node name="Area2D" type="Area2D" parent="DungeonGuard"] +collision_layer = 3 +collision_mask = 0 +input_pickable = false +monitoring = false + +[node name="CollisionShape2D" type="CollisionShape2D" parent="DungeonGuard/Area2D"] +shape = SubResource("RectangleShape2D_0v5y2") +debug_color = Color(0.643137, 0.341176, 0.988235, 0.419608) [node name="StaticBody2D" type="StaticBody2D" parent="."] diff --git a/DungeonGuard.gd b/DungeonGuard.gd new file mode 100644 index 0000000..68d84c4 --- /dev/null +++ b/DungeonGuard.gd @@ -0,0 +1,23 @@ +extends Sprite2D + +var health = 30 +var health_dirty = true + +# Called when the node enters the scene tree for the first time. +func _ready(): + pass # Replace with function body. + + +# Called every frame. 'delta' is the elapsed time since the previous frame. +func _process(delta): + if health_dirty: + health_dirty = false + var hp_label = find_child("GuardHPLabel") + if hp_label == null: + hp_label = Label.new() + hp_label.set_name(&"GuardHPLabel") + add_child(hp_label, true) + hp_label.set_owner(self) + hp_label.position.y += 20.0 + hp_label.position.x -= 20.0 + hp_label.text = "%d HP" % health diff --git a/MainLogic.gd b/MainLogic.gd index c9744b8..fafc75e 100644 --- a/MainLogic.gd +++ b/MainLogic.gd @@ -14,6 +14,10 @@ var sfx_select var sfx_confirm var sfx_cancel var sfx_summon +var sfx_enemy_hit +var sfx_parry +var sfx_sword_hit +var sfx_hammer_hit @onready var camera = $Camera2D @@ -36,6 +40,8 @@ const diamond_dist_rate = 50.0 const diamond_start_dist = 800.0 const diamond_min_dist = 150.0 +const parry_penalty = 0.5 + enum StateT { Start, Start_TextRendered, @@ -67,8 +73,17 @@ enum BattleState { SummonSword, SummonHammer, EnemyAttack, + PlayerAttack, + PlayerWin, + PlayerLose, } +enum GuardPhase { + Stomp, +} + +var guard_phase = GuardPhase.Stomp + static var state_dict = {} var tween_volume @@ -80,12 +95,17 @@ var diamonds_gone = false var gander var level +var level_guard_static_body = null var level_guard = null +var level_guard_cached_pos = null var level_cached_pos = null var viewport_size +var play_attack_sfx_type = null +var play_attack_sfx_once = false + # Called when the node enters the scene tree for the first time. func _ready(): if not state_dict.has("state"): @@ -106,6 +126,10 @@ func _ready(): sfx_confirm = load("res://audio/LD55_sfx_confirm.mp3") sfx_cancel = load("res://audio/LD55_sfx_cancel.mp3") sfx_summon = load("res://audio/LD55_sfx_summon.mp3") + sfx_enemy_hit = load("res://audio/LD55_sfx_enemy_hit.mp3") + sfx_parry = load("res://audio/LD55_sfx_parry.mp3") + sfx_sword_hit = load("res://audio/LD55_sfx_sword_hit.mp3") + sfx_hammer_hit = load("res://audio/LD55_sfx_hammer_hit.mp3") func update_text(text, next_state): if state_dict["timer"] > text_speed: @@ -144,6 +168,7 @@ func _process(delta): var gander_scene = preload("res://gander_schwartz.tscn") gander = gander_scene.instantiate() add_child(gander) + gander.set_owner(self) gander.position.x = 800 gander.position.y = 50 gander.velocity.x = -gander.SPEED @@ -206,13 +231,16 @@ func _process(delta): StateT.Dungeon_Entrance: camera_to_gander(delta) if level_guard == null: - level_guard = level.find_child("DungeonGuardStaticBody") - if level_guard != null and gander.last_collided_id == level_guard.get_instance_id(): + level_guard = level.find_child("DungeonGuard") + if level_guard_static_body == null: + level_guard_static_body = level.find_child("DungeonGuardBody") + if level_guard_static_body != null and gander.last_collided_id == level_guard_static_body.get_instance_id(): print("collided with guard.") gander.last_collided_id = null music_player.stop() music_player.stream = preload("res://audio/LD55_3.mp3") music_player.stream.loop = true + music_player.volume_db = -8.0 music_player.play() level.find_child("DungeonGuardCollider").set_deferred("disabled", true) gander.find_child("CollisionShape2D").set_deferred("disabled", true) @@ -229,6 +257,8 @@ func _process(delta): tween_scene.tween_callback(func(): gander.auto_control_action = "facing_left" state_dict["state"] = StateT.Dungeon_Entrance_Battle + state_dict["parry_timer"] = 0.0 + state_dict["parry_failed_played"] = false state_dict["battle_state"] = BattleState.MainMenu state_dict["battle_menu_setup"] = false state_dict["battle_refresh_gui"] = false @@ -247,10 +277,19 @@ func _process(delta): tween_text.tween_callback(func(): camera.remove_child(indicator_arrow) ) + gander.battle_started = true ) StateT.Dungeon_Entrance_Battle: + if state_dict["battle_state"] == BattleState.EnemyAttack: + if level_guard_cached_pos == null: + level_guard_cached_pos = level_guard.position camera_to_target(delta, level_cached_pos + Vector2(0.0, 500.0)) setup_battle_menu() + state_dict["parry_timer"] -= delta + if not gander.parry_success and gander.hit_active and not state_dict["parry_failed_played"]: + sfx_player.stream = sfx_enemy_hit + sfx_player.play() + state_dict["parry_failed_played"] = true _: pass if gander is MainCharacter and not gander.player_controlled and gander.current_scene_type == gander.GanderSceneT.Introduction: @@ -407,6 +446,25 @@ func camera_to_target(delta, vec2): camera.position += diff * delta * camera_move_speed func setup_battle_menu(): + if state_dict["battle_state"] != BattleState.PlayerWin and state_dict["battle_state"] != BattleState.PlayerLose: + if gander.health <= 0: + state_dict["battle_state"] = BattleState.PlayerLose + music_player.stop() + music_player.stream = load("res://audio/LD55_5.mp3") + music_player.play() + remove_child(gander) + main_label.text = "Thanks for playing! I ran out of time for this overly ambitious game..." + lower_label.text = "Ohhhh, it ended with a game over... Better luck next time?" + elif level_guard.health <= 0: + state_dict["battle_state"] = BattleState.PlayerWin + music_player.stop() + music_player.stream = load("res://audio/LD55_4.mp3") + music_player.play() + level_guard.get_parent().remove_child(level_guard) + main_label.text = "Thanks for playing! I ran out of time for this overly ambitious game..." + lower_label.text = "Good show, good show!" + elif state_dict["battle_state"] == BattleState.PlayerWin or state_dict["battle_state"] == BattleState.PlayerLose: + return match state_dict["battle_state"]: BattleState.MainMenu: if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]: @@ -477,7 +535,7 @@ func setup_battle_menu(): var summon_node = find_child("SummonAttempt") if summon_node.success_count >= summon_node.MAX_SUCCESS: camera.remove_child(summon_node) - var summon_item = find_child("SummonItem") + var summon_item = gander.find_child("SummonItem") if summon_item == null: summon_item = Sprite2D.new() summon_item.texture = load("res://gimp/sword.png") @@ -487,19 +545,26 @@ func setup_battle_menu(): else: summon_item.texture = load("res://gimp/sword.png") gander.summon_item = summon_item + state_dict["battle_item"] = summon_item + gander.attack_type = gander.AttackType.SWORD + gander.summon_item_summoned = true sfx_player.stream = sfx_summon sfx_player.play() state_dict["battle_state"] = BattleState.EnemyAttack + level_guard_cached_pos = null + pick_guard_phase() elif summon_node.error_count >= summon_node.MAX_ERRORS: tween_scene = get_tree().create_tween() tween_scene.tween_method(func(c): for i in range(8): summon_node.summon_arrows_arr[i].self_modulate = c, Color(1.0, 0.0, 0.0), Color(1.0, 0.0, 0.0, 0.0), 1.0) tween_scene.tween_callback(func(): camera.remove_child(summon_node)) state_dict["battle_state"] = BattleState.EnemyAttack + level_guard_cached_pos = null + pick_guard_phase() BattleState.SummonHammer: var summon_node = find_child("SummonAttempt") if summon_node.success_count >= summon_node.MAX_SUCCESS: camera.remove_child(summon_node) - var summon_item = find_child("SummonItem") + var summon_item = gander.find_child("SummonItem") if summon_item == null: summon_item = Sprite2D.new() summon_item.texture = load("res://gimp/hammer.png") @@ -509,27 +574,92 @@ func setup_battle_menu(): else: summon_item.texture = load("res://gimp/hammer.png") gander.summon_item = summon_item + state_dict["battle_item"] = summon_item + gander.attack_type = gander.AttackType.HAMMER + gander.summon_item_summoned = true sfx_player.stream = sfx_summon sfx_player.play() state_dict["battle_state"] = BattleState.EnemyAttack + level_guard_cached_pos = null + pick_guard_phase() elif summon_node.error_count >= summon_node.MAX_ERRORS: tween_scene = get_tree().create_tween() tween_scene.tween_method(func(c): for i in range(8): summon_node.summon_arrows_arr[i].self_modulate = c, Color(1.0, 0.0, 0.0), Color(1.0, 0.0, 0.0, 0.0), 1.0) tween_scene.tween_callback(func(): camera.remove_child(summon_node)) state_dict["battle_state"] = BattleState.EnemyAttack + level_guard_cached_pos = null + pick_guard_phase() BattleState.EnemyAttack: if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]: state_dict["battle_menu_setup"] = true state_dict["battle_refresh_gui"] = false + state_dict["parry_failed_played"] = false var battle_arrow = camera.find_child("BattleArrow") var battle_menu_item_0 = camera.find_child("BattleMenuItem0") var battle_menu_item_1 = camera.find_child("BattleMenuItem1") battle_arrow.self_modulate = Color(1, 1, 1, 0) battle_menu_item_0.text = "" battle_menu_item_1.text = "" + if gander.summon_item != null: + lower_label.text = "Press key-Z, button-A, or Spacebar at the right time to parry!" + match guard_phase: + GuardPhase.Stomp: + tween_scene = get_tree().create_tween() + var diff = gander.position.x - level_guard_cached_pos.x + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos + Vector2(diff / 2.0, -200.0), 1.0) + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos + Vector2(diff / 2.0, 0.0), 0.7) + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos + Vector2(diff, -200.0), 1.0) + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos + Vector2(diff, 0.0), 0.7) + tween_scene.tween_callback(func(): + state_dict["battle_state"] = BattleState.MainMenu + state_dict["battle_menu_setup"] = false + lower_label.text = "" + ) + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos, 1.0) + _: + state_dict["battle_state"] = BattleState.MainMenu + state_dict["battle_menu_setup"] = false + BattleState.PlayerAttack: + if gander.attack_target == null: + state_dict["battle_state"] = BattleState.EnemyAttack + state_dict["battle_menu_setup"] = false + play_attack_sfx_type = null + play_attack_sfx_once = false + elif not play_attack_sfx_once and play_attack_sfx_type != null: + var rng = RandomNumberGenerator.new() + if play_attack_sfx_type == "sword": + sfx_player.stream = sfx_sword_hit + sfx_player.play() + level_guard.health -= rng.randi_range(3, 4) + level_guard.health_dirty = true + elif play_attack_sfx_type == "hammer": + sfx_player.stream = sfx_hammer_hit + sfx_player.play() + level_guard.health -= rng.randi_range(2, 5) + level_guard.health_dirty = true + play_attack_sfx_type = null + play_attack_sfx_once = true func handle_battle_input(event: InputEvent): - if state_dict["battle_state"] == BattleState.SummonSword or state_dict["battle_state"] == BattleState.SummonHammer: + if state_dict["battle_state"] == BattleState.SummonSword or state_dict["battle_state"] == BattleState.SummonHammer \ + or state_dict["battle_state"] == BattleState.PlayerWin or state_dict["battle_state"] == BattleState.PlayerLose: + return + elif state_dict["battle_state"] == BattleState.EnemyAttack: + if event.is_pressed() and event.is_action("Confirm"): + if state_dict["parry_timer"] < 0.0 and gander.parry_active and not gander.hit_active and gander.summon_item != null: + lower_label.text = "Nice parry!" + gander.parry_success = true + sfx_player.stream = sfx_parry + sfx_player.play() + tween_scene.kill() + tween_scene = get_tree().create_tween() + tween_scene.tween_property(level_guard, "position", level_guard_cached_pos, 0.8) + tween_scene.tween_callback(func(): + state_dict["battle_state"] = BattleState.MainMenu + state_dict["battle_menu_setup"] = false + lower_label.text = "" + ) + state_dict["parry_timer"] = parry_penalty return if event.is_pressed(): if event.is_action("Down"): @@ -550,8 +680,12 @@ func handle_battle_input(event: InputEvent): func handle_battle_action(action): match action: "attack": + state_dict["battle_state"] = BattleState.PlayerAttack + state_dict["battle_menu_setup"] = false sfx_player.stream = sfx_confirm sfx_player.play() + if gander.summon_item != null: + gander.attack_target = level_guard "summon": state_dict["battle_state"] = BattleState.SummonMenu state_dict["battle_menu_setup"] = false @@ -592,3 +726,6 @@ func battle_arrow_positioning(): battle_arrow.position.y = (viewport_size.y + arrow_rect.size.y) / 2.0 - (arrow_rect.size.y * (state_dict["battle_options"].size() - state_dict["battle_selection"])) sfx_player.stream = sfx_select sfx_player.play() + +func pick_guard_phase(): + guard_phase = GuardPhase.Stomp diff --git a/audio/LD55_sfx_enemy_hit.mp3 b/audio/LD55_sfx_enemy_hit.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..6eddbc7959bafa71d9932ee89fe4f2da1b965260 GIT binary patch literal 56050 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 literal 0 HcmV?d00001 diff --git a/audio/LD55_sfx_enemy_hit.mp3.import b/audio/LD55_sfx_enemy_hit.mp3.import new file mode 100644 index 0000000..e3813a8 --- /dev/null +++ b/audio/LD55_sfx_enemy_hit.mp3.import @@ -0,0 +1,19 @@ +[remap] + +importer="mp3" +type="AudioStreamMP3" +uid="uid://bu34dnb7q3arr" +path="res://.godot/imported/LD55_sfx_enemy_hit.mp3-33970ec45349dad7d9a01186fd03e09a.mp3str" + +[deps] + +source_file="res://audio/LD55_sfx_enemy_hit.mp3" +dest_files=["res://.godot/imported/LD55_sfx_enemy_hit.mp3-33970ec45349dad7d9a01186fd03e09a.mp3str"] + +[params] + +loop=false +loop_offset=0 +bpm=0 +beat_count=0 +bar_beats=4 diff --git a/audio/LD55_sfx_parry.mp3 b/audio/LD55_sfx_parry.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ff066d6cdfc38de85d48d01f6e1f94df1c9a14bf GIT binary patch literal 56050 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 TAU: + summon_item_angle -= TAU + if summon_item != null and not parry_success: + summon_item.position.x = cos(-summon_item_angle) * SUMMON_ITEM_DIST + summon_item.position.y = sin(-summon_item_angle) * SUMMON_ITEM_DIST + SUMMON_ITEM_Y_OFFSET + elif parry_success and not parry_success_checked and parry_body != null: + parry_success_checked = true + parry_tween = get_tree().create_tween() + parry_tween.set_parallel() + parry_tween.set_trans(Tween.TRANS_SPRING) + var between = parry_body.get_parent().position - self.position + parry_tween.tween_property(summon_item, "position", between, 0.2) + parry_tween.set_trans(Tween.TRANS_EXPO) + parry_tween.tween_property(summon_item, "rotation", TAU * 10, 0.3) + parry_tween.set_parallel(false) + var old_x = cos(-summon_item_angle) * SUMMON_ITEM_DIST + var old_y = sin(-summon_item_angle) * SUMMON_ITEM_DIST + SUMMON_ITEM_Y_OFFSET + parry_tween.set_trans(Tween.TRANS_EXPO) + parry_tween.tween_property(summon_item, "position", Vector2(old_x, old_y), 0.4) + parry_tween.tween_callback(func(): + parry_tween = null + summon_item.rotation = 0.0 + ) + elif attack_target != null and summon_item != null: + attack_tween = get_tree().create_tween() + var prev_x = cos(-summon_item_angle) * SUMMON_ITEM_DIST + var prev_y = sin(-summon_item_angle) * SUMMON_ITEM_DIST + SUMMON_ITEM_Y_OFFSET + attack_tween.set_parallel() + attack_tween.tween_property(summon_item, "position", attack_target.position - self.position, 0.2) + attack_tween.tween_property(summon_item, "rotation", -PI / 2.0, 0.2) + attack_tween.set_parallel(false) + var parent = get_parent() + attack_tween.tween_callback(func(): + match attack_type: + AttackType.SWORD: + parent.play_attack_sfx_type = "sword" + AttackType.HAMMER: + parent.play_attack_sfx_type = "hammer" + ) + attack_tween.set_parallel() + attack_tween.tween_property(summon_item, "position", Vector2(prev_x, prev_y), 0.4) + attack_tween.tween_property(summon_item, "rotation", 0.0, 0.4) + attack_tween.set_parallel(false) + attack_tween.tween_callback(func(): + attack_target = null + ) + + if summon_item_summoned: + summon_item_summoned = false + var summon_overlay = Sprite2D.new() + summon_overlay.set_name(&"SummonOverlay") + summon_overlay.set_texture(summon_item.get_texture()) + add_child(summon_overlay, true) + summon_overlay.set_owner(self) + summon_overlay.set_scale(Vector2(5.0, 5.0)) + summon_overlay.self_modulate = Color(1.0, 1.0, 1.0, 0.4) + summon_tween = get_tree().create_tween() + summon_tween.set_parallel() + summon_tween.set_trans(Tween.TRANS_EXPO) + summon_tween.tween_property(summon_overlay, "rotation", -TAU * 50.0, 2.0) + summon_tween.set_trans(Tween.TRANS_QUAD) + summon_tween.tween_property(summon_overlay, "self_modulate", Color(1.0, 1.0, 1.0, 0.0), 2.0) + summon_tween.set_parallel(false) + summon_tween.tween_callback(func(): self.remove_child(summon_overlay)) + if health_dirty: + health_dirty = false + var hp_label = find_child("PlayerHPLabel") + if hp_label == null: + hp_label = Label.new() + hp_label.set_name(&"PlayerHPLabel") + add_child(hp_label, true) + hp_label.set_owner(self) + hp_label.position.y += 10.0 + hp_label.position.x -= 18.0 + hp_label.text = "%d HP" % health func _physics_process(delta): var vec2 = Vector2() diff --git a/gander_schwartz.tscn b/gander_schwartz.tscn index 4deb67f..f71ba98 100644 --- a/gander_schwartz.tscn +++ b/gander_schwartz.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=21 format=3 uid="uid://ktxqc7xtqkex"] +[gd_scene load_steps=23 format=3 uid="uid://ktxqc7xtqkex"] [ext_resource type="Script" path="res://gander_schwartz.gd" id="1_6ob4s"] [ext_resource type="Texture2D" uid="uid://cv0qw4j1q78r8" path="res://gimp/GanderSchwartz_spritesheet.png" id="1_n7bds"] @@ -162,6 +162,14 @@ animations = [{ radius = 15.0 height = 80.0 +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_sy0be"] +radius = 32.0 +height = 126.0 + +[sub_resource type="CapsuleShape2D" id="CapsuleShape2D_58op3"] +radius = 13.0 +height = 76.0 + [node name="GanderSchwartz" type="CharacterBody2D"] motion_mode = 1 script = ExtResource("1_6ob4s") @@ -178,3 +186,25 @@ frame_progress = 0.126405 [node name="CollisionShape2D" type="CollisionShape2D" parent="."] position = Vector2(0, -40) shape = SubResource("CapsuleShape2D_u3k2h") + +[node name="ParryArea2D" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 2 +input_pickable = false +monitorable = false + +[node name="CollisionShape2D" type="CollisionShape2D" parent="ParryArea2D"] +position = Vector2(0, -40) +shape = SubResource("CapsuleShape2D_sy0be") +debug_color = Color(0.631373, 0.352941, 0.984314, 0.419608) + +[node name="HitArea2D" type="Area2D" parent="."] +collision_layer = 4 +collision_mask = 2 +input_pickable = false +monitorable = false + +[node name="CollisionShape2D" type="CollisionShape2D" parent="HitArea2D"] +position = Vector2(0, -40) +shape = SubResource("CapsuleShape2D_58op3") +debug_color = Color(0.988235, 0, 0.290196, 0.419608)