127 lines
3.2 KiB
GDScript
127 lines
3.2 KiB
GDScript
class_name ChargeComponent
|
|
extends Node
|
|
|
|
signal charge_changed(current: float, maximum: float, charge_ready: bool, active: bool)
|
|
signal release_requested(skill_id: StringName, direction: Vector2)
|
|
|
|
@export var charge_duration := 1.1
|
|
@export var animation_player_path: NodePath
|
|
@export var effect_sprite_path: NodePath
|
|
|
|
var value := 0.0
|
|
var charge_ready := false
|
|
var active := false
|
|
|
|
var _hold_symbol: StringName = &""
|
|
var _hold_direction := Vector2.ZERO
|
|
var _effect_time := 0.0
|
|
var _animation_time := 0.0
|
|
|
|
@onready var _animation_player: AnimationPlayer = get_node_or_null(animation_player_path) as AnimationPlayer
|
|
@onready var _effect_sprite: Sprite2D = get_node_or_null(effect_sprite_path) as Sprite2D
|
|
|
|
|
|
func begin_hold(symbol: StringName, direction: Vector2) -> void:
|
|
_hold_symbol = symbol
|
|
_hold_direction = direction
|
|
|
|
|
|
func finish_hold(symbol: StringName) -> void:
|
|
if _hold_symbol != symbol:
|
|
return
|
|
var release_ready := active and charge_ready
|
|
var release_direction := _hold_direction
|
|
var release_skill := &"skill_a_charge_release" if symbol == &"A" else &"skill_d_charge_release"
|
|
cancel()
|
|
if release_ready:
|
|
release_requested.emit(release_skill, release_direction)
|
|
|
|
|
|
func tick(delta: float, can_charge: bool) -> void:
|
|
if _hold_symbol.is_empty():
|
|
return
|
|
if not active:
|
|
if not can_charge:
|
|
return
|
|
_start()
|
|
if not active:
|
|
return
|
|
_update_charge_animation(delta)
|
|
value = minf(charge_duration, value + delta)
|
|
charge_ready = value >= charge_duration
|
|
_update_charge_effect(delta)
|
|
_emit_changed()
|
|
|
|
|
|
func cancel() -> void:
|
|
_hold_symbol = &""
|
|
_hold_direction = Vector2.ZERO
|
|
active = false
|
|
value = 0.0
|
|
charge_ready = false
|
|
_animation_time = 0.0
|
|
_set_effect_visible(false)
|
|
_emit_changed()
|
|
|
|
|
|
func is_active() -> bool:
|
|
return active
|
|
|
|
|
|
func is_ready() -> bool:
|
|
return charge_ready
|
|
|
|
|
|
func maximum() -> float:
|
|
return charge_duration
|
|
|
|
|
|
func _start() -> void:
|
|
active = true
|
|
value = 0.0
|
|
charge_ready = false
|
|
_effect_time = 0.0
|
|
_animation_time = 0.0
|
|
_play_charge_animation(&"warrior_charge_intro")
|
|
_update_charge_effect(0.0)
|
|
_emit_changed()
|
|
|
|
|
|
func _update_charge_effect(delta: float) -> void:
|
|
if _effect_sprite == null:
|
|
return
|
|
_effect_sprite.visible = active
|
|
if not active:
|
|
return
|
|
_effect_time += delta
|
|
_effect_sprite.frame = int(_effect_time * 12.0) % 5
|
|
|
|
|
|
func _update_charge_animation(delta: float) -> void:
|
|
_animation_time += delta
|
|
var intro_length := _animation_length(&"warrior_charge_intro")
|
|
if _animation_time < intro_length:
|
|
_play_charge_animation(&"warrior_charge_intro")
|
|
else:
|
|
_play_charge_animation(&"warrior_charge_loop")
|
|
|
|
|
|
func _play_charge_animation(animation_name: StringName) -> void:
|
|
if _animation_player != null and _animation_player.has_animation(animation_name) and _animation_player.current_animation != animation_name:
|
|
_animation_player.play(animation_name)
|
|
|
|
|
|
func _animation_length(animation_name: StringName) -> float:
|
|
if _animation_player != null and _animation_player.has_animation(animation_name):
|
|
return maxf(0.1, _animation_player.get_animation(animation_name).length)
|
|
return 0.1
|
|
|
|
|
|
func _set_effect_visible(is_visible: bool) -> void:
|
|
if _effect_sprite != null:
|
|
_effect_sprite.visible = is_visible
|
|
|
|
|
|
func _emit_changed() -> void:
|
|
charge_changed.emit(value, charge_duration, charge_ready, active)
|