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 ## Creates a TweenChannel which arbitrates by yielding. static func make_yielding() -> TweenChannel: return new(ArbitrationMode.YIELD) ## Creates a TweenChannel which arbitrates by replacing. static func make_replacing() -> TweenChannel: return new(ArbitrationMode.REPLACE) ## Creates a TweenChannel which arbitrates by ignoring. static func make_ignoring() -> TweenChannel: return new(ArbitrationMode.IGNORE) ## 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: if what and what.is_valid(): 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)