facsimile-wing/scripts/effects/blinker_effect.gd

90 lines
3.2 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

class_name BlinkerEffect
extends BaseEffect
## How many blink cycles per second.
@export_range(0.0, 60.0) var blink_frequency: float = 8.0
## Fraction of each cycle the sprite is visible (0.01.0).
@export_range(0.0, 1.0) var blink_length: float = 0.5
## Minimum alpha when "off" (0.0 = fully invisible, 1.0 = fully visible).
@export_range(0.0, 1.0) var min_alpha: float = 0.0
## Maximum alpha when "on" (0.01.0).
@export_range(0.0, 1.0) var max_alpha: float = 1.0
## Duration of the fade-in at the start of the effect (seconds).
@export_range(0.0, 5.0) var start_ease: float = 0.0
## Easing curve for the fade-in.
@export_enum("Linear", "Smooth", "Ease-In", "Ease-Out", "Ease-In-Out") var start_ease_mode: int = 1
## Duration of the fade-out at the end of the effect (seconds).
@export_range(0.0, 5.0) var end_ease: float = 0.0
## Easing curve for the fade-out.
@export_enum("Linear", "Smooth", "Ease-In", "Ease-Out", "Ease-In-Out") var end_ease_mode: int = 1
var _original_modulate: Color
func start(target: Node) -> void:
super.start(target)
if target is CanvasItem:
_original_modulate = target.modulate
func process(delta: float, target: Node) -> void:
super.process(delta, target)
if target is CanvasItem:
var alpha: float = _compute_alpha(_elapsed)
target.modulate = Color(_original_modulate.r, _original_modulate.g, _original_modulate.b, alpha)
func stop(target: Node) -> void:
if target is CanvasItem:
target.modulate = _original_modulate
## Compute the combined eased alpha for a given elapsed time.
func _compute_alpha(elapsed: float) -> float:
if duration <= 0.0:
return 1.0
var t: float = min(elapsed, duration)
# Blink pulse: on/off cycling at the given frequency and duty cycle
var period := 1.0 / blink_frequency if blink_frequency > 0.0 else 1.0
var phase := fmod(t, period) / period
var pulse: float = min_alpha
if phase < blink_length:
var pulse_progress = phase / blink_length if blink_length > 0.0 else 1.0
if pulse_progress < 0.5:
pulse = min_alpha + (max_alpha - min_alpha) * _ease_value(pulse_progress * 2.0, 2)
else:
pulse = min_alpha + (max_alpha - min_alpha) * _ease_value((1.0 - pulse_progress) * 2.0, 3)
# Start ease: fade from fully visible into the blink pattern
if t < start_ease and start_ease > 0.0:
var fade_in = _ease_value(t / start_ease, start_ease_mode)
return lerp(max_alpha, pulse, fade_in)
# End ease: fade from blink pattern back to fully visible
if t > duration - end_ease and end_ease > 0.0:
var fade_progress = (t - (duration - end_ease)) / end_ease
var fade_out = _ease_value(fade_progress, end_ease_mode)
return lerp(pulse, max_alpha, fade_out)
return pulse
## Apply easing to a 0.01.0 normalized value based on the selected mode.
func _ease_value(value: float, mode: int) -> float:
match mode:
0: return value # Linear
1: return smoothstep(0.0, 1.0, value) # Smooth
2: return ease(value, -2.0) # Ease-In (accelerating)
3: return ease(value, 2.0) # Ease-Out (decelerating)
4: return ease(value, 3.0) # Ease-In-Out (S-curve)
return value