From 143719467788f622122555b9d741c2db437468c2 Mon Sep 17 00:00:00 2001 From: blujai831 Date: Sat, 6 Jan 2024 13:09:18 -0800 Subject: [PATCH] Implemented TweenChannel. --- util/TweenChannel.gd | 62 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 util/TweenChannel.gd diff --git a/util/TweenChannel.gd b/util/TweenChannel.gd new file mode 100644 index 0000000..53f780f --- /dev/null +++ b/util/TweenChannel.gd @@ -0,0 +1,62 @@ +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. +var arbitration_mode := ArbitrationMode.YIELD +## Tween currently running if any, else null. +var current_tween: Tween = null + +## 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)