class_name OneShotFx extends Node2D var texture: Texture2D var hframes := 1 var vframes := 1 var first_frame := 0 var last_frame := 0 var fps := 20.0 var delay := 0.0 var duration_override := 0.0 var velocity := Vector2.ZERO var flip_h := false var sprite_scale := Vector2.ONE var sprite_offset := Vector2.ZERO var _sprite: Sprite2D var _elapsed := 0.0 static func spawn(parent: Node, spawn_global_position: Vector2, config: Dictionary) -> Node2D: if parent == null: return null var script: Script = load("res://scenes/combat/one_shot_fx.gd") var fx: Node2D = script.new() var texture_path := str(config.get("path", "")) if ResourceLoader.exists(texture_path): fx.set("texture", load(texture_path)) fx.set("hframes", maxi(1, int(config.get("hframes", 1)))) fx.set("vframes", maxi(1, int(config.get("vframes", 1)))) fx.set("first_frame", maxi(0, int(config.get("first", 0)))) fx.set("last_frame", maxi(0, int(config.get("last", 0)))) fx.set("fps", maxf(1.0, float(config.get("fps", 20.0)))) fx.set("delay", maxf(0.0, float(config.get("delay", 0.0)))) fx.set("duration_override", maxf(0.0, float(config.get("duration", 0.0)))) fx.set("velocity", config.get("velocity", Vector2.ZERO)) fx.set("flip_h", bool(config.get("flip_h", false))) var scale_value := float(config.get("scale", 1.0)) fx.set("sprite_scale", Vector2(scale_value, scale_value)) fx.set("sprite_offset", config.get("offset", Vector2.ZERO)) fx.z_index = int(config.get("z_index", 3)) parent.add_child(fx) fx.global_position = spawn_global_position return fx func _ready() -> void: if texture == null: queue_free() return _sprite = Sprite2D.new() _sprite.texture = texture _sprite.hframes = hframes _sprite.vframes = vframes _sprite.centered = true _sprite.scale = sprite_scale _sprite.offset = sprite_offset _sprite.flip_h = flip_h _sprite.frame = clampi(first_frame, 0, hframes * vframes - 1) _sprite.visible = delay <= 0.0 add_child(_sprite) func _process(delta: float) -> void: _elapsed += delta if _elapsed < delay: return if _sprite == null: queue_free() return _sprite.visible = true var play_time := _elapsed - delay position += velocity * delta var lifetime := duration_override if lifetime <= 0.0: lifetime = float(last_frame - first_frame + 1) / fps if play_time >= lifetime: queue_free() return var frame_index := first_frame + int(play_time * fps) _sprite.frame = clampi(frame_index, first_frame, mini(last_frame, hframes * vframes - 1))