Add combat combo gameplay
This commit is contained in:
@@ -8,18 +8,22 @@ const GRAVITY := 1200.0
|
||||
@export var attack_duration := 0.4
|
||||
@export var attack_lunge_duration := 0.18
|
||||
@export var attack_lunge_speed := 220.0
|
||||
@export var air_attack_duration := 0.45
|
||||
@export var air_attack_lunge_duration := 0.22
|
||||
@export var air_attack_lunge_speed := 260.0
|
||||
|
||||
@onready var animation_player: AnimationPlayer = $AnimationPlayer
|
||||
@onready var character_sprite: Sprite2D = $CharacterSprite
|
||||
|
||||
enum State { IDLE, WALK, JUMP, LAND, ATTACK }
|
||||
enum State { IDLE, WALK, JUMP, LAND, ATTACK, AIR_ATTACK }
|
||||
|
||||
var anim_map := {
|
||||
State.IDLE: "idle",
|
||||
State.WALK: "idle",
|
||||
State.JUMP: "jump",
|
||||
State.LAND: "idle",
|
||||
State.ATTACK: "挥砍",
|
||||
State.IDLE: "warrior_idle",
|
||||
State.WALK: "warrior_idle",
|
||||
State.JUMP: "warrior_w",
|
||||
State.LAND: "warrior_idle",
|
||||
State.ATTACK: "warrior_a",
|
||||
State.AIR_ATTACK: "warrior_a",
|
||||
}
|
||||
var attack_direction := Vector2.RIGHT
|
||||
var attack_lunge_time_left := 0.0
|
||||
@@ -55,7 +59,7 @@ func handle_air_time(delta: float) -> void:
|
||||
height_speed -= GRAVITY * delta
|
||||
|
||||
func handle_attack_time(delta: float) -> void:
|
||||
if state != State.ATTACK:
|
||||
if state != State.ATTACK and state != State.AIR_ATTACK:
|
||||
return
|
||||
velocity.y = 0.0
|
||||
attack_time_left -= delta
|
||||
@@ -68,7 +72,7 @@ func handle_attack_time(delta: float) -> void:
|
||||
velocity.x = 0.0
|
||||
|
||||
func handle_movement() -> void:
|
||||
if state == State.JUMP or state == State.ATTACK:
|
||||
if state == State.JUMP or state == State.ATTACK or state == State.AIR_ATTACK:
|
||||
return
|
||||
if absf(velocity.x) > 0.0:
|
||||
state = State.WALK
|
||||
@@ -97,6 +101,9 @@ func can_jump() -> bool:
|
||||
func can_attack() -> bool:
|
||||
return state == State.IDLE or state == State.WALK
|
||||
|
||||
func can_air_attack() -> bool:
|
||||
return state == State.IDLE or state == State.WALK
|
||||
|
||||
func start_jump() -> void:
|
||||
state = State.JUMP
|
||||
height_speed = jump_intensity
|
||||
@@ -112,3 +119,15 @@ func start_directional_attack(direction: Vector2) -> void:
|
||||
attack_time_left = attack_duration
|
||||
attack_lunge_time_left = attack_lunge_duration
|
||||
velocity = Vector2(attack_x * attack_lunge_speed, 0.0)
|
||||
|
||||
func start_air_attack() -> void:
|
||||
start_directional_air_attack(heading)
|
||||
|
||||
func start_directional_air_attack(direction: Vector2) -> void:
|
||||
var attack_x := -1.0 if direction.x < 0.0 else 1.0
|
||||
attack_direction = Vector2(attack_x, 0.0)
|
||||
heading = Vector2.RIGHT if attack_x > 0.0 else Vector2.LEFT
|
||||
state = State.AIR_ATTACK
|
||||
attack_time_left = air_attack_duration
|
||||
attack_lunge_time_left = air_attack_lunge_duration
|
||||
velocity = Vector2(attack_x * air_attack_lunge_speed, 0.0)
|
||||
|
||||
@@ -1,23 +1,106 @@
|
||||
class_name Player
|
||||
extends Character
|
||||
|
||||
signal combo_window_changed(slots: Array)
|
||||
signal combo_window_cleared(reason: String)
|
||||
signal charge_changed(current: float, maximum: float, ready: bool, active: bool)
|
||||
signal energy_changed(current: int, maximum: int)
|
||||
signal health_changed(current: int, maximum: int)
|
||||
signal skill_requested(skill_id: String)
|
||||
|
||||
@export var combo_clear_display_time := 0.35
|
||||
@export var charge_duration := 1.1
|
||||
@export var max_health := 100
|
||||
@export var current_health := 100
|
||||
@export var max_energy := 10
|
||||
@export var current_energy := 0
|
||||
|
||||
var combo_window := ComboWindow.new()
|
||||
var last_requested_skill_id := ""
|
||||
var current_skill_animation := ""
|
||||
var combo_clear_timer: Timer
|
||||
var charge_value := 0.0
|
||||
var charge_ready := false
|
||||
var charge_active := false
|
||||
var _pending_combo_clear_reason := ""
|
||||
var _charge_effect_time := 0.0
|
||||
var _charge_hold_symbol := ""
|
||||
var _charge_hold_direction := Vector2.ZERO
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
combo_clear_timer = Timer.new()
|
||||
combo_clear_timer.one_shot = true
|
||||
combo_clear_timer.wait_time = combo_clear_display_time
|
||||
combo_clear_timer.timeout.connect(flush_pending_combo_clear)
|
||||
add_child(combo_clear_timer)
|
||||
combo_window.window_cleared.connect(_on_combo_window_cleared)
|
||||
_emit_combo_window_changed()
|
||||
_emit_charge_changed()
|
||||
_emit_health_changed()
|
||||
_emit_energy_changed()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_update_charge(delta)
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if _handle_combo_key_event(event):
|
||||
_mark_input_handled()
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _handle_combo_key_event(event):
|
||||
_mark_input_handled()
|
||||
|
||||
|
||||
func _handle_combo_key_event(event: InputEvent) -> bool:
|
||||
var key_event := event as InputEventKey
|
||||
if key_event == null or key_event.echo:
|
||||
return false
|
||||
if not key_event.pressed:
|
||||
if _event_matches_key(key_event, KEY_A):
|
||||
_finish_charge_hold("A")
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_D):
|
||||
_finish_charge_hold("D")
|
||||
return true
|
||||
return false
|
||||
if _event_matches_key(key_event, KEY_W):
|
||||
_submit_combo_input_from_event("W")
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_A):
|
||||
heading = Vector2.LEFT
|
||||
var skill_id := _submit_combo_input_from_event("A")
|
||||
if skill_id == "skill_a":
|
||||
_begin_charge_hold("A", Vector2.LEFT)
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_D):
|
||||
heading = Vector2.RIGHT
|
||||
var skill_id := _submit_combo_input_from_event("D")
|
||||
if skill_id == "skill_d":
|
||||
_begin_charge_hold("D", Vector2.RIGHT)
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_S):
|
||||
_submit_combo_input_from_event("S")
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_SPACE):
|
||||
_submit_combo_input_from_event("SP")
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func handle_input() -> void:
|
||||
if Input.is_action_just_pressed("ui_left"):
|
||||
judge_rhythm_action("left")
|
||||
if can_attack():
|
||||
start_directional_attack(Vector2.LEFT)
|
||||
return
|
||||
if Input.is_action_just_pressed("ui_right"):
|
||||
judge_rhythm_action("right")
|
||||
if can_attack():
|
||||
start_directional_attack(Vector2.RIGHT)
|
||||
if charge_active:
|
||||
velocity = Vector2.ZERO
|
||||
return
|
||||
_apply_horizontal_movement()
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
judge_rhythm_action("jump")
|
||||
if can_jump():
|
||||
start_jump()
|
||||
if state == State.IDLE or state == State.WALK:
|
||||
velocity.x = 0.0
|
||||
|
||||
|
||||
func set_heading() -> void:
|
||||
if velocity.x > 0.0:
|
||||
@@ -25,7 +108,407 @@ func set_heading() -> void:
|
||||
elif velocity.x < 0.0:
|
||||
heading = Vector2.LEFT
|
||||
|
||||
func judge_rhythm_action(action_name: String) -> void:
|
||||
|
||||
func get_combo_slots() -> Array[String]:
|
||||
return combo_window.get_slots()
|
||||
|
||||
|
||||
func get_energy() -> int:
|
||||
return current_energy
|
||||
|
||||
|
||||
func get_max_energy() -> int:
|
||||
return max_energy
|
||||
|
||||
|
||||
func get_health() -> int:
|
||||
return current_health
|
||||
|
||||
|
||||
func get_max_health() -> int:
|
||||
return max_health
|
||||
|
||||
|
||||
func get_charge() -> float:
|
||||
return charge_value
|
||||
|
||||
|
||||
func get_max_charge() -> float:
|
||||
return charge_duration
|
||||
|
||||
|
||||
func is_charge_active() -> bool:
|
||||
return charge_active
|
||||
|
||||
|
||||
func is_charge_ready() -> bool:
|
||||
return charge_ready
|
||||
|
||||
|
||||
func submit_combo_input(symbol: String, forced_rating := "") -> String:
|
||||
match symbol:
|
||||
"W":
|
||||
return _record_combo_symbol("W", "w", forced_rating)
|
||||
"A":
|
||||
return _record_combo_symbol("A", "a", forced_rating)
|
||||
"D":
|
||||
return _record_combo_symbol("D", "d", forced_rating)
|
||||
"S":
|
||||
return _record_combo_symbol("S", "s", forced_rating)
|
||||
"SP":
|
||||
return _record_combo_symbol("SP", "space", forced_rating)
|
||||
return ""
|
||||
|
||||
|
||||
func _record_combo_symbol(symbol: String, rhythm_action: String, forced_rating := "") -> String:
|
||||
var rating := _rating_or_forced(judge_rhythm_action(rhythm_action), forced_rating)
|
||||
_apply_energy_reward(str(rating.get("label", "perfect")))
|
||||
if not _record_rated_combo_input(symbol, rating):
|
||||
if symbol == "A" or symbol == "D":
|
||||
_cancel_missed_direction_action()
|
||||
return ""
|
||||
var resolved := InputResolver.resolve(combo_window)
|
||||
if resolved.is_empty() and _pending_combo_clear_reason == "full":
|
||||
resolved = _resolve_full_window_fallback(symbol)
|
||||
if not resolved.is_empty():
|
||||
if not _execute_combo_skill(resolved):
|
||||
return ""
|
||||
if symbol == "SP" and not _is_projectile_space_chain() and _pending_combo_clear_reason.is_empty():
|
||||
_schedule_combo_clear("space")
|
||||
return last_requested_skill_id if not resolved.is_empty() else ""
|
||||
|
||||
|
||||
func _submit_combo_input_from_event(symbol: String) -> String:
|
||||
return submit_combo_input(symbol)
|
||||
|
||||
|
||||
func _event_matches_key(event: InputEventKey, key: Key) -> bool:
|
||||
return event.physical_keycode == key or event.keycode == key
|
||||
|
||||
|
||||
func _event_matches_any_key(event: InputEventKey, keys: Array[Key]) -> bool:
|
||||
for key: Key in keys:
|
||||
if _event_matches_key(event, key):
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _mark_input_handled() -> void:
|
||||
var viewport := get_viewport()
|
||||
if viewport != null:
|
||||
viewport.set_input_as_handled()
|
||||
|
||||
|
||||
func _record_combo_direction(symbol: String, direction: Vector2, rhythm_action: String, forced_rating := "") -> void:
|
||||
heading = direction
|
||||
var rating := _rating_or_forced(judge_rhythm_action(rhythm_action), forced_rating)
|
||||
_record_rated_combo_input(symbol, rating)
|
||||
if state == State.IDLE or state == State.WALK:
|
||||
velocity.x = 0.0
|
||||
|
||||
|
||||
func _record_rated_combo_input(symbol: String, rating: Dictionary) -> bool:
|
||||
if str(rating.get("label", "perfect")) == "miss":
|
||||
_record_combo_input("Ø")
|
||||
return false
|
||||
_record_combo_input(symbol)
|
||||
return true
|
||||
|
||||
|
||||
func _record_combo_input(symbol: String) -> void:
|
||||
if combo_window.has_pending_clear() or not _pending_combo_clear_reason.is_empty():
|
||||
if _pending_combo_clear_reason.begins_with("skill:") and not combo_window.has_pending_clear():
|
||||
_cancel_pending_combo_clear()
|
||||
else:
|
||||
flush_pending_combo_clear()
|
||||
combo_window.record(symbol)
|
||||
_emit_combo_window_changed()
|
||||
var reason := combo_window.consume_pending_clear_reason()
|
||||
if not reason.is_empty():
|
||||
_schedule_combo_clear(reason)
|
||||
|
||||
|
||||
func _rating_or_forced(rating: Dictionary, forced_rating: String) -> Dictionary:
|
||||
if forced_rating.is_empty():
|
||||
return rating
|
||||
var forced := rating.duplicate()
|
||||
forced["label"] = forced_rating
|
||||
return forced
|
||||
|
||||
|
||||
func _execute_combo_skill(skill: Dictionary) -> bool:
|
||||
if not _spend_skill_energy(skill):
|
||||
return false
|
||||
last_requested_skill_id = str(skill.get("id", ""))
|
||||
current_skill_animation = str(skill.get("animation", "warrior_idle"))
|
||||
skill_requested.emit(last_requested_skill_id)
|
||||
judge_rhythm_action(last_requested_skill_id)
|
||||
_play_skill_animation(current_skill_animation, _skill_displacement_direction(skill))
|
||||
if bool(skill.get("projectile", false)):
|
||||
_fire_projectile()
|
||||
_emit_combo_window_changed()
|
||||
if bool(skill.get("clear_window", false)):
|
||||
_schedule_combo_clear("skill:%s" % last_requested_skill_id)
|
||||
return true
|
||||
|
||||
|
||||
func _play_skill_animation(animation_name: String, displacement_direction := Vector2.ZERO) -> void:
|
||||
var player_animation := _get_animation_player()
|
||||
anim_map[State.ATTACK] = animation_name
|
||||
state = State.ATTACK
|
||||
attack_time_left = _animation_length(animation_name)
|
||||
if displacement_direction == Vector2.ZERO:
|
||||
attack_lunge_time_left = 0.0
|
||||
velocity = Vector2.ZERO
|
||||
else:
|
||||
heading = displacement_direction
|
||||
attack_lunge_time_left = attack_lunge_duration
|
||||
velocity = Vector2(displacement_direction.x * attack_lunge_speed, 0.0)
|
||||
if player_animation != null and player_animation.has_animation(animation_name):
|
||||
player_animation.play(animation_name)
|
||||
|
||||
|
||||
func _skill_displacement_direction(skill: Dictionary) -> Vector2:
|
||||
match str(skill.get("displacement", "")):
|
||||
"left":
|
||||
return Vector2.LEFT
|
||||
"right":
|
||||
return Vector2.RIGHT
|
||||
return Vector2.ZERO
|
||||
|
||||
|
||||
func _apply_energy_reward(rating_label: String) -> void:
|
||||
match rating_label:
|
||||
"perfect":
|
||||
_change_energy(2)
|
||||
"good":
|
||||
_change_energy(1)
|
||||
|
||||
|
||||
func _spend_skill_energy(skill: Dictionary) -> bool:
|
||||
var energy_cost := int(skill.get("energy_cost", 0))
|
||||
if energy_cost <= 0:
|
||||
return true
|
||||
if current_energy < energy_cost:
|
||||
return false
|
||||
_change_energy(-energy_cost)
|
||||
return true
|
||||
|
||||
|
||||
func _change_energy(delta: int) -> void:
|
||||
var next_energy := clampi(current_energy + delta, 0, max_energy)
|
||||
if next_energy == current_energy:
|
||||
return
|
||||
current_energy = next_energy
|
||||
_emit_energy_changed()
|
||||
|
||||
|
||||
func _begin_charge_hold(symbol: String, direction: Vector2) -> void:
|
||||
_charge_hold_symbol = symbol
|
||||
_charge_hold_direction = direction
|
||||
|
||||
|
||||
func _finish_charge_hold(symbol: String) -> void:
|
||||
if _charge_hold_symbol != symbol:
|
||||
return
|
||||
var release_ready := charge_active and charge_ready
|
||||
var release_direction := _charge_hold_direction
|
||||
var release_skill := "skill_a_charge_release" if symbol == "A" else "skill_d_charge_release"
|
||||
_cancel_charge()
|
||||
if release_ready:
|
||||
_execute_charge_release(release_skill, release_direction)
|
||||
|
||||
|
||||
func _update_charge(delta: float) -> void:
|
||||
if _charge_hold_symbol.is_empty():
|
||||
return
|
||||
if not charge_active:
|
||||
if state != State.IDLE:
|
||||
return
|
||||
_start_charge()
|
||||
if not charge_active:
|
||||
return
|
||||
state = State.IDLE
|
||||
attack_time_left = 0.0
|
||||
attack_lunge_time_left = 0.0
|
||||
velocity = Vector2.ZERO
|
||||
var player_animation := _get_animation_player()
|
||||
if player_animation != null and player_animation.has_animation("warrior_idle") and player_animation.current_animation != "warrior_idle":
|
||||
player_animation.play("warrior_idle")
|
||||
charge_value = minf(charge_duration, charge_value + delta)
|
||||
charge_ready = charge_value >= charge_duration
|
||||
_update_charge_effect(delta)
|
||||
_emit_charge_changed()
|
||||
|
||||
|
||||
func _start_charge() -> void:
|
||||
charge_active = true
|
||||
charge_value = 0.0
|
||||
charge_ready = false
|
||||
_charge_effect_time = 0.0
|
||||
_update_charge_effect(0.0)
|
||||
_emit_charge_changed()
|
||||
|
||||
|
||||
func _cancel_charge() -> void:
|
||||
_charge_hold_symbol = ""
|
||||
_charge_hold_direction = Vector2.ZERO
|
||||
charge_active = false
|
||||
charge_value = 0.0
|
||||
charge_ready = false
|
||||
_set_charge_effect_visible(false)
|
||||
_emit_charge_changed()
|
||||
|
||||
|
||||
func _execute_charge_release(skill_id: String, direction: Vector2) -> void:
|
||||
last_requested_skill_id = skill_id
|
||||
current_skill_animation = "warrior_charge_release"
|
||||
skill_requested.emit(last_requested_skill_id)
|
||||
_play_skill_animation(current_skill_animation, direction)
|
||||
|
||||
|
||||
func _update_charge_effect(delta: float) -> void:
|
||||
var sprite := _get_charge_effect_sprite()
|
||||
if sprite == null:
|
||||
return
|
||||
sprite.visible = charge_active
|
||||
if not charge_active:
|
||||
return
|
||||
_charge_effect_time += delta
|
||||
sprite.frame = int(_charge_effect_time * 12.0) % 5
|
||||
|
||||
|
||||
func _set_charge_effect_visible(is_visible: bool) -> void:
|
||||
var sprite := _get_charge_effect_sprite()
|
||||
if sprite != null:
|
||||
sprite.visible = is_visible
|
||||
|
||||
|
||||
func _get_charge_effect_sprite() -> Sprite2D:
|
||||
if has_node("ChargeEffectSprite"):
|
||||
return get_node("ChargeEffectSprite") as Sprite2D
|
||||
return null
|
||||
|
||||
|
||||
func _resolve_full_window_fallback(symbol: String) -> Dictionary:
|
||||
if symbol != "A" and symbol != "D":
|
||||
return {}
|
||||
return InputResolver.resolve_pattern(symbol)
|
||||
|
||||
|
||||
func _cancel_missed_direction_action() -> void:
|
||||
velocity = Vector2.ZERO
|
||||
attack_lunge_time_left = 0.0
|
||||
attack_time_left = 0.0
|
||||
state = State.IDLE
|
||||
anim_map[State.ATTACK] = "warrior_a"
|
||||
var player_animation := _get_animation_player()
|
||||
if player_animation != null and player_animation.has_animation("warrior_idle"):
|
||||
player_animation.play("warrior_idle")
|
||||
|
||||
|
||||
func _is_projectile_space_chain() -> bool:
|
||||
var pattern := combo_window.get_contiguous_pattern()
|
||||
return pattern == "SSP" or pattern == "SSPSP" or pattern == "SSPSPSP"
|
||||
|
||||
|
||||
func _apply_horizontal_movement() -> void:
|
||||
if charge_active:
|
||||
velocity.x = 0.0
|
||||
return
|
||||
if state != State.IDLE and state != State.WALK:
|
||||
return
|
||||
var direction := 0.0
|
||||
if Input.is_action_pressed("player_a"):
|
||||
direction -= 1.0
|
||||
if Input.is_action_pressed("player_d"):
|
||||
direction += 1.0
|
||||
if direction < 0.0:
|
||||
heading = Vector2.LEFT
|
||||
elif direction > 0.0:
|
||||
heading = Vector2.RIGHT
|
||||
velocity.x = direction * speed
|
||||
|
||||
|
||||
func _animation_length(animation_name: String) -> float:
|
||||
var player_animation := _get_animation_player()
|
||||
if player_animation != null and player_animation.has_animation(animation_name):
|
||||
return maxf(0.1, player_animation.get_animation(animation_name).length)
|
||||
return attack_duration
|
||||
|
||||
|
||||
func _get_animation_player() -> AnimationPlayer:
|
||||
if animation_player == null and has_node("AnimationPlayer"):
|
||||
animation_player = get_node("AnimationPlayer") as AnimationPlayer
|
||||
return animation_player
|
||||
|
||||
|
||||
func _fire_projectile() -> void:
|
||||
var projectile := PlayerProjectile.new()
|
||||
projectile.direction = heading
|
||||
projectile.global_position = global_position + Vector2(heading.x * 36.0, -30.0)
|
||||
var parent := get_parent()
|
||||
if parent != null:
|
||||
parent.add_child(projectile)
|
||||
else:
|
||||
add_child(projectile)
|
||||
projectile.add_to_group("player_projectiles")
|
||||
|
||||
|
||||
func _cancel_pending_combo_clear() -> void:
|
||||
_pending_combo_clear_reason = ""
|
||||
if combo_clear_timer != null:
|
||||
combo_clear_timer.stop()
|
||||
|
||||
|
||||
func _schedule_combo_clear(reason: String) -> void:
|
||||
_pending_combo_clear_reason = reason
|
||||
if combo_clear_timer == null:
|
||||
return
|
||||
combo_clear_timer.stop()
|
||||
combo_clear_timer.wait_time = combo_clear_display_time
|
||||
combo_clear_timer.start()
|
||||
|
||||
|
||||
func flush_pending_combo_clear() -> void:
|
||||
var reason := _pending_combo_clear_reason
|
||||
if reason.is_empty():
|
||||
reason = combo_window.consume_pending_clear_reason()
|
||||
else:
|
||||
combo_window.consume_pending_clear_reason()
|
||||
if reason.is_empty():
|
||||
return
|
||||
_pending_combo_clear_reason = ""
|
||||
if combo_clear_timer != null:
|
||||
combo_clear_timer.stop()
|
||||
combo_window.clear(reason)
|
||||
|
||||
|
||||
func _on_combo_window_cleared(reason: String) -> void:
|
||||
combo_window_cleared.emit(reason)
|
||||
_emit_combo_window_changed()
|
||||
|
||||
|
||||
func _emit_combo_window_changed() -> void:
|
||||
combo_window_changed.emit(combo_window.get_slots())
|
||||
|
||||
|
||||
func _emit_charge_changed() -> void:
|
||||
charge_changed.emit(charge_value, charge_duration, charge_ready, charge_active)
|
||||
|
||||
|
||||
func _emit_energy_changed() -> void:
|
||||
energy_changed.emit(current_energy, max_energy)
|
||||
|
||||
|
||||
func _emit_health_changed() -> void:
|
||||
health_changed.emit(current_health, max_health)
|
||||
|
||||
|
||||
func judge_rhythm_action(action_name: String) -> Dictionary:
|
||||
if not is_inside_tree():
|
||||
return {"label": "perfect"}
|
||||
var conductor: Node = get_tree().get_first_node_in_group("rhythm_conductor")
|
||||
if conductor != null and conductor.has_method("judge_action"):
|
||||
conductor.call("judge_action", action_name)
|
||||
return conductor.call("judge_action", action_name) as Dictionary
|
||||
return {"label": "perfect"}
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
[gd_scene load_steps=10 format=3]
|
||||
[gd_scene format=3 uid="uid://cs3s5wy1melul"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/characters/player.gd" id="1_player_script"]
|
||||
[ext_resource type="Texture2D" path="res://assets/art/characters/jump.png" id="2_jump_texture"]
|
||||
[ext_resource type="Texture2D" path="res://assets/art/characters/katana_attack_sheathe.png" id="3_slash_texture"]
|
||||
[ext_resource type="Texture2D" path="res://assets/art/characters/player_idle.png" id="4_idle_texture"]
|
||||
[ext_resource type="Script" uid="uid://cwp1u2srtj5ko" path="res://scenes/characters/player.gd" id="1_player_script"]
|
||||
[ext_resource type="Texture2D" uid="uid://bbkamgcdsw5g6" path="res://assets/art/characters/warrior_man_sheet.png" id="2_yewv4"]
|
||||
[ext_resource type="Texture2D" uid="uid://womoel71g8ae" path="res://assets/art/characters/warrior_woman_sheet.png" id="3_dyp2m"]
|
||||
[ext_resource type="Texture2D" uid="uid://1p2uqgg1jole" path="res://assets/art/effects/effect_hp_mp_sheet.png" id="4_atpat"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_player"]
|
||||
size = Vector2(16, 36)
|
||||
|
||||
[sub_resource type="Animation" id="Animation_idle"]
|
||||
resource_name = "idle"
|
||||
length = 1.0
|
||||
loop_mode = 1
|
||||
step = 0.1
|
||||
[sub_resource type="Animation" id="Animation_76oj4"]
|
||||
resource_name = "warrior_a"
|
||||
length = 0.5833333
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
@@ -23,7 +22,7 @@ tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("4_idle_texture")]
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
@@ -35,7 +34,7 @@ tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [10]
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
@@ -47,138 +46,7 @@ tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [1]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-24, -40)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_jump"]
|
||||
resource_name = "jump"
|
||||
length = 0.36
|
||||
loop_mode = 1
|
||||
step = 0.06
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_jump_texture")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [6]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [1]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-24, -44)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.06, 0.12, 0.18, 0.24, 0.3),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_slash"]
|
||||
resource_name = "挥砍"
|
||||
length = 0.4
|
||||
step = 0.04
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("3_slash_texture")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [10]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [1]
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
@@ -199,51 +67,708 @@ tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.04, 0.08, 0.12, 0.16, 0.2, 0.24, 0.28, 0.32, 0.36),
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666, 0.5),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [144, 145, 146, 147, 148, 149, 150]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_yewv4"]
|
||||
resource_name = "warrior_a_space"
|
||||
length = 0.8333333
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666, 0.5, 0.5833333, 0.6666667, 0.75),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
"values": [256, 257, 258, 259, 260, 261, 262, 263, 264, 265]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_player"]
|
||||
[sub_resource type="Animation" id="Animation_2l4js"]
|
||||
resource_name = "warrior_a_space_space"
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666, 0.5, 0.5833333, 0.6666667, 0.75, 0.8333333, 0.9166667),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_dyp2m"]
|
||||
resource_name = "warrior_aa"
|
||||
length = 0.41666666
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [160, 161, 162, 163, 164]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_atpat"]
|
||||
resource_name = "warrior_aaa"
|
||||
length = 0.5714286
|
||||
step = 0.071428575
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.071428575, 0.14285715, 0.21428572, 0.2857143, 0.35714287, 0.42857143, 0.5),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [176, 177, 178, 179, 180, 181, 182, 183]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_jk2m4"]
|
||||
resource_name = "warrior_charge_release"
|
||||
length = 1.3333334
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("3_dyp2m")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666, 0.5, 0.5833333, 0.6666667, 0.75, 0.8333333, 0.9166667, 1, 1.0833334, 1.1666666, 1.25),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_kqtwu"]
|
||||
resource_name = "warrior_idle"
|
||||
length = 0.8
|
||||
loop_mode = 1
|
||||
step = 0.1
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_6eyoc"]
|
||||
resource_name = "warrior_s"
|
||||
length = 0.71428573
|
||||
step = 0.071428575
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.071428575, 0.14285715, 0.21428572, 0.2857143, 0.35714287, 0.42857143, 0.5, 0.5714286, 0.64285713),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [128, 129, 130, 131, 132, 133, 134, 135, 136, 137]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_eojnx"]
|
||||
resource_name = "warrior_s_projectile"
|
||||
length = 0.8125
|
||||
step = 0.0625
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.0625, 0.125, 0.1875, 0.25, 0.3125, 0.375, 0.4375, 0.5, 0.5625, 0.625, 0.6875, 0.75),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_qgnko"]
|
||||
resource_name = "warrior_w"
|
||||
length = 0.5
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [80, 81, 82, 83, 84, 85]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_7vyk4"]
|
||||
resource_name = "warrior_wa"
|
||||
length = 0.41666666
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
tracks/0/enabled = true
|
||||
tracks/0/path = NodePath("CharacterSprite:texture")
|
||||
tracks/0/interp = 1
|
||||
tracks/0/loop_wrap = true
|
||||
tracks/0/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [ExtResource("2_yewv4")]
|
||||
}
|
||||
tracks/1/type = "value"
|
||||
tracks/1/imported = false
|
||||
tracks/1/enabled = true
|
||||
tracks/1/path = NodePath("CharacterSprite:hframes")
|
||||
tracks/1/interp = 1
|
||||
tracks/1/loop_wrap = true
|
||||
tracks/1/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [16]
|
||||
}
|
||||
tracks/2/type = "value"
|
||||
tracks/2/imported = false
|
||||
tracks/2/enabled = true
|
||||
tracks/2/path = NodePath("CharacterSprite:vframes")
|
||||
tracks/2/interp = 1
|
||||
tracks/2/loop_wrap = true
|
||||
tracks/2/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [25]
|
||||
}
|
||||
tracks/3/type = "value"
|
||||
tracks/3/imported = false
|
||||
tracks/3/enabled = true
|
||||
tracks/3/path = NodePath("CharacterSprite:offset")
|
||||
tracks/3/interp = 1
|
||||
tracks/3/loop_wrap = true
|
||||
tracks/3/keys = {
|
||||
"times": PackedFloat32Array(0),
|
||||
"transitions": PackedFloat32Array(1),
|
||||
"update": 1,
|
||||
"values": [Vector2(-40, -48)]
|
||||
}
|
||||
tracks/4/type = "value"
|
||||
tracks/4/imported = false
|
||||
tracks/4/enabled = true
|
||||
tracks/4/path = NodePath("CharacterSprite:frame")
|
||||
tracks/4/interp = 1
|
||||
tracks/4/loop_wrap = true
|
||||
tracks/4/keys = {
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [96, 97, 98, 99, 100]
|
||||
}
|
||||
|
||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_2l4js"]
|
||||
_data = {
|
||||
"idle": SubResource("Animation_idle"),
|
||||
"jump": SubResource("Animation_jump"),
|
||||
"挥砍": SubResource("Animation_slash")
|
||||
&"warrior_a": SubResource("Animation_76oj4"),
|
||||
&"warrior_a_space": SubResource("Animation_yewv4"),
|
||||
&"warrior_a_space_space": SubResource("Animation_2l4js"),
|
||||
&"warrior_aa": SubResource("Animation_dyp2m"),
|
||||
&"warrior_aaa": SubResource("Animation_atpat"),
|
||||
&"warrior_charge_release": SubResource("Animation_jk2m4"),
|
||||
&"warrior_idle": SubResource("Animation_kqtwu"),
|
||||
&"warrior_s": SubResource("Animation_6eyoc"),
|
||||
&"warrior_s_projectile": SubResource("Animation_eojnx"),
|
||||
&"warrior_w": SubResource("Animation_qgnko"),
|
||||
&"warrior_wa": SubResource("Animation_7vyk4")
|
||||
}
|
||||
|
||||
[node name="Player" type="CharacterBody2D"]
|
||||
collision_layer = 2
|
||||
collision_mask = 1
|
||||
safe_margin = 0.001
|
||||
floor_snap_length = 0.0
|
||||
[node name="Player" type="CharacterBody2D" unique_id=1029375298]
|
||||
scale = Vector2(4, 4)
|
||||
collision_layer = 2
|
||||
floor_snap_length = 0.0
|
||||
safe_margin = 0.001
|
||||
script = ExtResource("1_player_script")
|
||||
speed = 180.0
|
||||
jump_intensity = 304.056
|
||||
attack_duration = 0.4
|
||||
attack_lunge_duration = 0.18
|
||||
attack_lunge_speed = 220.0
|
||||
|
||||
[node name="CharacterSprite" type="Sprite2D" parent="."]
|
||||
texture = ExtResource("4_idle_texture")
|
||||
[node name="CharacterSprite" type="Sprite2D" parent="." unique_id=1175595770]
|
||||
texture = ExtResource("2_yewv4")
|
||||
centered = false
|
||||
offset = Vector2(-24, -40)
|
||||
hframes = 10
|
||||
vframes = 1
|
||||
offset = Vector2(-40, -48)
|
||||
hframes = 16
|
||||
vframes = 25
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="." unique_id=1167515641]
|
||||
position = Vector2(0, -18)
|
||||
shape = SubResource("RectangleShape2D_player")
|
||||
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
|
||||
libraries = {
|
||||
"": SubResource("AnimationLibrary_player")
|
||||
}
|
||||
autoplay = "idle"
|
||||
[node name="AnimationPlayer" type="AnimationPlayer" parent="." unique_id=822598049]
|
||||
libraries/ = SubResource("AnimationLibrary_2l4js")
|
||||
autoplay = &"warrior_idle"
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="."]
|
||||
[node name="Camera2D" type="Camera2D" parent="." unique_id=1607685219]
|
||||
position = Vector2(0, -37.5)
|
||||
scale = Vector2(0.25, 0.25)
|
||||
zoom = Vector2(1.5, 1.5)
|
||||
enabled = true
|
||||
|
||||
[node name="ChargeEffectSprite" type="Sprite2D" parent="." unique_id=1049185311]
|
||||
visible = false
|
||||
z_index = 2
|
||||
position = Vector2(0, -8)
|
||||
texture = ExtResource("4_atpat")
|
||||
hframes = 5
|
||||
vframes = 2
|
||||
|
||||
55
scenes/combat/combo_window.gd
Normal file
55
scenes/combat/combo_window.gd
Normal file
@@ -0,0 +1,55 @@
|
||||
class_name ComboWindow
|
||||
extends RefCounted
|
||||
|
||||
signal window_cleared(reason: String)
|
||||
|
||||
const SIZE := 4
|
||||
|
||||
var slots: Array[String] = []
|
||||
var pending_clear_reason := ""
|
||||
|
||||
|
||||
func record(input: String) -> void:
|
||||
if input.is_empty():
|
||||
return
|
||||
slots.append(input)
|
||||
if slots.size() >= SIZE:
|
||||
pending_clear_reason = "full"
|
||||
|
||||
|
||||
func get_slots() -> Array[String]:
|
||||
return slots.duplicate()
|
||||
|
||||
|
||||
func has_pending_clear() -> bool:
|
||||
return not pending_clear_reason.is_empty()
|
||||
|
||||
|
||||
func consume_pending_clear_reason() -> String:
|
||||
var reason := pending_clear_reason
|
||||
pending_clear_reason = ""
|
||||
return reason
|
||||
|
||||
|
||||
func get_pattern() -> String:
|
||||
var pattern := ""
|
||||
for slot: String in slots:
|
||||
if slot != "Ø":
|
||||
pattern += slot
|
||||
return pattern
|
||||
|
||||
|
||||
func get_contiguous_pattern() -> String:
|
||||
var pattern := ""
|
||||
for index: int in range(slots.size() - 1, -1, -1):
|
||||
var slot := slots[index]
|
||||
if slot == "Ø":
|
||||
break
|
||||
pattern = slot + pattern
|
||||
return pattern
|
||||
|
||||
|
||||
func clear(reason := "") -> void:
|
||||
slots.clear()
|
||||
pending_clear_reason = ""
|
||||
window_cleared.emit(reason)
|
||||
1
scenes/combat/combo_window.gd.uid
Normal file
1
scenes/combat/combo_window.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dtguxwnh02f6g
|
||||
151
scenes/combat/input_resolver.gd
Normal file
151
scenes/combat/input_resolver.gd
Normal file
@@ -0,0 +1,151 @@
|
||||
class_name InputResolver
|
||||
extends RefCounted
|
||||
|
||||
const SKILLS := {
|
||||
"A": {
|
||||
"type": "skill",
|
||||
"id": "skill_a",
|
||||
"animation": "warrior_a",
|
||||
"displacement": "left",
|
||||
"clear_window": false,
|
||||
},
|
||||
"D": {
|
||||
"type": "skill",
|
||||
"id": "skill_d",
|
||||
"animation": "warrior_a",
|
||||
"displacement": "right",
|
||||
"clear_window": false,
|
||||
},
|
||||
"WA": {
|
||||
"type": "skill",
|
||||
"id": "skill_wa",
|
||||
"animation": "warrior_wa",
|
||||
"displacement": "left",
|
||||
"clear_window": false,
|
||||
},
|
||||
"WD": {
|
||||
"type": "skill",
|
||||
"id": "skill_wd",
|
||||
"animation": "warrior_wa",
|
||||
"displacement": "right",
|
||||
"clear_window": false,
|
||||
},
|
||||
"AA": {
|
||||
"type": "skill",
|
||||
"id": "skill_aa",
|
||||
"animation": "warrior_aa",
|
||||
"displacement": "left",
|
||||
"clear_window": false,
|
||||
},
|
||||
"DD": {
|
||||
"type": "skill",
|
||||
"id": "skill_dd",
|
||||
"animation": "warrior_aa",
|
||||
"displacement": "right",
|
||||
"clear_window": false,
|
||||
},
|
||||
"AAA": {
|
||||
"type": "skill",
|
||||
"id": "skill_aaa",
|
||||
"animation": "warrior_aaa",
|
||||
"displacement": "left",
|
||||
"clear_window": false,
|
||||
},
|
||||
"DDD": {
|
||||
"type": "skill",
|
||||
"id": "skill_ddd",
|
||||
"animation": "warrior_aaa",
|
||||
"displacement": "right",
|
||||
"clear_window": false,
|
||||
},
|
||||
"ASP": {
|
||||
"type": "skill",
|
||||
"id": "skill_a_space",
|
||||
"animation": "warrior_a_space",
|
||||
"displacement": "left",
|
||||
"clear_window": true,
|
||||
},
|
||||
"DSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_d_space",
|
||||
"animation": "warrior_a_space",
|
||||
"displacement": "right",
|
||||
"clear_window": true,
|
||||
},
|
||||
"ASPSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_a_space_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "left",
|
||||
"clear_window": true,
|
||||
},
|
||||
"DSPSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_d_space_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "right",
|
||||
"clear_window": true,
|
||||
},
|
||||
"AASP": {
|
||||
"type": "skill",
|
||||
"id": "skill_aa_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "left",
|
||||
"clear_window": true,
|
||||
},
|
||||
"ADSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_ad_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "right",
|
||||
"clear_window": true,
|
||||
},
|
||||
"DASP": {
|
||||
"type": "skill",
|
||||
"id": "skill_da_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "left",
|
||||
"clear_window": true,
|
||||
},
|
||||
"DDSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_dd_space",
|
||||
"animation": "warrior_a_space_space",
|
||||
"displacement": "right",
|
||||
"clear_window": true,
|
||||
},
|
||||
"SSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_s_projectile_1",
|
||||
"animation": "warrior_s_projectile",
|
||||
"projectile": true,
|
||||
"energy_cost": 3,
|
||||
"clear_window": false,
|
||||
},
|
||||
"SSPSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_s_projectile_2",
|
||||
"animation": "warrior_s_projectile",
|
||||
"projectile": true,
|
||||
"energy_cost": 2,
|
||||
"clear_window": false,
|
||||
},
|
||||
"SSPSPSP": {
|
||||
"type": "skill",
|
||||
"id": "skill_s_projectile_3",
|
||||
"animation": "warrior_s_projectile",
|
||||
"projectile": true,
|
||||
"energy_cost": 1,
|
||||
"clear_window": false,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
static func resolve(window: ComboWindow) -> Dictionary:
|
||||
return resolve_pattern(window.get_contiguous_pattern())
|
||||
|
||||
|
||||
static func resolve_pattern(pattern: String) -> Dictionary:
|
||||
if not SKILLS.has(pattern):
|
||||
return {}
|
||||
return SKILLS[pattern].duplicate()
|
||||
1
scenes/combat/input_resolver.gd.uid
Normal file
1
scenes/combat/input_resolver.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cyhq381jiyo42
|
||||
42
scenes/combat/player_projectile.gd
Normal file
42
scenes/combat/player_projectile.gd
Normal file
@@ -0,0 +1,42 @@
|
||||
class_name PlayerProjectile
|
||||
extends Node2D
|
||||
|
||||
const EFFECT_TEXTURE := preload("res://assets/art/effects/effect_sheet.png")
|
||||
const FRAME_COUNT := 4
|
||||
const FRAME_TIME := 0.06
|
||||
const LIFE_TIME := 1.2
|
||||
|
||||
var direction := Vector2.RIGHT
|
||||
var speed := 360.0
|
||||
var _age := 0.0
|
||||
var _sprite: Sprite2D
|
||||
|
||||
|
||||
func _init() -> void:
|
||||
_create_sprite()
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
add_to_group("player_projectiles")
|
||||
if _sprite == null:
|
||||
_create_sprite()
|
||||
|
||||
|
||||
func _create_sprite() -> void:
|
||||
_sprite = Sprite2D.new()
|
||||
_sprite.texture = EFFECT_TEXTURE
|
||||
_sprite.hframes = 6
|
||||
_sprite.vframes = 2
|
||||
_sprite.centered = true
|
||||
_sprite.scale = Vector2(2.0, 2.0)
|
||||
add_child(_sprite)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_age += delta
|
||||
position += direction.normalized() * speed * delta
|
||||
_sprite.frame = int(_age / FRAME_TIME) % FRAME_COUNT
|
||||
if direction.x < 0.0:
|
||||
_sprite.flip_h = true
|
||||
if _age >= LIFE_TIME:
|
||||
queue_free()
|
||||
1
scenes/combat/player_projectile.gd.uid
Normal file
1
scenes/combat/player_projectile.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bwjk27wxb6p20
|
||||
@@ -3,10 +3,43 @@ extends Node2D
|
||||
@onready var rhythm_conductor: Node = $RhythmConductor
|
||||
@onready var rhythm_track: Control = $RhythmFeedback/RhythmTrack
|
||||
@onready var rhythm_feedback_label: Label = $RhythmFeedback/JudgementLabel
|
||||
@onready var player: Node = $Player
|
||||
@onready var center_base: TextureRect = $RhythmFeedback/RhythmTrack/CenterBase
|
||||
@onready var center_flash: TextureRect = $RhythmFeedback/RhythmTrack/CenterFlash
|
||||
@onready var left_mover: TextureRect = $RhythmFeedback/RhythmTrack/LeftMover
|
||||
@onready var right_mover: TextureRect = $RhythmFeedback/RhythmTrack/RightMover
|
||||
@onready var combo_skill_label: Label = $RhythmFeedback/ComboSkillLabel
|
||||
@onready var health_bar: ProgressBar = $RhythmFeedback/StatusBars/HealthBar
|
||||
@onready var charge_bar: ProgressBar = $RhythmFeedback/StatusBars/ChargeBar
|
||||
@onready var energy_segments: Array[Panel] = [
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment0,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment1,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment2,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment3,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment4,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment5,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment6,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment7,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment8,
|
||||
$RhythmFeedback/StatusBars/EnergyBar/Segment9,
|
||||
]
|
||||
@onready var combo_slot_panels: Array[PanelContainer] = [
|
||||
$RhythmFeedback/ComboWindow/Slot0,
|
||||
$RhythmFeedback/ComboWindow/Slot1,
|
||||
$RhythmFeedback/ComboWindow/Slot2,
|
||||
$RhythmFeedback/ComboWindow/Slot3,
|
||||
]
|
||||
@onready var combo_key_labels: Array[Label] = [
|
||||
$RhythmFeedback/ComboWindow/Slot0/Key,
|
||||
$RhythmFeedback/ComboWindow/Slot1/Key,
|
||||
$RhythmFeedback/ComboWindow/Slot2/Key,
|
||||
$RhythmFeedback/ComboWindow/Slot3/Key,
|
||||
]
|
||||
|
||||
var combo_clear_tween: Tween
|
||||
var combo_clear_flash := 0.0
|
||||
var charge_bar_ready := false
|
||||
var charge_flash := 0.0
|
||||
|
||||
var track_center := Vector2.ZERO
|
||||
var left_mover_start := Vector2.ZERO
|
||||
@@ -21,12 +54,33 @@ func _ready() -> void:
|
||||
_cache_rhythm_track_layout()
|
||||
rhythm_conductor.action_judged.connect(_on_rhythm_action_judged)
|
||||
rhythm_conductor.beat.connect(_on_rhythm_beat)
|
||||
if player.has_signal("combo_window_changed"):
|
||||
player.connect("combo_window_changed", _on_combo_window_changed)
|
||||
if player.has_signal("combo_window_cleared"):
|
||||
player.connect("combo_window_cleared", _on_combo_window_cleared)
|
||||
if player.has_signal("skill_requested"):
|
||||
player.connect("skill_requested", _on_skill_requested)
|
||||
if player.has_signal("energy_changed"):
|
||||
player.connect("energy_changed", _on_energy_changed)
|
||||
if player.has_signal("health_changed"):
|
||||
player.connect("health_changed", _on_health_changed)
|
||||
if player.has_signal("charge_changed"):
|
||||
player.connect("charge_changed", _on_charge_changed)
|
||||
rhythm_feedback_label.text = "READY"
|
||||
_on_combo_window_changed([])
|
||||
if player.has_method("get_energy") and player.has_method("get_max_energy"):
|
||||
_on_energy_changed(player.call("get_energy"), player.call("get_max_energy"))
|
||||
if player.has_method("get_health") and player.has_method("get_max_health"):
|
||||
_on_health_changed(player.call("get_health"), player.call("get_max_health"))
|
||||
if player.has_method("get_charge") and player.has_method("get_max_charge") and player.has_method("is_charge_ready") and player.has_method("is_charge_active"):
|
||||
_on_charge_changed(player.call("get_charge"), player.call("get_max_charge"), player.call("is_charge_ready"), player.call("is_charge_active"))
|
||||
_update_rhythm_track(0.0)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_update_rhythm_track(delta)
|
||||
_update_combo_clear_animation(delta)
|
||||
_update_charge_bar_flash(delta)
|
||||
if feedback_flash > 0.0:
|
||||
feedback_flash = maxf(0.0, feedback_flash - delta * 4.0)
|
||||
rhythm_feedback_label.scale = Vector2.ONE * (1.0 + feedback_flash * 0.18)
|
||||
@@ -50,6 +104,92 @@ func _on_rhythm_beat(_position: int) -> void:
|
||||
beat_flash = 1.0
|
||||
|
||||
|
||||
func _on_combo_window_changed(slots: Array) -> void:
|
||||
for index: int in range(combo_key_labels.size()):
|
||||
var filled := index < slots.size()
|
||||
var label := combo_key_labels[index]
|
||||
var panel := combo_slot_panels[index]
|
||||
label.text = str(slots[index]) if filled else "·"
|
||||
label.modulate = Color(1.0, 1.0, 1.0, 1.0 if filled else 0.32)
|
||||
panel.modulate = Color(1.0, 1.0, 1.0, 1.0 if filled else 0.48)
|
||||
if filled:
|
||||
_pulse_combo_slot(panel)
|
||||
|
||||
|
||||
func _on_combo_window_cleared(_reason: String) -> void:
|
||||
_play_combo_clear_animation()
|
||||
|
||||
|
||||
func _on_skill_requested(skill_id: String) -> void:
|
||||
combo_skill_label.text = _format_skill_name(skill_id)
|
||||
|
||||
|
||||
func _on_energy_changed(current: int, maximum: int) -> void:
|
||||
var filled_segments := clampi(current, 0, min(maximum, energy_segments.size()))
|
||||
for index: int in range(energy_segments.size()):
|
||||
var filled := index < filled_segments
|
||||
var panel := energy_segments[index]
|
||||
panel.modulate = Color(1.0, 1.0, 1.0, 1.0 if filled else 0.38)
|
||||
|
||||
|
||||
func _on_health_changed(current: int, maximum: int) -> void:
|
||||
health_bar.max_value = max(1, maximum)
|
||||
health_bar.value = clampi(current, 0, maximum)
|
||||
|
||||
|
||||
func _on_charge_changed(current: float, maximum: float, ready: bool, active: bool) -> void:
|
||||
charge_bar.max_value = maxf(0.01, maximum)
|
||||
charge_bar.value = clampf(current, 0.0, maximum)
|
||||
charge_bar_ready = ready and active
|
||||
if charge_bar_ready:
|
||||
return
|
||||
charge_bar.modulate = Color(1.0, 1.0, 1.0, 1.0 if active or current > 0.0 else 0.45)
|
||||
|
||||
|
||||
func _update_charge_bar_flash(delta: float) -> void:
|
||||
if not charge_bar_ready:
|
||||
charge_flash = 0.0
|
||||
return
|
||||
charge_flash = fmod(charge_flash + delta * 7.0, TAU)
|
||||
var alpha := 0.62 + 0.38 * absf(sin(charge_flash))
|
||||
charge_bar.modulate = Color(1.0, 1.0, 1.0, alpha)
|
||||
|
||||
|
||||
func _play_combo_clear_animation() -> void:
|
||||
if combo_clear_tween != null and combo_clear_tween.is_valid():
|
||||
combo_clear_tween.kill()
|
||||
combo_clear_flash = 1.0
|
||||
for panel: PanelContainer in combo_slot_panels:
|
||||
panel.scale = Vector2(1.16, 1.16)
|
||||
panel.modulate = Color(1.0, 1.0, 1.0, 1.0)
|
||||
|
||||
|
||||
func _update_combo_clear_animation(delta: float) -> void:
|
||||
if combo_clear_flash <= 0.0:
|
||||
return
|
||||
combo_clear_flash = maxf(0.0, combo_clear_flash - delta * 5.0)
|
||||
var eased := combo_clear_flash * combo_clear_flash
|
||||
for panel: PanelContainer in combo_slot_panels:
|
||||
panel.scale = Vector2.ONE * (1.0 + 0.16 * eased)
|
||||
panel.modulate = Color(1.0, 1.0, 1.0, 0.48 + 0.52 * eased)
|
||||
if combo_clear_flash <= 0.0:
|
||||
_restore_empty_combo_slots()
|
||||
|
||||
|
||||
func _pulse_combo_slot(panel: PanelContainer) -> void:
|
||||
var tween := create_tween()
|
||||
panel.scale = Vector2(1.08, 1.08)
|
||||
tween.tween_property(panel, "scale", Vector2.ONE, 0.09)
|
||||
|
||||
|
||||
func _restore_empty_combo_slots() -> void:
|
||||
for index: int in range(combo_slot_panels.size()):
|
||||
combo_slot_panels[index].modulate = Color(1.0, 1.0, 1.0, 0.48)
|
||||
combo_slot_panels[index].scale = Vector2.ONE
|
||||
combo_key_labels[index].text = "·"
|
||||
combo_key_labels[index].modulate = Color(1.0, 1.0, 1.0, 0.32)
|
||||
|
||||
|
||||
func _update_rhythm_track(delta: float) -> void:
|
||||
beat_flash = maxf(0.0, beat_flash - delta * 8.0)
|
||||
var progress := 0.0
|
||||
@@ -88,16 +228,110 @@ func _set_control_center(control: Control, center: Vector2, size: Vector2) -> vo
|
||||
|
||||
func _format_action_name(action_name: String) -> String:
|
||||
match action_name:
|
||||
"left":
|
||||
return "LEFT"
|
||||
"right":
|
||||
return "RIGHT"
|
||||
"jump":
|
||||
return "JUMP"
|
||||
"w":
|
||||
return "W"
|
||||
"a":
|
||||
return "A"
|
||||
"d":
|
||||
return "D"
|
||||
"s":
|
||||
return "S"
|
||||
"space":
|
||||
return "SP"
|
||||
"skill_w":
|
||||
return "W"
|
||||
"skill_wa":
|
||||
return "W+A"
|
||||
"skill_wd":
|
||||
return "W+D"
|
||||
"skill_s":
|
||||
return "S"
|
||||
"skill_a":
|
||||
return "A"
|
||||
"skill_d":
|
||||
return "D"
|
||||
"skill_aa":
|
||||
return "A+A"
|
||||
"skill_dd":
|
||||
return "D+D"
|
||||
"skill_aaa":
|
||||
return "A+A+A"
|
||||
"skill_ddd":
|
||||
return "D+D+D"
|
||||
"skill_a_space":
|
||||
return "A+SP"
|
||||
"skill_d_space":
|
||||
return "D+SP"
|
||||
"skill_a_space_space":
|
||||
return "A+SP+SP"
|
||||
"skill_d_space_space":
|
||||
return "D+SP+SP"
|
||||
"skill_aa_space":
|
||||
return "A+A+SP"
|
||||
"skill_ad_space":
|
||||
return "A+D+SP"
|
||||
"skill_da_space":
|
||||
return "D+A+SP"
|
||||
"skill_dd_space":
|
||||
return "D+D+SP"
|
||||
"skill_s_projectile_1":
|
||||
return "S+SP"
|
||||
"skill_s_projectile_2":
|
||||
return "S+SP+SP"
|
||||
"skill_s_projectile_3":
|
||||
return "S+SP+SP+SP"
|
||||
_:
|
||||
return action_name.to_upper()
|
||||
|
||||
|
||||
func _format_skill_name(skill_id: String) -> String:
|
||||
match skill_id:
|
||||
"skill_w":
|
||||
return "W"
|
||||
"skill_wa":
|
||||
return "W+A"
|
||||
"skill_wd":
|
||||
return "W+D"
|
||||
"skill_s":
|
||||
return "S"
|
||||
"skill_a":
|
||||
return "A"
|
||||
"skill_d":
|
||||
return "D"
|
||||
"skill_aa":
|
||||
return "A+A"
|
||||
"skill_dd":
|
||||
return "D+D"
|
||||
"skill_aaa":
|
||||
return "A+A+A"
|
||||
"skill_ddd":
|
||||
return "D+D+D"
|
||||
"skill_a_space":
|
||||
return "A+SP"
|
||||
"skill_d_space":
|
||||
return "D+SP"
|
||||
"skill_a_space_space":
|
||||
return "A+SP+SP"
|
||||
"skill_d_space_space":
|
||||
return "D+SP+SP"
|
||||
"skill_aa_space":
|
||||
return "A+A+SP"
|
||||
"skill_ad_space":
|
||||
return "A+D+SP"
|
||||
"skill_da_space":
|
||||
return "D+A+SP"
|
||||
"skill_dd_space":
|
||||
return "D+D+SP"
|
||||
"skill_s_projectile_1":
|
||||
return "S+SP"
|
||||
"skill_s_projectile_2":
|
||||
return "S+SP+SP"
|
||||
"skill_s_projectile_3":
|
||||
return "S+SP+SP+SP"
|
||||
_:
|
||||
return skill_id.to_upper()
|
||||
|
||||
|
||||
func _format_signed_ms(seconds: float) -> String:
|
||||
if is_inf(seconds):
|
||||
return "-- ms"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[gd_scene format=3 uid="uid://brx0c2va3831p"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://cs0rhloanh2u4" path="res://scenes/ground/ground.tscn" id="1_ground"]
|
||||
[ext_resource type="PackedScene" path="res://scenes/characters/player.tscn" id="2_player"]
|
||||
[ext_resource type="PackedScene" uid="uid://cs3s5wy1melul" path="res://scenes/characters/player.tscn" id="2_player"]
|
||||
[ext_resource type="Script" uid="uid://3n4nkejauoim" path="res://scenes/main/main.gd" id="3_main_script"]
|
||||
[ext_resource type="Script" uid="uid://brh83qp8flq5u" path="res://scenes/rhythm/rhythm_conductor.gd" id="4_rhythm_script"]
|
||||
[ext_resource type="AudioStream" uid="uid://di5ceecn088rk" path="res://assets/audio/song.ogg" id="5_song"]
|
||||
@@ -11,6 +11,172 @@
|
||||
[ext_resource type="Texture2D" uid="uid://dbmdivnpjf48l" path="res://assets/ui/rhythm/blue_ball.png" id="9_blue_ball"]
|
||||
[ext_resource type="Texture2D" uid="uid://ewr8k3lwpcna" path="res://assets/ui/rhythm/yellow_ball.png" id="10_yellow_ball"]
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a8run"]
|
||||
content_margin_left = 6.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 6.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.04, 0.07, 0.09, 0.82)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.43, 0.78, 0.88, 0.95)
|
||||
corner_radius_top_left = 6
|
||||
corner_radius_top_right = 6
|
||||
corner_radius_bottom_right = 6
|
||||
corner_radius_bottom_left = 6
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ouso4"]
|
||||
content_margin_left = 6.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 6.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.04, 0.07, 0.09, 0.82)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.43, 0.78, 0.88, 0.95)
|
||||
corner_radius_top_left = 6
|
||||
corner_radius_top_right = 6
|
||||
corner_radius_bottom_right = 6
|
||||
corner_radius_bottom_left = 6
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_blune"]
|
||||
content_margin_left = 6.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 6.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.04, 0.07, 0.09, 0.82)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.43, 0.78, 0.88, 0.95)
|
||||
corner_radius_top_left = 6
|
||||
corner_radius_top_right = 6
|
||||
corner_radius_bottom_right = 6
|
||||
corner_radius_bottom_left = 6
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_th5th"]
|
||||
content_margin_left = 6.0
|
||||
content_margin_top = 4.0
|
||||
content_margin_right = 6.0
|
||||
content_margin_bottom = 4.0
|
||||
bg_color = Color(0.04, 0.07, 0.09, 0.82)
|
||||
border_width_left = 2
|
||||
border_width_top = 2
|
||||
border_width_right = 2
|
||||
border_width_bottom = 2
|
||||
border_color = Color(0.43, 0.78, 0.88, 0.95)
|
||||
corner_radius_top_left = 6
|
||||
corner_radius_top_right = 6
|
||||
corner_radius_bottom_right = 6
|
||||
corner_radius_bottom_left = 6
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_7smn1"]
|
||||
bg_color = Color(0.12, 0.08, 0.08, 0.86)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.6, 0.12, 0.16, 0.95)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_raeie"]
|
||||
bg_color = Color(0.86, 0.11, 0.18, 1)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hxu8e"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_nvumn"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_ou6is"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_necax"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_r4lks"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pg34l"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_m4h2d"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_p8abn"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_s17dp"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_37hlw"]
|
||||
bg_color = Color(0.18, 0.66, 0.95, 1)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.66, 0.92, 1, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_charge_bg"]
|
||||
bg_color = Color(0.08, 0.07, 0.12, 0.86)
|
||||
border_width_left = 1
|
||||
border_width_top = 1
|
||||
border_width_right = 1
|
||||
border_width_bottom = 1
|
||||
border_color = Color(0.42, 0.36, 0.75, 0.9)
|
||||
|
||||
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_charge_fill"]
|
||||
bg_color = Color(0.92, 0.72, 0.25, 1)
|
||||
|
||||
[node name="Main" type="Node2D" unique_id=596674982]
|
||||
script = ExtResource("3_main_script")
|
||||
|
||||
@@ -190,3 +356,195 @@ theme_override_font_sizes/font_size = 24
|
||||
text = "READY"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="ComboWindow" type="HBoxContainer" parent="RhythmFeedback" unique_id=1940360666]
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -148.0
|
||||
offset_top = 222.0
|
||||
offset_right = 148.0
|
||||
offset_bottom = 282.0
|
||||
pivot_offset = Vector2(148, 30)
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="Slot0" type="PanelContainer" parent="RhythmFeedback/ComboWindow" unique_id=181099068]
|
||||
modulate = Color(1, 1, 1, 0.45)
|
||||
custom_minimum_size = Vector2(64, 56)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_a8run")
|
||||
|
||||
[node name="Key" type="Label" parent="RhythmFeedback/ComboWindow/Slot0" unique_id=1605416584]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_colors/font_color = Color(0.94, 0.98, 1, 1)
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.9)
|
||||
theme_override_constants/shadow_offset_x = 2
|
||||
theme_override_constants/shadow_offset_y = 2
|
||||
theme_override_font_sizes/font_size = 26
|
||||
text = "·"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Slot1" type="PanelContainer" parent="RhythmFeedback/ComboWindow" unique_id=1398681506]
|
||||
modulate = Color(1, 1, 1, 0.45)
|
||||
custom_minimum_size = Vector2(64, 56)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ouso4")
|
||||
|
||||
[node name="Key" type="Label" parent="RhythmFeedback/ComboWindow/Slot1" unique_id=1841250488]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_colors/font_color = Color(0.94, 0.98, 1, 1)
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.9)
|
||||
theme_override_constants/shadow_offset_x = 2
|
||||
theme_override_constants/shadow_offset_y = 2
|
||||
theme_override_font_sizes/font_size = 26
|
||||
text = "·"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Slot2" type="PanelContainer" parent="RhythmFeedback/ComboWindow" unique_id=22762864]
|
||||
modulate = Color(1, 1, 1, 0.45)
|
||||
custom_minimum_size = Vector2(64, 56)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_blune")
|
||||
|
||||
[node name="Key" type="Label" parent="RhythmFeedback/ComboWindow/Slot2" unique_id=470444619]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_colors/font_color = Color(0.94, 0.98, 1, 1)
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.9)
|
||||
theme_override_constants/shadow_offset_x = 2
|
||||
theme_override_constants/shadow_offset_y = 2
|
||||
theme_override_font_sizes/font_size = 26
|
||||
text = "·"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="Slot3" type="PanelContainer" parent="RhythmFeedback/ComboWindow" unique_id=669931458]
|
||||
modulate = Color(1, 1, 1, 0.45)
|
||||
custom_minimum_size = Vector2(64, 56)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_th5th")
|
||||
|
||||
[node name="Key" type="Label" parent="RhythmFeedback/ComboWindow/Slot3" unique_id=1939775423]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
theme_override_colors/font_color = Color(0.94, 0.98, 1, 1)
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.9)
|
||||
theme_override_constants/shadow_offset_x = 2
|
||||
theme_override_constants/shadow_offset_y = 2
|
||||
theme_override_font_sizes/font_size = 26
|
||||
text = "·"
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="ComboSkillLabel" type="Label" parent="RhythmFeedback" unique_id=246366341]
|
||||
anchors_preset = 5
|
||||
anchor_left = 0.5
|
||||
anchor_right = 0.5
|
||||
offset_left = -240.0
|
||||
offset_top = 286.0
|
||||
offset_right = 240.0
|
||||
offset_bottom = 322.0
|
||||
theme_override_colors/font_color = Color(1, 0.84, 0.26, 1)
|
||||
theme_override_colors/font_shadow_color = Color(0, 0, 0, 0.85)
|
||||
theme_override_constants/shadow_offset_x = 2
|
||||
theme_override_constants/shadow_offset_y = 2
|
||||
theme_override_font_sizes/font_size = 18
|
||||
horizontal_alignment = 1
|
||||
vertical_alignment = 1
|
||||
|
||||
[node name="StatusBars" type="VBoxContainer" parent="RhythmFeedback" unique_id=1850079775]
|
||||
offset_left = 24.0
|
||||
offset_top = 9.0
|
||||
offset_right = 294.0
|
||||
offset_bottom = 69.0
|
||||
theme_override_constants/separation = 8
|
||||
|
||||
[node name="HealthBar" type="ProgressBar" parent="RhythmFeedback/StatusBars" unique_id=562194184]
|
||||
custom_minimum_size = Vector2(270, 18)
|
||||
layout_mode = 2
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_7smn1")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_raeie")
|
||||
value = 100.0
|
||||
show_percentage = false
|
||||
|
||||
[node name="EnergyBar" type="HBoxContainer" parent="RhythmFeedback/StatusBars" unique_id=353280285]
|
||||
custom_minimum_size = Vector2(270, 16)
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 4
|
||||
|
||||
[node name="Segment0" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1721101704]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_hxu8e")
|
||||
|
||||
[node name="Segment1" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=2071238510]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_nvumn")
|
||||
|
||||
[node name="Segment2" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=820288176]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_ou6is")
|
||||
|
||||
[node name="Segment3" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1809879636]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_necax")
|
||||
|
||||
[node name="Segment4" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=205364545]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_r4lks")
|
||||
|
||||
[node name="Segment5" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1414251865]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_pg34l")
|
||||
|
||||
[node name="Segment6" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1626363537]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_m4h2d")
|
||||
|
||||
[node name="Segment7" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1577127808]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_p8abn")
|
||||
|
||||
[node name="Segment8" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1597873707]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_s17dp")
|
||||
|
||||
[node name="Segment9" type="Panel" parent="RhythmFeedback/StatusBars/EnergyBar" unique_id=1260417702]
|
||||
modulate = Color(1, 1, 1, 0.38)
|
||||
custom_minimum_size = Vector2(23, 16)
|
||||
layout_mode = 2
|
||||
theme_override_styles/panel = SubResource("StyleBoxFlat_37hlw")
|
||||
|
||||
[node name="ChargeBar" type="ProgressBar" parent="RhythmFeedback/StatusBars" unique_id=674131167]
|
||||
modulate = Color(1, 1, 1, 0.45)
|
||||
custom_minimum_size = Vector2(270, 10)
|
||||
layout_mode = 2
|
||||
theme_override_styles/background = SubResource("StyleBoxFlat_charge_bg")
|
||||
theme_override_styles/fill = SubResource("StyleBoxFlat_charge_fill")
|
||||
max_value = 1.1
|
||||
show_percentage = false
|
||||
|
||||
Reference in New Issue
Block a user