132 lines
4.6 KiB
GDScript
132 lines
4.6 KiB
GDScript
class_name PickupBehaviorController extends Area2D
|
|
|
|
## Controls visual movement (bob, shake) and drift of a pickup.
|
|
## Attach to the root Area2D node of your pickup scene.
|
|
|
|
@export var behavior: PickupBehavior
|
|
@export var drift_behavior: PickupDriftBehavior
|
|
|
|
|
|
var _icon_node: TextureRect
|
|
var _spawn_position: Vector2 = Vector2.ZERO
|
|
|
|
|
|
func _ready() -> void:
|
|
# Find the runtime-added icon node.
|
|
for child in get_children():
|
|
if child is TextureRect:
|
|
_icon_node = child as TextureRect
|
|
break
|
|
# Capture the initial spawn position.
|
|
_spawn_position = global_position
|
|
|
|
if behavior != null:
|
|
behavior.start()
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
if behavior == null or drift_behavior == null:
|
|
return
|
|
|
|
var alpha: float = behavior.process(delta)
|
|
|
|
if _icon_node != null:
|
|
_icon_node.visible = alpha > 0.01
|
|
if behavior != null and behavior.fade_in_duration > 0 and _icon_node is CanvasItem:
|
|
_icon_node.modulate.a = alpha
|
|
|
|
var offset := _compute_animation_offset()
|
|
var drift_offset := _compute_drift_offset()
|
|
|
|
position = _spawn_position + Vector2(drift_offset.x, drift_offset.y)
|
|
|
|
if _icon_node != null:
|
|
_icon_node.position = offset
|
|
|
|
|
|
func _compute_animation_offset() -> Vector2:
|
|
# Returns the bob + shake offset applied to the icon node.
|
|
var result := Vector2.ZERO
|
|
|
|
if behavior == null:
|
|
return result
|
|
|
|
# Bob (vertical oscillation).
|
|
if behavior.bob_enabled:
|
|
var bob_angle := _elapsed_time() * TAU * behavior.bob_frequency
|
|
result.y += sin(bob_angle) * behavior.bob_amplitude
|
|
|
|
# Shake (subtle jitter).
|
|
if behavior.shake_enabled:
|
|
var shake_angle := _elapsed_time() * TAU * behavior.shake_frequency
|
|
result.x += sin(shake_angle) * behavior.shake_amplitude
|
|
|
|
return result
|
|
|
|
|
|
func _compute_drift_offset() -> Vector2:
|
|
# Returns the global drift position offset from initial spawn position.
|
|
if drift_behavior == null:
|
|
return Vector2.ZERO
|
|
|
|
match drift_behavior.drift_type:
|
|
PickupDriftBehavior.DriftType.STATIONARY:
|
|
return Vector2.ZERO
|
|
|
|
PickupDriftBehavior.DriftType.SINE_WAVE:
|
|
var t := _elapsed_time() * drift_behavior.wave_frequency
|
|
var travel_speed: float = drift_behavior.drift_speed
|
|
if drift_behavior.reverse_direction:
|
|
travel_speed *= -1.0
|
|
|
|
var offset := Vector2.ZERO
|
|
if drift_behavior.drift_along_x:
|
|
# Travels along X; waves on Y.
|
|
offset.x = travel_speed * _elapsed_time()
|
|
offset.y = sin(t + drift_behavior.phase_offset) * drift_behavior.wave_amplitude
|
|
else:
|
|
# Travels along Y; waves on X.
|
|
offset.y = travel_speed * _elapsed_time()
|
|
offset.x = sin(t + drift_behavior.phase_offset) * drift_behavior.wave_amplitude
|
|
return offset
|
|
|
|
PickupDriftBehavior.DriftType.LEAF_FALL:
|
|
var leaf_t := _elapsed_time() * drift_behavior.wave_frequency
|
|
var travel_speed: float = drift_behavior.fall_speed
|
|
if drift_behavior.reverse_direction:
|
|
travel_speed *= -1.0
|
|
|
|
var offset := Vector2.ZERO
|
|
if drift_behavior.drift_along_x:
|
|
# Travels along X; waves on Y.
|
|
offset.x = travel_speed * _elapsed_time()
|
|
offset.y = sin(leaf_t + drift_behavior.phase_offset) * drift_behavior.wave_amplitude
|
|
else:
|
|
# Travels along Y; waves on X.
|
|
offset.y = travel_speed * _elapsed_time()
|
|
offset.x = sin(leaf_t + drift_behavior.phase_offset) * drift_behavior.wave_amplitude
|
|
return offset
|
|
|
|
PickupDriftBehavior.DriftType.DIAGONAL:
|
|
var dir: float = 1.0 if drift_behavior.diagonal_forward else -1.0
|
|
if drift_behavior.reverse_direction:
|
|
dir *= -1.0
|
|
|
|
var offset := Vector2.ZERO
|
|
if drift_behavior.drift_along_x:
|
|
# Travels along X; secondary on Y.
|
|
offset.x = dir * drift_behavior.drift_speed * _elapsed_time()
|
|
offset.y = dir * (drift_behavior.drift_speed * 0.5) * _elapsed_time()
|
|
else:
|
|
# Travels along Y; secondary on X.
|
|
offset.y = dir * drift_behavior.drift_speed * _elapsed_time()
|
|
offset.x = dir * (drift_behavior.drift_speed * 0.5) * _elapsed_time()
|
|
return offset
|
|
|
|
return Vector2.ZERO
|
|
|
|
|
|
func _elapsed_time() -> float:
|
|
if behavior == null:
|
|
return 0.0
|
|
return behavior._elapsed
|