Files
rthythm_archor_game/scenes/combat/contact_fx_spawner.gd
T
2026-07-06 22:59:47 -07:00

75 lines
3.1 KiB
GDScript

class_name ContactFxSpawner
extends Node
const OneShotFxScript := preload("res://scenes/combat/one_shot_fx.gd")
const CONTACT_SPECS := {
&"basic_1": {"path": "res://assets/art/characters/player/01_basic_attack_i/enemy_contact_fx.png", "hframes": 7, "vframes": 1, "first": 0, "last": 6, "fps": 20.0},
&"basic_2": {"path": "res://assets/art/characters/player/02_basic_attack_ii/enemy_contact_fx.png", "hframes": 7, "vframes": 1, "first": 0, "last": 6, "fps": 20.0},
&"basic_3": {"path": "res://assets/art/characters/player/03_basic_attack_iii/enemy_contact_fx.png", "hframes": 7, "vframes": 1, "first": 0, "last": 6, "fps": 20.0},
&"finisher": {"path": "res://assets/art/characters/player/05_combo_finisher/enemy_contact_fx.png", "hframes": 7, "vframes": 1, "first": 0, "last": 6, "fps": 20.0},
&"projectile": {"path": "res://assets/art/characters/player/11_blade_wave/projectile_enemy_contact.png", "hframes": 5, "vframes": 1, "first": 0, "last": 4, "fps": 20.0, "scale": 0.7},
}
func _ready() -> void:
var bus := _event_bus_or_null()
if bus != null and bus.has_signal("hit_confirmed") and not bus.is_connected("hit_confirmed", _on_hit_confirmed):
bus.connect("hit_confirmed", _on_hit_confirmed)
func _exit_tree() -> void:
var bus := _event_bus_or_null()
if bus != null and bus.has_signal("hit_confirmed") and bus.is_connected("hit_confirmed", _on_hit_confirmed):
bus.disconnect("hit_confirmed", _on_hit_confirmed)
func _on_hit_confirmed(result: Dictionary) -> void:
if int(result.get("damage", 0)) <= 0:
return
var emitter := result.get("emitter", null) as Area2D
var receiver := result.get("receiver", null) as Area2D
if emitter == null or receiver == null or not is_instance_valid(emitter) or not is_instance_valid(receiver):
return
if not _is_our_hit(emitter):
return
var target := receiver.get_parent() as Node2D
if target == null:
return
var spec: Dictionary = CONTACT_SPECS.get(_spec_key_for(result), {})
if spec.is_empty():
return
var config := spec.duplicate()
var from := result.get("from", target.global_position) as Vector2
config["flip_h"] = from.x > target.global_position.x
OneShotFxScript.spawn(target, target.global_position + Vector2(0.0, -70.0), config)
func _is_our_hit(emitter: Area2D) -> bool:
var actor := get_parent()
if actor != null and emitter.get_parent() == actor:
return true
return emitter.is_in_group("player_projectiles")
func _spec_key_for(result: Dictionary) -> StringName:
if StringName(str(result.get("hit_type", &""))) == &"projectile":
return &"projectile"
var action: Resource = result.get("action", null) as Resource
if action == null:
return &"basic_1"
var action_id := str(action.get("id"))
if action_id.begins_with("ground_attack") and action_id.ends_with("_2"):
return &"basic_2"
if action_id.begins_with("ground_attack") and action_id.ends_with("_3"):
return &"basic_3"
if action_id.begins_with("combo_finisher") or action_id.begins_with("ground_smash"):
return &"finisher"
return &"basic_1"
func _event_bus_or_null() -> Node:
if not is_inside_tree():
return null
return get_tree().root.get_node_or_null("EventBus")