Files
Fighting_Rthythm_game/tests/test_player_air_attack.gd
2026-07-02 05:46:33 -07:00

186 lines
8.2 KiB
GDScript

extends SceneTree
const WARRIOR_TEXTURE := "res://assets/art/characters/warrior_man_sheet.png"
const WARRIOR_WOMAN_TEXTURE := "res://assets/art/characters/warrior_woman_sheet.png"
const CHARGE_EFFECT_TEXTURE := "res://assets/art/effects/effect_hp_mp_sheet.png"
const EFFECT_TEXTURE := "res://assets/art/effects/effect_sheet.png"
const WARRIOR_COLUMNS := 16
const WARRIOR_ROWS := 25
var failures: Array[String] = []
func _init() -> void:
var scene: PackedScene = load("res://scenes/characters/player.tscn")
if scene == null:
push_error("Could not load player.tscn")
quit(1)
return
var player: Node = scene.instantiate()
get_root().add_child(player)
var animation_player: AnimationPlayer = player.get_node("AnimationPlayer") as AnimationPlayer
_expect_action_has_key("player_w", KEY_W)
_expect_action_has_key("player_a", KEY_A)
_expect_action_has_key("player_d", KEY_D)
_expect_action_has_key("player_s", KEY_S)
_expect_action_has_key("player_space", KEY_SPACE)
_expect_warrior_animation(animation_player, "warrior_idle", 1, 8)
_expect_warrior_animation(animation_player, "warrior_w", 6, 6)
_expect_warrior_animation(animation_player, "warrior_wa", 7, 5)
_expect_warrior_animation(animation_player, "warrior_s", 9, 10)
_expect_warrior_animation(animation_player, "warrior_a", 10, 7)
_expect_warrior_animation(animation_player, "warrior_aa", 11, 5)
_expect_warrior_animation(animation_player, "warrior_aaa", 12, 8)
_expect_warrior_animation(animation_player, "warrior_s_projectile", 14, 13)
_expect_warrior_animation(animation_player, "warrior_charge_intro", 13, 8, WARRIOR_WOMAN_TEXTURE)
_expect_warrior_animation(animation_player, "warrior_charge_loop", 13, 4, WARRIOR_WOMAN_TEXTURE, 4)
_expect_animation_loops(animation_player, "warrior_charge_loop")
_expect_warrior_animation(animation_player, "warrior_charge_release", 13, 8, WARRIOR_WOMAN_TEXTURE, 8)
_expect_warrior_animation(animation_player, "warrior_a_space_space", 15, 12)
_expect_warrior_animation(animation_player, "warrior_a_space", 17, 10)
_expect_charge_effect(player)
if animation_player.has_animation("player_punch"):
failures.append("Old player_punch animation should be removed")
if animation_player.has_animation("挥砍"):
failures.append("Old slash animation should be removed")
player.call("submit_combo_input", "W")
_expect_string(str(player.get("last_requested_skill_id")), "skill_w", "W alone should request row 6 skill")
_expect_string(str(player.get("current_skill_animation")), "warrior_w", "W alone should play warrior_w")
player.call("submit_combo_input", "A")
_expect_string(str(player.get("last_requested_skill_id")), "skill_wa", "W+A should request row 7 skill")
_expect_string(str(player.get("current_skill_animation")), "warrior_wa", "W+A should play warrior_wa")
var projectile := PlayerProjectile.new()
get_root().add_child(projectile)
_expect_projectile_animation(projectile)
projectile.queue_free()
player.queue_free()
_finish()
func _expect_action_has_key(action_name: String, key: Key) -> void:
if not InputMap.has_action(action_name):
failures.append("Missing input action: %s" % action_name)
return
for event: InputEvent in InputMap.action_get_events(action_name):
var key_event := event as InputEventKey
if key_event != null and (key_event.keycode == key or key_event.physical_keycode == key):
return
failures.append("Input action %s should be bound to key %s" % [action_name, OS.get_keycode_string(key)])
func _expect_warrior_animation(animation_player: AnimationPlayer, animation_name: String, row: int, expected_frames: int, texture_path := WARRIOR_TEXTURE, start_column := 0) -> void:
if not animation_player.has_animation(animation_name):
failures.append("Missing animation: %s" % animation_name)
return
var animation: Animation = animation_player.get_animation(animation_name)
var hframes_found := false
var vframes_found := false
var texture_found := false
var frame_values: Array[int] = []
for track_index: int in range(animation.get_track_count()):
var track_path := animation.track_get_path(track_index)
if track_path == NodePath("CharacterSprite:texture"):
var texture: Texture2D = animation.track_get_key_value(track_index, 0)
texture_found = texture != null and texture.resource_path == texture_path
elif track_path == NodePath("CharacterSprite:hframes"):
hframes_found = true
var hframes: int = animation.track_get_key_value(track_index, 0)
if hframes != WARRIOR_COLUMNS:
failures.append("%s hframes expected %d, got %d" % [animation_name, WARRIOR_COLUMNS, hframes])
elif track_path == NodePath("CharacterSprite:vframes"):
vframes_found = true
var vframes: int = animation.track_get_key_value(track_index, 0)
if vframes != WARRIOR_ROWS:
failures.append("%s vframes expected %d, got %d" % [animation_name, WARRIOR_ROWS, vframes])
elif track_path == NodePath("CharacterSprite:frame"):
for key_index: int in range(animation.track_get_key_count(track_index)):
frame_values.append(animation.track_get_key_value(track_index, key_index))
if not texture_found:
failures.append("%s should use %s" % [animation_name, texture_path])
if not hframes_found:
failures.append("Missing hframes track: %s" % animation_name)
if not vframes_found:
failures.append("Missing vframes track: %s" % animation_name)
if frame_values.size() != expected_frames:
failures.append("%s should key %d frames, got %d" % [animation_name, expected_frames, frame_values.size()])
var first_frame := (row - 1) * WARRIOR_COLUMNS + start_column
for index: int in range(frame_values.size()):
var expected := first_frame + index
if frame_values[index] != expected:
failures.append("%s frame %d expected sheet frame %d, got %d" % [
animation_name,
index,
expected,
frame_values[index],
])
func _expect_string(actual: String, expected: String, label: String) -> void:
if actual != expected:
failures.append("%s: expected %s, got %s" % [label, expected, actual])
func _expect_animation_loops(animation_player: AnimationPlayer, animation_name: String) -> void:
if not animation_player.has_animation(animation_name):
failures.append("Missing animation for loop check: %s" % animation_name)
return
var animation: Animation = animation_player.get_animation(animation_name)
if int(animation.loop_mode) != 1:
failures.append("%s should loop, got loop_mode %d" % [animation_name, int(animation.loop_mode)])
func _expect_projectile_animation(projectile: Node) -> void:
if projectile.get_child_count() == 0:
failures.append("Projectile should create a Sprite2D child")
return
var sprite := projectile.get_child(0) as Sprite2D
if sprite == null:
failures.append("Projectile child should be Sprite2D")
return
if sprite.texture == null or sprite.texture.resource_path != EFFECT_TEXTURE:
failures.append("Projectile should use %s" % EFFECT_TEXTURE)
if sprite.hframes != 6:
failures.append("Projectile hframes expected 6, got %d" % sprite.hframes)
if sprite.vframes != 2:
failures.append("Projectile vframes expected 2, got %d" % sprite.vframes)
projectile.call("_process", 0.0)
if sprite.frame != 0:
failures.append("Projectile first frame expected 0, got %d" % sprite.frame)
projectile.call("_process", 0.18)
if sprite.frame != 3:
failures.append("Projectile should use first row frame 3 after 0.18s, got %d" % sprite.frame)
func _expect_charge_effect(player: Node) -> void:
var sprite := player.get_node_or_null("ChargeEffectSprite") as Sprite2D
if sprite == null:
failures.append("Player should include ChargeEffectSprite")
return
if sprite.texture == null or sprite.texture.resource_path != CHARGE_EFFECT_TEXTURE:
failures.append("Charge effect should use %s" % CHARGE_EFFECT_TEXTURE)
if sprite.hframes != 5:
failures.append("Charge effect hframes expected 5, got %d" % sprite.hframes)
if sprite.vframes != 2:
failures.append("Charge effect vframes expected 2, got %d" % sprite.vframes)
if sprite.z_index < 1:
failures.append("Charge effect should draw above the player feet, got z_index %d" % sprite.z_index)
if sprite.visible:
failures.append("Charge effect should start hidden")
func _finish() -> void:
if failures.is_empty():
print("PASS player warrior actions")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)