Work
Game now reaches the end after the guardian battle. Work on parry system, battle system.
This commit is contained in:
parent
d4809bd78d
commit
e9bc30fd13
9 changed files with 387 additions and 19 deletions
|
@ -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://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="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"]
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_fey6x"]
|
||||||
radius = 15.0
|
size = Vector2(30.4094, 31.5789)
|
||||||
height = 32.0
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_0v5y2"]
|
||||||
|
size = Vector2(30.4094, 31.5789)
|
||||||
|
|
||||||
[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_ocep5"]
|
[sub_resource type="WorldBoundaryShape2D" id="WorldBoundaryShape2D_ocep5"]
|
||||||
normal = Vector2(1, 0)
|
normal = Vector2(1, 0)
|
||||||
|
@ -35,13 +38,22 @@ texture_filter = 1
|
||||||
position = Vector2(0, -552)
|
position = Vector2(0, -552)
|
||||||
scale = Vector2(1.71, 1.71)
|
scale = Vector2(1.71, 1.71)
|
||||||
texture = ExtResource("2_nujkm")
|
texture = ExtResource("2_nujkm")
|
||||||
|
script = ExtResource("3_hisk5")
|
||||||
|
|
||||||
[node name="DungeonGuardStaticBody" type="StaticBody2D" parent="DungeonGuard"]
|
[node name="DungeonGuardBody" type="StaticBody2D" parent="DungeonGuard"]
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="DungeonGuardCollider" type="CollisionShape2D" parent="DungeonGuard/DungeonGuardStaticBody"]
|
[node name="DungeonGuardCollider" type="CollisionShape2D" parent="DungeonGuard/DungeonGuardBody"]
|
||||||
visible = false
|
shape = SubResource("RectangleShape2D_fey6x")
|
||||||
shape = SubResource("CapsuleShape2D_18p8i")
|
|
||||||
|
[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="."]
|
[node name="StaticBody2D" type="StaticBody2D" parent="."]
|
||||||
|
|
||||||
|
|
23
DungeonGuard.gd
Normal file
23
DungeonGuard.gd
Normal file
|
@ -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
|
147
MainLogic.gd
147
MainLogic.gd
|
@ -14,6 +14,10 @@ var sfx_select
|
||||||
var sfx_confirm
|
var sfx_confirm
|
||||||
var sfx_cancel
|
var sfx_cancel
|
||||||
var sfx_summon
|
var sfx_summon
|
||||||
|
var sfx_enemy_hit
|
||||||
|
var sfx_parry
|
||||||
|
var sfx_sword_hit
|
||||||
|
var sfx_hammer_hit
|
||||||
|
|
||||||
@onready var camera = $Camera2D
|
@onready var camera = $Camera2D
|
||||||
|
|
||||||
|
@ -36,6 +40,8 @@ const diamond_dist_rate = 50.0
|
||||||
const diamond_start_dist = 800.0
|
const diamond_start_dist = 800.0
|
||||||
const diamond_min_dist = 150.0
|
const diamond_min_dist = 150.0
|
||||||
|
|
||||||
|
const parry_penalty = 0.5
|
||||||
|
|
||||||
enum StateT {
|
enum StateT {
|
||||||
Start,
|
Start,
|
||||||
Start_TextRendered,
|
Start_TextRendered,
|
||||||
|
@ -67,8 +73,17 @@ enum BattleState {
|
||||||
SummonSword,
|
SummonSword,
|
||||||
SummonHammer,
|
SummonHammer,
|
||||||
EnemyAttack,
|
EnemyAttack,
|
||||||
|
PlayerAttack,
|
||||||
|
PlayerWin,
|
||||||
|
PlayerLose,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GuardPhase {
|
||||||
|
Stomp,
|
||||||
|
}
|
||||||
|
|
||||||
|
var guard_phase = GuardPhase.Stomp
|
||||||
|
|
||||||
static var state_dict = {}
|
static var state_dict = {}
|
||||||
|
|
||||||
var tween_volume
|
var tween_volume
|
||||||
|
@ -80,12 +95,17 @@ var diamonds_gone = false
|
||||||
var gander
|
var gander
|
||||||
|
|
||||||
var level
|
var level
|
||||||
|
var level_guard_static_body = null
|
||||||
var level_guard = null
|
var level_guard = null
|
||||||
|
var level_guard_cached_pos = null
|
||||||
|
|
||||||
var level_cached_pos = null
|
var level_cached_pos = null
|
||||||
|
|
||||||
var viewport_size
|
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.
|
# Called when the node enters the scene tree for the first time.
|
||||||
func _ready():
|
func _ready():
|
||||||
if not state_dict.has("state"):
|
if not state_dict.has("state"):
|
||||||
|
@ -106,6 +126,10 @@ func _ready():
|
||||||
sfx_confirm = load("res://audio/LD55_sfx_confirm.mp3")
|
sfx_confirm = load("res://audio/LD55_sfx_confirm.mp3")
|
||||||
sfx_cancel = load("res://audio/LD55_sfx_cancel.mp3")
|
sfx_cancel = load("res://audio/LD55_sfx_cancel.mp3")
|
||||||
sfx_summon = load("res://audio/LD55_sfx_summon.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):
|
func update_text(text, next_state):
|
||||||
if state_dict["timer"] > text_speed:
|
if state_dict["timer"] > text_speed:
|
||||||
|
@ -144,6 +168,7 @@ func _process(delta):
|
||||||
var gander_scene = preload("res://gander_schwartz.tscn")
|
var gander_scene = preload("res://gander_schwartz.tscn")
|
||||||
gander = gander_scene.instantiate()
|
gander = gander_scene.instantiate()
|
||||||
add_child(gander)
|
add_child(gander)
|
||||||
|
gander.set_owner(self)
|
||||||
gander.position.x = 800
|
gander.position.x = 800
|
||||||
gander.position.y = 50
|
gander.position.y = 50
|
||||||
gander.velocity.x = -gander.SPEED
|
gander.velocity.x = -gander.SPEED
|
||||||
|
@ -206,13 +231,16 @@ func _process(delta):
|
||||||
StateT.Dungeon_Entrance:
|
StateT.Dungeon_Entrance:
|
||||||
camera_to_gander(delta)
|
camera_to_gander(delta)
|
||||||
if level_guard == null:
|
if level_guard == null:
|
||||||
level_guard = level.find_child("DungeonGuardStaticBody")
|
level_guard = level.find_child("DungeonGuard")
|
||||||
if level_guard != null and gander.last_collided_id == level_guard.get_instance_id():
|
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.")
|
print("collided with guard.")
|
||||||
gander.last_collided_id = null
|
gander.last_collided_id = null
|
||||||
music_player.stop()
|
music_player.stop()
|
||||||
music_player.stream = preload("res://audio/LD55_3.mp3")
|
music_player.stream = preload("res://audio/LD55_3.mp3")
|
||||||
music_player.stream.loop = true
|
music_player.stream.loop = true
|
||||||
|
music_player.volume_db = -8.0
|
||||||
music_player.play()
|
music_player.play()
|
||||||
level.find_child("DungeonGuardCollider").set_deferred("disabled", true)
|
level.find_child("DungeonGuardCollider").set_deferred("disabled", true)
|
||||||
gander.find_child("CollisionShape2D").set_deferred("disabled", true)
|
gander.find_child("CollisionShape2D").set_deferred("disabled", true)
|
||||||
|
@ -229,6 +257,8 @@ func _process(delta):
|
||||||
tween_scene.tween_callback(func():
|
tween_scene.tween_callback(func():
|
||||||
gander.auto_control_action = "facing_left"
|
gander.auto_control_action = "facing_left"
|
||||||
state_dict["state"] = StateT.Dungeon_Entrance_Battle
|
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_state"] = BattleState.MainMenu
|
||||||
state_dict["battle_menu_setup"] = false
|
state_dict["battle_menu_setup"] = false
|
||||||
state_dict["battle_refresh_gui"] = false
|
state_dict["battle_refresh_gui"] = false
|
||||||
|
@ -247,10 +277,19 @@ func _process(delta):
|
||||||
tween_text.tween_callback(func():
|
tween_text.tween_callback(func():
|
||||||
camera.remove_child(indicator_arrow)
|
camera.remove_child(indicator_arrow)
|
||||||
)
|
)
|
||||||
|
gander.battle_started = true
|
||||||
)
|
)
|
||||||
StateT.Dungeon_Entrance_Battle:
|
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))
|
camera_to_target(delta, level_cached_pos + Vector2(0.0, 500.0))
|
||||||
setup_battle_menu()
|
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
|
pass
|
||||||
if gander is MainCharacter and not gander.player_controlled and gander.current_scene_type == gander.GanderSceneT.Introduction:
|
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
|
camera.position += diff * delta * camera_move_speed
|
||||||
|
|
||||||
func setup_battle_menu():
|
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"]:
|
match state_dict["battle_state"]:
|
||||||
BattleState.MainMenu:
|
BattleState.MainMenu:
|
||||||
if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]:
|
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")
|
var summon_node = find_child("SummonAttempt")
|
||||||
if summon_node.success_count >= summon_node.MAX_SUCCESS:
|
if summon_node.success_count >= summon_node.MAX_SUCCESS:
|
||||||
camera.remove_child(summon_node)
|
camera.remove_child(summon_node)
|
||||||
var summon_item = find_child("SummonItem")
|
var summon_item = gander.find_child("SummonItem")
|
||||||
if summon_item == null:
|
if summon_item == null:
|
||||||
summon_item = Sprite2D.new()
|
summon_item = Sprite2D.new()
|
||||||
summon_item.texture = load("res://gimp/sword.png")
|
summon_item.texture = load("res://gimp/sword.png")
|
||||||
|
@ -487,19 +545,26 @@ func setup_battle_menu():
|
||||||
else:
|
else:
|
||||||
summon_item.texture = load("res://gimp/sword.png")
|
summon_item.texture = load("res://gimp/sword.png")
|
||||||
gander.summon_item = summon_item
|
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.stream = sfx_summon
|
||||||
sfx_player.play()
|
sfx_player.play()
|
||||||
state_dict["battle_state"] = BattleState.EnemyAttack
|
state_dict["battle_state"] = BattleState.EnemyAttack
|
||||||
|
level_guard_cached_pos = null
|
||||||
|
pick_guard_phase()
|
||||||
elif summon_node.error_count >= summon_node.MAX_ERRORS:
|
elif summon_node.error_count >= summon_node.MAX_ERRORS:
|
||||||
tween_scene = get_tree().create_tween()
|
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_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))
|
tween_scene.tween_callback(func(): camera.remove_child(summon_node))
|
||||||
state_dict["battle_state"] = BattleState.EnemyAttack
|
state_dict["battle_state"] = BattleState.EnemyAttack
|
||||||
|
level_guard_cached_pos = null
|
||||||
|
pick_guard_phase()
|
||||||
BattleState.SummonHammer:
|
BattleState.SummonHammer:
|
||||||
var summon_node = find_child("SummonAttempt")
|
var summon_node = find_child("SummonAttempt")
|
||||||
if summon_node.success_count >= summon_node.MAX_SUCCESS:
|
if summon_node.success_count >= summon_node.MAX_SUCCESS:
|
||||||
camera.remove_child(summon_node)
|
camera.remove_child(summon_node)
|
||||||
var summon_item = find_child("SummonItem")
|
var summon_item = gander.find_child("SummonItem")
|
||||||
if summon_item == null:
|
if summon_item == null:
|
||||||
summon_item = Sprite2D.new()
|
summon_item = Sprite2D.new()
|
||||||
summon_item.texture = load("res://gimp/hammer.png")
|
summon_item.texture = load("res://gimp/hammer.png")
|
||||||
|
@ -509,27 +574,92 @@ func setup_battle_menu():
|
||||||
else:
|
else:
|
||||||
summon_item.texture = load("res://gimp/hammer.png")
|
summon_item.texture = load("res://gimp/hammer.png")
|
||||||
gander.summon_item = summon_item
|
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.stream = sfx_summon
|
||||||
sfx_player.play()
|
sfx_player.play()
|
||||||
state_dict["battle_state"] = BattleState.EnemyAttack
|
state_dict["battle_state"] = BattleState.EnemyAttack
|
||||||
|
level_guard_cached_pos = null
|
||||||
|
pick_guard_phase()
|
||||||
elif summon_node.error_count >= summon_node.MAX_ERRORS:
|
elif summon_node.error_count >= summon_node.MAX_ERRORS:
|
||||||
tween_scene = get_tree().create_tween()
|
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_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))
|
tween_scene.tween_callback(func(): camera.remove_child(summon_node))
|
||||||
state_dict["battle_state"] = BattleState.EnemyAttack
|
state_dict["battle_state"] = BattleState.EnemyAttack
|
||||||
|
level_guard_cached_pos = null
|
||||||
|
pick_guard_phase()
|
||||||
BattleState.EnemyAttack:
|
BattleState.EnemyAttack:
|
||||||
if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]:
|
if not state_dict["battle_menu_setup"] or state_dict["battle_refresh_gui"]:
|
||||||
state_dict["battle_menu_setup"] = true
|
state_dict["battle_menu_setup"] = true
|
||||||
state_dict["battle_refresh_gui"] = false
|
state_dict["battle_refresh_gui"] = false
|
||||||
|
state_dict["parry_failed_played"] = false
|
||||||
var battle_arrow = camera.find_child("BattleArrow")
|
var battle_arrow = camera.find_child("BattleArrow")
|
||||||
var battle_menu_item_0 = camera.find_child("BattleMenuItem0")
|
var battle_menu_item_0 = camera.find_child("BattleMenuItem0")
|
||||||
var battle_menu_item_1 = camera.find_child("BattleMenuItem1")
|
var battle_menu_item_1 = camera.find_child("BattleMenuItem1")
|
||||||
battle_arrow.self_modulate = Color(1, 1, 1, 0)
|
battle_arrow.self_modulate = Color(1, 1, 1, 0)
|
||||||
battle_menu_item_0.text = ""
|
battle_menu_item_0.text = ""
|
||||||
battle_menu_item_1.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):
|
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
|
return
|
||||||
if event.is_pressed():
|
if event.is_pressed():
|
||||||
if event.is_action("Down"):
|
if event.is_action("Down"):
|
||||||
|
@ -550,8 +680,12 @@ func handle_battle_input(event: InputEvent):
|
||||||
func handle_battle_action(action):
|
func handle_battle_action(action):
|
||||||
match action:
|
match action:
|
||||||
"attack":
|
"attack":
|
||||||
|
state_dict["battle_state"] = BattleState.PlayerAttack
|
||||||
|
state_dict["battle_menu_setup"] = false
|
||||||
sfx_player.stream = sfx_confirm
|
sfx_player.stream = sfx_confirm
|
||||||
sfx_player.play()
|
sfx_player.play()
|
||||||
|
if gander.summon_item != null:
|
||||||
|
gander.attack_target = level_guard
|
||||||
"summon":
|
"summon":
|
||||||
state_dict["battle_state"] = BattleState.SummonMenu
|
state_dict["battle_state"] = BattleState.SummonMenu
|
||||||
state_dict["battle_menu_setup"] = false
|
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"]))
|
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.stream = sfx_select
|
||||||
sfx_player.play()
|
sfx_player.play()
|
||||||
|
|
||||||
|
func pick_guard_phase():
|
||||||
|
guard_phase = GuardPhase.Stomp
|
||||||
|
|
BIN
audio/LD55_sfx_enemy_hit.mp3
Normal file
BIN
audio/LD55_sfx_enemy_hit.mp3
Normal file
Binary file not shown.
19
audio/LD55_sfx_enemy_hit.mp3.import
Normal file
19
audio/LD55_sfx_enemy_hit.mp3.import
Normal file
|
@ -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
|
BIN
audio/LD55_sfx_parry.mp3
Normal file
BIN
audio/LD55_sfx_parry.mp3
Normal file
Binary file not shown.
19
audio/LD55_sfx_parry.mp3.import
Normal file
19
audio/LD55_sfx_parry.mp3.import
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="mp3"
|
||||||
|
type="AudioStreamMP3"
|
||||||
|
uid="uid://cnumagq6o3qxj"
|
||||||
|
path="res://.godot/imported/LD55_sfx_parry.mp3-7a46deb538aa1e0147d4915f42b03709.mp3str"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://audio/LD55_sfx_parry.mp3"
|
||||||
|
dest_files=["res://.godot/imported/LD55_sfx_parry.mp3-7a46deb538aa1e0147d4915f42b03709.mp3str"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
loop=false
|
||||||
|
loop_offset=0
|
||||||
|
bpm=0
|
||||||
|
beat_count=0
|
||||||
|
bar_beats=4
|
|
@ -13,21 +13,149 @@ var auto_control_action = "facing_front"
|
||||||
|
|
||||||
var last_collided_id = null
|
var last_collided_id = null
|
||||||
|
|
||||||
|
@onready var parry_area = $ParryArea2D
|
||||||
|
@onready var hit_area = $HitArea2D
|
||||||
|
|
||||||
@onready var animated = $AnimatedSprite2D
|
@onready var animated = $AnimatedSprite2D
|
||||||
|
|
||||||
|
var battle_started = false
|
||||||
|
|
||||||
|
var health = 30
|
||||||
|
var health_dirty = true
|
||||||
|
|
||||||
var summon_item = null
|
var summon_item = null
|
||||||
var summon_item_angle = 0.0
|
var summon_item_angle = 0.0
|
||||||
|
var summon_item_summoned = false
|
||||||
|
var summon_tween
|
||||||
|
|
||||||
|
var parry_tween = null
|
||||||
|
|
||||||
|
var parry_active = false
|
||||||
|
var parry_body = null
|
||||||
|
var hit_active = false
|
||||||
|
var parry_success = false
|
||||||
|
var parry_success_checked = false
|
||||||
|
|
||||||
|
enum AttackType {
|
||||||
|
SWORD,
|
||||||
|
HAMMER,
|
||||||
|
}
|
||||||
|
|
||||||
|
var attack_target = null
|
||||||
|
var attack_tween = null
|
||||||
|
var attack_type = AttackType.SWORD
|
||||||
|
|
||||||
const SPEED = 150.0
|
const SPEED = 150.0
|
||||||
const ANIM_DEADZONE = 0.3
|
const ANIM_DEADZONE = 0.3
|
||||||
const SUMMON_ITEM_DIST = 100.0
|
const SUMMON_ITEM_DIST = 100.0
|
||||||
const SUMMON_ITEM_Y_OFFSET = -30.0
|
const SUMMON_ITEM_Y_OFFSET = -30.0
|
||||||
|
|
||||||
|
func parry_entered(node):
|
||||||
|
parry_active = true
|
||||||
|
parry_success_checked = false
|
||||||
|
parry_body = node
|
||||||
|
func parry_exited(node):
|
||||||
|
parry_active = false
|
||||||
|
parry_body = null
|
||||||
|
if battle_started:
|
||||||
|
if parry_success:
|
||||||
|
print("Successful parry")
|
||||||
|
parry_success = false
|
||||||
|
else:
|
||||||
|
print("Failed to parry")
|
||||||
|
var rng = RandomNumberGenerator.new()
|
||||||
|
health -= rng.randi_range(1, 5)
|
||||||
|
health_dirty = true
|
||||||
|
|
||||||
|
func hit_entered(node):
|
||||||
|
hit_active = true
|
||||||
|
func hit_exited(node):
|
||||||
|
hit_active = false
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
parry_area.area_entered.connect(parry_entered)
|
||||||
|
parry_area.area_exited.connect(parry_exited)
|
||||||
|
hit_area.area_entered.connect(hit_entered)
|
||||||
|
hit_area.area_exited.connect(hit_exited)
|
||||||
|
|
||||||
func _process(delta):
|
func _process(delta):
|
||||||
|
if parry_tween == null and attack_target == null:
|
||||||
summon_item_angle += delta
|
summon_item_angle += delta
|
||||||
if summon_item != null:
|
if summon_item_angle > TAU:
|
||||||
summon_item.position.x = cos(summon_item_angle) * SUMMON_ITEM_DIST
|
summon_item_angle -= TAU
|
||||||
summon_item.position.y = sin(summon_item_angle) * SUMMON_ITEM_DIST + SUMMON_ITEM_Y_OFFSET
|
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):
|
func _physics_process(delta):
|
||||||
var vec2 = Vector2()
|
var vec2 = Vector2()
|
||||||
|
|
|
@ -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="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"]
|
[ext_resource type="Texture2D" uid="uid://cv0qw4j1q78r8" path="res://gimp/GanderSchwartz_spritesheet.png" id="1_n7bds"]
|
||||||
|
@ -162,6 +162,14 @@ animations = [{
|
||||||
radius = 15.0
|
radius = 15.0
|
||||||
height = 80.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"]
|
[node name="GanderSchwartz" type="CharacterBody2D"]
|
||||||
motion_mode = 1
|
motion_mode = 1
|
||||||
script = ExtResource("1_6ob4s")
|
script = ExtResource("1_6ob4s")
|
||||||
|
@ -178,3 +186,25 @@ frame_progress = 0.126405
|
||||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
position = Vector2(0, -40)
|
position = Vector2(0, -40)
|
||||||
shape = SubResource("CapsuleShape2D_u3k2h")
|
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)
|
||||||
|
|
Loading…
Reference in a new issue