76 lines
2.7 KiB
GDScript
76 lines
2.7 KiB
GDScript
class_name TweenChannel extends RefCounted
|
|
## Arbitrates between concurrent tweens, e.g. of the same property.
|
|
|
|
## Emitted when a tween finishes or is killed.
|
|
signal terminated(what: Tween)
|
|
|
|
## How to arbitrate between a tween request and an already running tween.
|
|
enum ArbitrationMode {
|
|
YIELD, ## Request yields until there is no longer any current tween.
|
|
REPLACE, ## Rather than request yielding, current tween is killed.
|
|
IGNORE ## Rather than request yielding, request is denied (returns null).
|
|
}
|
|
|
|
## How to arbitrate between a tween request and an already running tween.
|
|
##
|
|
## Takes effect only for new calls to self.create_tween,
|
|
## not in-progress calls. That is to say, if self.create_tween
|
|
## has already been called at a time when arbitration_mode was YIELD,
|
|
## and it changes while the call is yielding, then the in-progress call
|
|
## still will not return until its turn, as though arbitration_mode
|
|
## were still YIELD.
|
|
var arbitration_mode: ArbitrationMode
|
|
## Tween currently running if any, else null.
|
|
var current_tween: Tween = null
|
|
|
|
## Initializer. Sets arbitration mode.
|
|
func _init(
|
|
p_arbitration_mode: ArbitrationMode = ArbitrationMode.YIELD
|
|
) -> void:
|
|
arbitration_mode = p_arbitration_mode
|
|
|
|
## Returns target.create_tween() if and when arbitration_mode allows.
|
|
##
|
|
## "If:" if arbitration_mode is IGNORE and there is a current tween,
|
|
## then null is returned.
|
|
## "When:" if arbitration_mode is YIELD and there is a current tween,
|
|
## then this function yields until there is not.
|
|
## (If arbitration_mode is REPLACE and there is a current tween,
|
|
## then this function returns target.create_tween() immediately,
|
|
## and the preexisting current tween is killed.)
|
|
func create_tween(target: Variant) -> Tween:
|
|
assert(target is Node or target is SceneTree)
|
|
match arbitration_mode:
|
|
ArbitrationMode.YIELD:
|
|
while current_tween:
|
|
await terminated
|
|
ArbitrationMode.REPLACE:
|
|
if current_tween and current_tween.is_valid():
|
|
current_tween.kill()
|
|
ArbitrationMode.IGNORE:
|
|
if current_tween:
|
|
return null
|
|
current_tween = target.create_tween()
|
|
_cleanup_later(current_tween)
|
|
return current_tween
|
|
|
|
## Yields until the given tween has terminated.
|
|
##
|
|
## The given tween must have been created with self.create_tween.
|
|
func sync(what: Tween) -> void:
|
|
var last_terminated: Tween = null
|
|
while last_terminated != what:
|
|
last_terminated = await terminated
|
|
|
|
## Yields until the given tween is invalid and then cleans up bookkeeping.
|
|
##
|
|
## Bookkeeping cleanup entails the following:
|
|
## - if the given tween is the current tween, clears the current tween;
|
|
## - terminated is emitted with the given tween as the argument.
|
|
func _cleanup_later(what: Tween) -> void:
|
|
while what.is_valid():
|
|
await Wait.tick()
|
|
if current_tween == what:
|
|
current_tween = null
|
|
terminated.emit(what)
|