Add combat combo gameplay

This commit is contained in:
wxm
2026-07-02 05:11:24 -07:00
parent 8c0c5e5067
commit 67db812de4
32 changed files with 3297 additions and 205 deletions

View 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)

View File

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

View 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()

View File

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

View 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()

View File

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