Refine combo charge controls
This commit is contained in:
@@ -24,8 +24,14 @@ var charge_ready := false
|
||||
var charge_active := false
|
||||
var _pending_combo_clear_reason := ""
|
||||
var _charge_effect_time := 0.0
|
||||
var _charge_animation_time := 0.0
|
||||
var _charge_hold_symbol := ""
|
||||
var _charge_hold_direction := Vector2.ZERO
|
||||
var _suppressed_movement_actions := {
|
||||
"player_a": false,
|
||||
"player_d": false,
|
||||
}
|
||||
var _last_combo_input_accepted := false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -61,9 +67,11 @@ func _handle_combo_key_event(event: InputEvent) -> bool:
|
||||
return false
|
||||
if not key_event.pressed:
|
||||
if _event_matches_key(key_event, KEY_A):
|
||||
_set_movement_action_suppressed("player_a", false)
|
||||
_finish_charge_hold("A")
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_D):
|
||||
_set_movement_action_suppressed("player_d", false)
|
||||
_finish_charge_hold("D")
|
||||
return true
|
||||
return false
|
||||
@@ -71,15 +79,17 @@ func _handle_combo_key_event(event: InputEvent) -> bool:
|
||||
_submit_combo_input_from_event("W")
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_A):
|
||||
_set_movement_action_suppressed("player_a", true)
|
||||
heading = Vector2.LEFT
|
||||
var skill_id := _submit_combo_input_from_event("A")
|
||||
if skill_id == "skill_a":
|
||||
_submit_combo_input_from_event("A")
|
||||
if _last_combo_input_accepted:
|
||||
_begin_charge_hold("A", Vector2.LEFT)
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_D):
|
||||
_set_movement_action_suppressed("player_d", true)
|
||||
heading = Vector2.RIGHT
|
||||
var skill_id := _submit_combo_input_from_event("D")
|
||||
if skill_id == "skill_d":
|
||||
_submit_combo_input_from_event("D")
|
||||
if _last_combo_input_accepted:
|
||||
_begin_charge_hold("D", Vector2.RIGHT)
|
||||
return true
|
||||
elif _event_matches_key(key_event, KEY_S):
|
||||
@@ -96,7 +106,7 @@ func handle_input() -> void:
|
||||
velocity = Vector2.ZERO
|
||||
return
|
||||
_apply_horizontal_movement()
|
||||
if Input.is_action_just_pressed("jump"):
|
||||
if Input.is_action_just_pressed("jump") and not Input.is_action_just_pressed("player_space"):
|
||||
judge_rhythm_action("jump")
|
||||
if can_jump():
|
||||
start_jump()
|
||||
@@ -161,18 +171,20 @@ func submit_combo_input(symbol: String, forced_rating := "") -> String:
|
||||
|
||||
|
||||
func _record_combo_symbol(symbol: String, rhythm_action: String, forced_rating := "") -> String:
|
||||
_last_combo_input_accepted = false
|
||||
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 ""
|
||||
_last_combo_input_accepted = true
|
||||
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 ""
|
||||
_apply_skill_energy_reward(last_requested_skill_id)
|
||||
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 ""
|
||||
@@ -277,11 +289,9 @@ func _skill_displacement_direction(skill: Dictionary) -> Vector2:
|
||||
return Vector2.ZERO
|
||||
|
||||
|
||||
func _apply_energy_reward(rating_label: String) -> void:
|
||||
match rating_label:
|
||||
"perfect":
|
||||
_change_energy(2)
|
||||
"good":
|
||||
func _apply_skill_energy_reward(skill_id: String) -> void:
|
||||
match skill_id:
|
||||
"skill_a", "skill_aa", "skill_aaa", "skill_d", "skill_dd", "skill_ddd":
|
||||
_change_energy(1)
|
||||
|
||||
|
||||
@@ -332,9 +342,7 @@ func _update_charge(delta: float) -> void:
|
||||
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")
|
||||
_update_charge_animation(delta)
|
||||
charge_value = minf(charge_duration, charge_value + delta)
|
||||
charge_ready = charge_value >= charge_duration
|
||||
_update_charge_effect(delta)
|
||||
@@ -346,6 +354,8 @@ func _start_charge() -> void:
|
||||
charge_value = 0.0
|
||||
charge_ready = false
|
||||
_charge_effect_time = 0.0
|
||||
_charge_animation_time = 0.0
|
||||
_play_charge_animation("warrior_charge_intro")
|
||||
_update_charge_effect(0.0)
|
||||
_emit_charge_changed()
|
||||
|
||||
@@ -356,6 +366,7 @@ func _cancel_charge() -> void:
|
||||
charge_active = false
|
||||
charge_value = 0.0
|
||||
charge_ready = false
|
||||
_charge_animation_time = 0.0
|
||||
_set_charge_effect_visible(false)
|
||||
_emit_charge_changed()
|
||||
|
||||
@@ -378,6 +389,21 @@ func _update_charge_effect(delta: float) -> void:
|
||||
sprite.frame = int(_charge_effect_time * 12.0) % 5
|
||||
|
||||
|
||||
func _update_charge_animation(delta: float) -> void:
|
||||
_charge_animation_time += delta
|
||||
var intro_length := _animation_length("warrior_charge_intro")
|
||||
if _charge_animation_time < intro_length:
|
||||
_play_charge_animation("warrior_charge_intro")
|
||||
else:
|
||||
_play_charge_animation("warrior_charge_loop")
|
||||
|
||||
|
||||
func _play_charge_animation(animation_name: String) -> void:
|
||||
var player_animation := _get_animation_player()
|
||||
if player_animation != null and player_animation.has_animation(animation_name) and player_animation.current_animation != animation_name:
|
||||
player_animation.play(animation_name)
|
||||
|
||||
|
||||
func _set_charge_effect_visible(is_visible: bool) -> void:
|
||||
var sprite := _get_charge_effect_sprite()
|
||||
if sprite != null:
|
||||
@@ -419,9 +445,9 @@ func _apply_horizontal_movement() -> void:
|
||||
if state != State.IDLE and state != State.WALK:
|
||||
return
|
||||
var direction := 0.0
|
||||
if Input.is_action_pressed("player_a"):
|
||||
if _is_movement_action_pressed("player_a"):
|
||||
direction -= 1.0
|
||||
if Input.is_action_pressed("player_d"):
|
||||
if _is_movement_action_pressed("player_d"):
|
||||
direction += 1.0
|
||||
if direction < 0.0:
|
||||
heading = Vector2.LEFT
|
||||
@@ -430,6 +456,14 @@ func _apply_horizontal_movement() -> void:
|
||||
velocity.x = direction * speed
|
||||
|
||||
|
||||
func _set_movement_action_suppressed(action_name: String, suppressed: bool) -> void:
|
||||
_suppressed_movement_actions[action_name] = suppressed
|
||||
|
||||
|
||||
func _is_movement_action_pressed(action_name: String) -> bool:
|
||||
return Input.is_action_pressed(action_name) and not bool(_suppressed_movement_actions.get(action_name, false))
|
||||
|
||||
|
||||
func _animation_length(animation_name: String) -> float:
|
||||
var player_animation := _get_animation_player()
|
||||
if player_animation != null and player_animation.has_animation(animation_name):
|
||||
|
||||
@@ -332,9 +332,9 @@ tracks/4/keys = {
|
||||
"values": [176, 177, 178, 179, 180, 181, 182, 183]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_jk2m4"]
|
||||
resource_name = "warrior_charge_release"
|
||||
length = 1.3333334
|
||||
[sub_resource type="Animation" id="Animation_charge_intro"]
|
||||
resource_name = "warrior_charge_intro"
|
||||
length = 0.6666667
|
||||
step = 0.083333336
|
||||
tracks/0/type = "value"
|
||||
tracks/0/imported = false
|
||||
@@ -391,10 +391,141 @@ 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),
|
||||
"times": PackedFloat32Array(0, 0.083333336, 0.16666667, 0.25, 0.33333334, 0.41666666, 0.5, 0.5833333),
|
||||
"transitions": PackedFloat32Array(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]
|
||||
"values": [192, 193, 194, 195, 196, 197, 198, 199]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_charge_loop"]
|
||||
resource_name = "warrior_charge_loop"
|
||||
length = 0.33333334
|
||||
loop_mode = 1
|
||||
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),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [196, 197, 198, 199]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_jk2m4"]
|
||||
resource_name = "warrior_charge_release"
|
||||
length = 0.6666667
|
||||
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),
|
||||
"transitions": PackedFloat32Array(1, 1, 1, 1, 1, 1, 1, 1),
|
||||
"update": 1,
|
||||
"values": [200, 201, 202, 203, 204, 205, 206, 207]
|
||||
}
|
||||
|
||||
[sub_resource type="Animation" id="Animation_kqtwu"]
|
||||
@@ -730,6 +861,8 @@ _data = {
|
||||
&"warrior_a_space_space": SubResource("Animation_2l4js"),
|
||||
&"warrior_aa": SubResource("Animation_dyp2m"),
|
||||
&"warrior_aaa": SubResource("Animation_atpat"),
|
||||
&"warrior_charge_intro": SubResource("Animation_charge_intro"),
|
||||
&"warrior_charge_loop": SubResource("Animation_charge_loop"),
|
||||
&"warrior_charge_release": SubResource("Animation_jk2m4"),
|
||||
&"warrior_idle": SubResource("Animation_kqtwu"),
|
||||
&"warrior_s": SubResource("Animation_6eyoc"),
|
||||
|
||||
@@ -2,6 +2,12 @@ class_name InputResolver
|
||||
extends RefCounted
|
||||
|
||||
const SKILLS := {
|
||||
"W": {
|
||||
"type": "skill",
|
||||
"id": "skill_w",
|
||||
"animation": "warrior_w",
|
||||
"clear_window": false,
|
||||
},
|
||||
"A": {
|
||||
"type": "skill",
|
||||
"id": "skill_a",
|
||||
|
||||
Reference in New Issue
Block a user