87 lines
3.0 KiB
GDScript
87 lines
3.0 KiB
GDScript
@tool
|
|
## A trigger that activates when the input is pushed down and then repeatedly sends trigger events at a fixed interval.
|
|
## Note: the trigger will be either triggering or ongoing until the input is released.
|
|
## Note: at most one pulse will be emitted per frame.
|
|
class_name GUIDETriggerPulse
|
|
extends GUIDETrigger
|
|
|
|
## If true, the trigger will trigger immediately when the input is actuated. Otherwise, the trigger will wait for the initial delay.
|
|
@export var trigger_on_start:bool = true
|
|
## The delay after the initial actuation before pulsing begins.
|
|
@export var initial_delay:float = 0.3:
|
|
set(value):
|
|
initial_delay = max(0, value)
|
|
|
|
## The interval between pulses. Set to 0 to pulse every frame.
|
|
@export var pulse_interval:float = 0.1:
|
|
set(value):
|
|
pulse_interval = max(0, value)
|
|
|
|
## Maximum number of pulses. If <= 0, the trigger will pulse indefinitely.
|
|
@export var max_pulses:int = 0
|
|
|
|
var _delay_until_next_pulse:float = 0
|
|
var _emitted_pulses:int = 0
|
|
|
|
func _update_state(input:Vector3, delta:float, value_type:GUIDEAction.GUIDEActionValueType) -> GUIDETriggerState:
|
|
if _is_actuated(input, value_type):
|
|
if not _is_actuated(_last_value, value_type):
|
|
# we went from "not actuated" to actuated, pulsing starts
|
|
_delay_until_next_pulse = initial_delay
|
|
if trigger_on_start:
|
|
return GUIDETriggerState.TRIGGERED
|
|
else:
|
|
return GUIDETriggerState.ONGOING
|
|
|
|
# if we already are pulsing and have exceeded the maximum number of pulses, we will not pulse anymore.
|
|
if max_pulses > 0 and _emitted_pulses >= max_pulses:
|
|
return GUIDETriggerState.NONE
|
|
|
|
# subtract the delta from the delay until the next pulse
|
|
_delay_until_next_pulse -= delta
|
|
|
|
if _delay_until_next_pulse > 0:
|
|
# we are still waiting for the next pulse, nothing to do.
|
|
return GUIDETriggerState.ONGOING
|
|
|
|
# now delta could be larger than our pulse, in which case we loose a few pulses.
|
|
# as we can pulse at most once per frame.
|
|
|
|
# in case someone sets the pulse interval to 0, we will pulse every frame.
|
|
if is_equal_approx(pulse_interval, 0):
|
|
_delay_until_next_pulse = 0
|
|
if max_pulses > 0:
|
|
_emitted_pulses += 1
|
|
return GUIDETriggerState.TRIGGERED
|
|
|
|
# Now add the delay until the next pulse
|
|
_delay_until_next_pulse += pulse_interval
|
|
|
|
# If the interval is really small, we can potentially have skipped some pulses
|
|
if _delay_until_next_pulse <= 0:
|
|
# we have skipped some pulses
|
|
var skipped_pulses:int = int(-_delay_until_next_pulse / pulse_interval)
|
|
_delay_until_next_pulse += skipped_pulses * pulse_interval
|
|
if max_pulses > 0:
|
|
_emitted_pulses += skipped_pulses
|
|
if _emitted_pulses >= max_pulses:
|
|
return GUIDETriggerState.NONE
|
|
|
|
# Record a pulse and return triggered
|
|
if max_pulses > 0:
|
|
_emitted_pulses += 1
|
|
return GUIDETriggerState.TRIGGERED
|
|
|
|
# if the input is not actuated, then the trigger is not triggered.
|
|
_emitted_pulses = 0
|
|
_delay_until_next_pulse = 0
|
|
return GUIDETriggerState.NONE
|
|
|
|
|
|
func _editor_name() -> String:
|
|
return "Pulse"
|
|
|
|
|
|
func _editor_description() -> String:
|
|
return "Fires at an interval while the input is actuated."
|