Add AwaitTweener
This commit is contained in:
parent
bf95b62586
commit
94f9b87063
5 changed files with 152 additions and 1 deletions
21
doc/classes/AwaitTweener.xml
Normal file
21
doc/classes/AwaitTweener.xml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="AwaitTweener" inherits="Tweener" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Awaits a specified signal.
|
||||
</brief_description>
|
||||
<description>
|
||||
[AwaitTweener] is used to await a specified signal, allowing asynchronous steps in [Tween] animation. See [method Tween.tween_await] for more usage information.
|
||||
The [signal Tweener.finished] signal is emitted when either the awaited signal is received, when timeout is reached, or when the target object is freed.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="set_timeout">
|
||||
<return type="AwaitTweener" />
|
||||
<param index="0" name="timeout" type="float" />
|
||||
<description>
|
||||
Sets the maximum time an [AwaitTweener] can wait for the signal. Can be used as a safeguard for signals that may never be emitted. If not specified, the tweener will wait indefinitely.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
</class>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
Tweens are mostly useful for animations requiring a numerical property to be interpolated over a range of values. The name [i]tween[/i] comes from [i]in-betweening[/i], an animation technique where you specify [i]keyframes[/i] and the computer interpolates the frames that appear between them. Animating something with a [Tween] is called tweening.
|
||||
[Tween] is more suited than [AnimationPlayer] for animations where you don't know the final values in advance. For example, interpolating a dynamically-chosen camera zoom value is best done with a [Tween]; it would be difficult to do the same thing with an [AnimationPlayer] node. Tweens are also more light-weight than [AnimationPlayer], so they are very much suited for simple animations or general tasks that don't require visual tweaking provided by the editor. They can be used in a "fire-and-forget" manner for some logic that normally would be done by code. You can e.g. make something shoot periodically by using a looped [CallbackTweener] with a delay.
|
||||
A [Tween] can be created by using either [method SceneTree.create_tween] or [method Node.create_tween]. [Tween]s created manually (i.e. by using [code]Tween.new()[/code]) are invalid and can't be used for tweening values.
|
||||
A tween animation is created by adding [Tweener]s to the [Tween] object, using [method tween_property], [method tween_interval], [method tween_callback] or [method tween_method]:
|
||||
A tween animation is created by adding [Tweener]s to the [Tween] object, using [method tween_property], [method tween_interval], [method tween_callback], [method tween_method], [method tween_subtween], or [method tween_await]:
|
||||
[codeblocks]
|
||||
[gdscript]
|
||||
var tween = get_tree().create_tween()
|
||||
|
|
@ -317,6 +317,37 @@
|
|||
[b]Note:[/b] If a Tween is stopped and not bound to any node, it will exist indefinitely until manually started or invalidated. If you lose a reference to such Tween, you can retrieve it using [method SceneTree.get_processed_tweens].
|
||||
</description>
|
||||
</method>
|
||||
<method name="tween_await">
|
||||
<return type="AwaitTweener" />
|
||||
<param index="0" name="signal" type="Signal" />
|
||||
<description>
|
||||
Creates and appends an [AwaitTweener]. This method can be used to await a signal to be emitted and create asynchronous animations or cutscenes.
|
||||
The animation will not progress to the next step until the awaited signal is emitted or the connection becomes invalid (e.g. as a result of freeing the target object). If you know that the emission may not happen, use [method AwaitTweener.set_timeout].
|
||||
[b]Note:[/b] The awaited signal should be emitted during the step when [AwaitTweener] is active.
|
||||
[b]Example:[/b] An object launches itself and explodes upon collision or after 4 seconds.
|
||||
[codeblock]
|
||||
var tween = create_tween()
|
||||
tween.tween_callback(launch)
|
||||
tween.tween_await(collided).set_timeout(4.0)
|
||||
tween.tween_callback(explode)
|
||||
[/codeblock]
|
||||
[b]Example:[/b] A character walks to a specific point, says some lines and walks back when the player closes the message box.
|
||||
[codeblock]
|
||||
var tween = create_tween()
|
||||
tween.tween_callback(walk_to.bind(600.0))
|
||||
tween.tween_await(destination_reached)
|
||||
tween.tween_callback(say_dialogue.bind("Good day, sir!"))
|
||||
tween.tween_await(dialogue_closed)
|
||||
tween.tween_callback(walk_to.bind(0.0))
|
||||
[/codeblock]
|
||||
[b]Note:[/b] If you are awaiting a signal from a callback called in the same [Tween], make sure the signal is emitted [i]after[/i] the await starts. If it can't be reasonably guaranteed, you can await and emit in the same step:
|
||||
[codeblock]
|
||||
var tween = create_tween()
|
||||
tween.tween_await(signal)
|
||||
tween.parallel().tween_callback(method_that_emits_signal)
|
||||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="tween_callback">
|
||||
<return type="CallbackTweener" />
|
||||
<param index="0" name="callback" type="Callable" />
|
||||
|
|
|
|||
|
|
@ -169,6 +169,14 @@ RequiredResult<SubtweenTweener> Tween::tween_subtween(RequiredParam<Tween> rp_su
|
|||
return tweener;
|
||||
}
|
||||
|
||||
RequiredResult<AwaitTweener> Tween::tween_await(const Signal &p_signal) {
|
||||
CHECK_VALID();
|
||||
|
||||
Ref<AwaitTweener> tweener = memnew(AwaitTweener(p_signal));
|
||||
append(tweener);
|
||||
return tweener;
|
||||
}
|
||||
|
||||
void Tween::append(Ref<Tweener> p_tweener) {
|
||||
p_tweener->set_tween(this);
|
||||
|
||||
|
|
@ -474,6 +482,7 @@ void Tween::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("tween_callback", "callback"), &Tween::tween_callback);
|
||||
ClassDB::bind_method(D_METHOD("tween_method", "method", "from", "to", "duration"), &Tween::tween_method);
|
||||
ClassDB::bind_method(D_METHOD("tween_subtween", "subtween"), &Tween::tween_subtween);
|
||||
ClassDB::bind_method(D_METHOD("tween_await", "signal"), &Tween::tween_await);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("custom_step", "delta"), &Tween::custom_step);
|
||||
ClassDB::bind_method(D_METHOD("stop"), &Tween::stop);
|
||||
|
|
@ -928,3 +937,63 @@ SubtweenTweener::SubtweenTweener(const Ref<Tween> &p_subtween) {
|
|||
SubtweenTweener::SubtweenTweener() {
|
||||
ERR_FAIL_MSG("SubtweenTweener can't be created directly. Use the tween_subtween() method in Tween.");
|
||||
}
|
||||
|
||||
Ref<AwaitTweener> AwaitTweener::set_timeout(double p_timeout) {
|
||||
timeout = p_timeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
void AwaitTweener::start() {
|
||||
Tweener::start();
|
||||
received = false;
|
||||
}
|
||||
|
||||
bool AwaitTweener::step(double &r_delta) {
|
||||
if (finished) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!signal.get_object() || !signal.is_connected(target_callable)) { // In case the object was destroyed before emitting.
|
||||
_finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
elapsed_time += r_delta;
|
||||
|
||||
if (timeout >= 0 && elapsed_time >= timeout) {
|
||||
_finish();
|
||||
r_delta = elapsed_time - timeout;
|
||||
return false;
|
||||
}
|
||||
|
||||
r_delta = 0; // "Consume" all remaining time to prevent infinite loops.
|
||||
if (received) {
|
||||
_finish();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
AwaitTweener::AwaitTweener(const Signal &p_signal) {
|
||||
signal = p_signal;
|
||||
target_callable = Callable(this, SNAME("_signal_callback"));
|
||||
signal.connect(target_callable);
|
||||
|
||||
Object *signal_instance = p_signal.get_object();
|
||||
if (signal_instance && signal_instance->is_ref_counted()) {
|
||||
ref_copy = signal_instance;
|
||||
}
|
||||
}
|
||||
|
||||
AwaitTweener::AwaitTweener() {
|
||||
ERR_FAIL_MSG("AwaitTweener can't be created directly. Use the tween_await() method in Tween.");
|
||||
}
|
||||
|
||||
void AwaitTweener::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_timeout", "timeout"), &AwaitTweener::set_timeout);
|
||||
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "_signal_callback", &AwaitTweener::_signal_received, MethodInfo("_signal_callback"));
|
||||
}
|
||||
|
||||
void AwaitTweener::_signal_received(const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
|
||||
received = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ class IntervalTweener;
|
|||
class CallbackTweener;
|
||||
class MethodTweener;
|
||||
class SubtweenTweener;
|
||||
class AwaitTweener;
|
||||
|
||||
class Tween : public RefCounted {
|
||||
GDCLASS(Tween, RefCounted);
|
||||
|
|
@ -148,6 +149,7 @@ public:
|
|||
RequiredResult<CallbackTweener> tween_callback(const Callable &p_callback);
|
||||
RequiredResult<MethodTweener> tween_method(const Callable &p_callback, const Variant p_from, Variant p_to, double p_duration);
|
||||
RequiredResult<SubtweenTweener> tween_subtween(RequiredParam<Tween> rp_subtween);
|
||||
RequiredResult<AwaitTweener> tween_await(const Signal &p_signal);
|
||||
void append(Ref<Tweener> p_tweener);
|
||||
|
||||
bool custom_step(double p_delta);
|
||||
|
|
@ -326,3 +328,30 @@ protected:
|
|||
private:
|
||||
double delay = 0;
|
||||
};
|
||||
|
||||
class AwaitTweener : public Tweener {
|
||||
GDCLASS(AwaitTweener, Tweener);
|
||||
|
||||
public:
|
||||
Ref<AwaitTweener> set_timeout(double p_timeout);
|
||||
|
||||
void start() override;
|
||||
bool step(double &r_delta) override;
|
||||
|
||||
AwaitTweener(const Signal &p_signal);
|
||||
AwaitTweener();
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
Signal signal;
|
||||
Callable target_callable;
|
||||
bool received = false;
|
||||
|
||||
double timeout = -1;
|
||||
|
||||
void _signal_received(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
|
||||
Ref<RefCounted> ref_copy;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -582,6 +582,7 @@ void register_scene_types() {
|
|||
GDREGISTER_CLASS(CallbackTweener);
|
||||
GDREGISTER_CLASS(MethodTweener);
|
||||
GDREGISTER_CLASS(SubtweenTweener);
|
||||
GDREGISTER_CLASS(AwaitTweener);
|
||||
|
||||
GDREGISTER_ABSTRACT_CLASS(AnimationMixer);
|
||||
GDREGISTER_CLASS(AnimationPlayer);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue