Initial commit: Fighting_Rthythm_game project setup

This commit is contained in:
wxm
2026-07-01 06:59:12 -07:00
commit d7f118ae6e
291 changed files with 19614 additions and 0 deletions

40
tests/test_jump_height.gd Normal file
View File

@@ -0,0 +1,40 @@
extends SceneTree
const ORIGINAL_JUMP_INTENSITY := 430.0
const GRAVITY := 1200.0
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()
var jump_intensity: float = float(player.get("jump_intensity"))
var expected_height: float = _jump_height(ORIGINAL_JUMP_INTENSITY) * 0.5
var actual_height: float = _jump_height(jump_intensity)
if absf(actual_height - expected_height) > 0.01:
failures.append("jump height expected %.3f, got %.3f from jump_intensity %.3f" % [
expected_height,
actual_height,
jump_intensity,
])
player.free()
if failures.is_empty():
print("PASS jump height")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)
func _jump_height(jump_intensity: float) -> float:
return jump_intensity * jump_intensity / (2.0 * GRAVITY)

View File

@@ -0,0 +1 @@
uid://14lstjosx718

View File

@@ -0,0 +1,56 @@
extends SceneTree
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()
var sprite: Sprite2D = player.get_node("CharacterSprite") as Sprite2D
var collision: CollisionShape2D = player.get_node("CollisionShape2D") as CollisionShape2D
var camera: Camera2D = player.get_node("Camera2D") as Camera2D
var animation_player: AnimationPlayer = player.get_node("AnimationPlayer") as AnimationPlayer
_expect_vector((player as Node2D).scale, Vector2(4, 4), "Player root scale")
_expect_vector(sprite.scale, Vector2.ONE, "CharacterSprite local scale should keep anchor")
_expect_vector(sprite.offset, Vector2(-24, -40), "CharacterSprite visible foot offset")
_expect_vector(collision.scale, Vector2.ONE, "CollisionShape2D local scale should keep anchor")
_expect_vector(collision.position, Vector2(0, -18), "CollisionShape2D local position should keep anchor")
_expect_vector(camera.position, Vector2(0, -37.5), "Camera2D position should compensate player scale")
_expect_vector(camera.scale, Vector2(0.25, 0.25), "Camera2D scale should compensate player scale")
_expect_animation_offset(animation_player, "idle", Vector2(-24, -40))
_expect_animation_offset(animation_player, "jump", Vector2(-24, -44))
_expect_animation_offset(animation_player, "挥砍", Vector2(-40, -48))
player.free()
if failures.is_empty():
print("PASS player scale")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)
func _expect_vector(actual: Vector2, expected: Vector2, label: String) -> void:
if not actual.is_equal_approx(expected):
failures.append("%s: expected %s, got %s" % [label, expected, actual])
func _expect_animation_offset(animation_player: AnimationPlayer, animation_name: String, expected: Vector2) -> void:
var animation: Animation = animation_player.get_animation(animation_name)
if animation == null:
failures.append("Missing animation: %s" % animation_name)
return
for track_index: int in range(animation.get_track_count()):
if animation.track_get_path(track_index) == NodePath("CharacterSprite:offset"):
var actual: Vector2 = animation.track_get_key_value(track_index, 0)
_expect_vector(actual, expected, "%s CharacterSprite offset" % animation_name)
return
failures.append("Missing CharacterSprite offset track: %s" % animation_name)

View File

@@ -0,0 +1 @@
uid://di3givapw00bd

View File

@@ -0,0 +1,41 @@
extends SceneTree
var failures: Array[String] = []
func _init() -> void:
var conductor_script: Script = load("res://scenes/rhythm/rhythm_conductor.gd")
if conductor_script == null:
push_error("Could not load rhythm_conductor.gd")
quit(1)
return
var conductor: Node = conductor_script.new()
conductor.set("bpm", 120.0)
conductor.set("perfect_window", 0.060)
conductor.set("good_window", 0.120)
conductor.set("bad_window", 0.200)
conductor.set("beat_offset", 0.0)
conductor.call("_ready")
_expect_rating(conductor, 1.000, "perfect", "exact beat")
_expect_rating(conductor, 1.055, "perfect", "55ms from beat")
_expect_rating(conductor, 1.095, "good", "95ms from beat")
_expect_rating(conductor, 1.170, "bad", "170ms from beat")
_expect_rating(conductor, 1.240, "miss", "240ms from beat")
conductor.free()
if failures.is_empty():
print("PASS rhythm conductor")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)
func _expect_rating(conductor: Node, time_seconds: float, expected: String, label: String) -> void:
var rating: Dictionary = conductor.call("get_rating_for_time", time_seconds)
var actual: String = str(rating.get("label", ""))
if actual != expected:
failures.append("%s: expected %s, got %s" % [label, expected, actual])

View File

@@ -0,0 +1 @@
uid://cwovjddnrsl2o

View File

@@ -0,0 +1,42 @@
extends SceneTree
var failures: Array[String] = []
func _init() -> void:
var scene: PackedScene = load("res://scenes/main/main.tscn")
if scene == null:
push_error("Could not load main.tscn")
quit(1)
return
var main: Node = scene.instantiate()
if main.get_script() == null:
failures.append("Main script failed to load")
var required_nodes := [
"RhythmConductor",
"RhythmFeedback",
"Player",
]
for node_name: String in required_nodes:
if not main.has_node(node_name):
failures.append("Missing required node: %s" % node_name)
if main.has_node("RhythmConductor"):
var conductor: Node = main.get_node("RhythmConductor")
if not conductor.has_method("judge_action"):
failures.append("RhythmConductor missing judge_action")
if not conductor is AudioStreamPlayer:
failures.append("RhythmConductor should be an AudioStreamPlayer")
elif (conductor as AudioStreamPlayer).stream == null:
failures.append("RhythmConductor should have a music stream")
main.free()
if failures.is_empty():
print("PASS rhythm scene")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)

View File

@@ -0,0 +1 @@
uid://bmrcfsd34i24n

41
tests/test_rhythm_ui.gd Normal file
View File

@@ -0,0 +1,41 @@
extends SceneTree
var failures: Array[String] = []
func _init() -> void:
var scene: PackedScene = load("res://scenes/main/main.tscn")
if scene == null:
push_error("Could not load main.tscn")
quit(1)
return
var main: Node = scene.instantiate()
var required_nodes := [
"RhythmFeedback/RhythmTrack",
"RhythmFeedback/RhythmTrack/LeftRod",
"RhythmFeedback/RhythmTrack/RightRod",
"RhythmFeedback/RhythmTrack/CenterBase",
"RhythmFeedback/RhythmTrack/CenterFlash",
"RhythmFeedback/RhythmTrack/LeftMover",
"RhythmFeedback/RhythmTrack/RightMover",
"RhythmFeedback/RhythmTrack/BlueBallLeft1",
"RhythmFeedback/RhythmTrack/BlueBallRight1",
"RhythmFeedback/JudgementLabel",
]
for node_path: String in required_nodes:
if not main.has_node(node_path):
failures.append("Missing rhythm UI node: %s" % node_path)
if main.has_method("_update_rhythm_track") == false:
failures.append("Main script missing _update_rhythm_track")
main.free()
if failures.is_empty():
print("PASS rhythm ui")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)

View File

@@ -0,0 +1 @@
uid://b52hcjno3t4to

View File

@@ -0,0 +1,60 @@
extends SceneTree
var failures: Array[String] = []
func _init() -> void:
_run.call_deferred()
func _run() -> void:
var scene: PackedScene = load("res://scenes/main/main.tscn")
if scene == null:
push_error("Could not load main.tscn")
quit(1)
return
var main: Node = scene.instantiate()
var initial_left_mover: Control = main.get_node("RhythmFeedback/RhythmTrack/LeftMover")
var initial_right_mover: Control = main.get_node("RhythmFeedback/RhythmTrack/RightMover")
var initial_center_base: Control = main.get_node("RhythmFeedback/RhythmTrack/CenterBase")
var initial_center_flash: Control = main.get_node("RhythmFeedback/RhythmTrack/CenterFlash")
var expected_left_start := _control_center(initial_left_mover)
var expected_right_start := _control_center(initial_right_mover)
var expected_track_center := _control_center(initial_center_base)
var expected_mover_size := initial_left_mover.size
var expected_center_flash_size := initial_center_flash.size
root.add_child(main)
await process_frame
_expect_vector("left_mover_start", main.get("left_mover_start"), expected_left_start)
_expect_vector("right_mover_start", main.get("right_mover_start"), expected_right_start)
_expect_vector("track_center", main.get("track_center"), expected_track_center)
_expect_vector("mover_size", main.get("mover_size"), expected_mover_size)
_expect_vector("center_flash_size", main.get("center_flash_size"), expected_center_flash_size)
main.free()
if failures.is_empty():
print("PASS rhythm ui layout")
quit(0)
else:
for failure: String in failures:
push_error(failure)
quit(1)
func _control_center(control: Control) -> Vector2:
return Vector2(
(control.offset_left + control.offset_right) * 0.5,
(control.offset_top + control.offset_bottom) * 0.5
)
func _expect_vector(label: String, actual: Variant, expected: Vector2) -> void:
if not actual is Vector2:
failures.append("%s should be cached as Vector2, got %s" % [label, typeof(actual)])
return
if not (actual as Vector2).is_equal_approx(expected):
failures.append("%s should match scene layout: expected %s got %s" % [label, expected, actual])

View File

@@ -0,0 +1 @@
uid://bnkjqsfttot3m