Files
KickSurvivors/scripts/KickSystem.gd
T
2026-04-23 14:57:14 +03:00

64 lines
2.9 KiB
GDScript

class_name KickSystem
# Deduplication: each (A,B) pair resolved once per physics frame
static var _frame: int = -1
static var _pairs: Dictionary = {}
# Called by a flying kickable when it detects another kickable.
# Returns true if a merge happened (both objects will despawn).
static func resolve(owner: Node3D, other: Node3D, owner_vel: Vector3) -> bool:
var f := Engine.get_physics_frames()
if f != _frame:
_frame = f
_pairs.clear()
var id_lo := mini(owner.get_instance_id(), other.get_instance_id())
var id_hi := maxi(owner.get_instance_id(), other.get_instance_id())
var key := str(id_lo) + "_" + str(id_hi)
if _pairs.has(key):
return false
_pairs[key] = true
var other_vel: Vector3 = other.get("fly_vel") if other.get("fly_vel") != null else Vector3.ZERO
var speed_a := Vector2(owner_vel.x, owner_vel.z).length()
var speed_b := Vector2(other_vel.x, other_vel.z).length()
var collision_speed := speed_a + speed_b
# ── 1. Recipe merge (MergeRecipes) ────────────────────────────────────────
var kt_a: String = owner.get("kickable_type") if owner.get("kickable_type") != null else ""
var kt_b: String = other.get("kickable_type") if other.get("kickable_type") != null else ""
if kt_a != "" and kt_b != "":
var recipe: Dictionary = MergeRecipes.find(kt_a, kt_b, collision_speed)
if not recipe.is_empty():
_execute_recipe(owner, other, recipe)
return true
# ── 2. Merge (enemy-to-enemy) ─────────────────────────────────────────────
if owner.has_method("can_merge_with") and owner.call("can_merge_with", other, collision_speed):
owner.call("do_merge_with", other)
return true
# ── 3. Damage ─────────────────────────────────────────────────────────────
var mod_a: float = owner.get("damage_modifier") if owner.get("damage_modifier") != null else 0.0
var mod_b: float = other.get("damage_modifier") if other.get("damage_modifier") != null else 0.0
if is_instance_valid(other) and other.has_method("apply_collision_damage") and mod_a > 0.0:
other.call("apply_collision_damage", collision_speed * mod_a)
if is_instance_valid(owner) and owner.has_method("apply_collision_damage") and mod_b > 0.0:
owner.call("apply_collision_damage", collision_speed * mod_b)
return false
static func _execute_recipe(a: Node3D, b: Node3D, recipe: Dictionary) -> void:
var pos := (a.global_position + b.global_position) * 0.5
var parent := a.get_parent()
a.queue_free()
b.queue_free()
var scene: PackedScene = load(recipe["result_scene"])
if scene == null or parent == null:
return
var result := scene.instantiate() as Node3D
parent.add_child(result)
result.global_position = pos
FX.merge_smoke(pos + Vector3(0, 0.3, 0), parent)