Skip to content

Commit 141fdac

Browse files
authored
Merge pull request #65188 from Mickeon/animated-texture-speed-scale
Rework AnimatedTexture's `fps` into `speed_scale`
2 parents 4287beb + 9c9c5f6 commit 141fdac

File tree

3 files changed

+43
-47
lines changed

3 files changed

+43
-47
lines changed

doc/classes/AnimatedTexture.xml

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@
55
</brief_description>
66
<description>
77
[AnimatedTexture] is a resource format for frame-based animations, where multiple textures can be chained automatically with a predefined delay for each frame. Unlike [AnimationPlayer] or [AnimatedSprite2D], it isn't a [Node], but has the advantage of being usable anywhere a [Texture2D] resource can be used, e.g. in a [TileSet].
8-
The playback of the animation is controlled by the [member fps] property as well as each frame's optional delay (see [method set_frame_delay]). The animation loops, i.e. it will restart at frame 0 automatically after playing the last frame.
8+
The playback of the animation is controlled by the [member speed_scale] property, as well as each frame's duration (see [method set_frame_duration]). The animation loops, i.e. it will restart at frame 0 automatically after playing the last frame.
99
[AnimatedTexture] currently requires all frame textures to have the same size, otherwise the bigger ones will be cropped to match the smallest one.
1010
[b]Note:[/b] AnimatedTexture doesn't support using [AtlasTexture]s. Each frame needs to be a separate [Texture2D].
1111
</description>
1212
<tutorials>
1313
</tutorials>
1414
<methods>
15-
<method name="get_frame_delay" qualifiers="const">
15+
<method name="get_frame_duration" qualifiers="const">
1616
<return type="float" />
1717
<param index="0" name="frame" type="int" />
1818
<description>
19-
Returns the given frame's delay value.
19+
Returns the given [param frame]'s duration, in seconds.
2020
</description>
2121
</method>
2222
<method name="get_frame_texture" qualifiers="const">
@@ -26,19 +26,12 @@
2626
Returns the given frame's [Texture2D].
2727
</description>
2828
</method>
29-
<method name="set_frame_delay">
29+
<method name="set_frame_duration">
3030
<return type="void" />
3131
<param index="0" name="frame" type="int" />
32-
<param index="1" name="delay" type="float" />
32+
<param index="1" name="duration" type="float" />
3333
<description>
34-
Sets an additional delay (in seconds) between this frame and the next one, that will be added to the time interval defined by [member fps]. By default, frames have no delay defined. If a delay value is defined, the final time interval between this frame and the next will be [code]1.0 / fps + delay[/code].
35-
For example, for an animation with 3 frames, 2 FPS and a frame delay on the second frame of 1.2, the resulting playback will be:
36-
[codeblock]
37-
Frame 0: 0.5 s (1 / fps)
38-
Frame 1: 1.7 s (1 / fps + 1.2)
39-
Frame 2: 0.5 s (1 / fps)
40-
Total duration: 2.7 s
41-
[/codeblock]
34+
Sets the duration of any given [param frame]. The final duration is affected by the [member speed_scale]. If set to [code]0[/code], the frame is skipped during playback.
4235
</description>
4336
</method>
4437
<method name="set_frame_texture">
@@ -55,10 +48,6 @@
5548
<member name="current_frame" type="int" setter="set_current_frame" getter="get_current_frame">
5649
Sets the currently visible frame of the texture.
5750
</member>
58-
<member name="fps" type="float" setter="set_fps" getter="get_fps" default="4.0">
59-
Animation speed in frames per second. This value defines the default time interval between two frames of the animation, and thus the overall duration of the animation loop based on the [member frames] property. A value of 0 means no predefined number of frames per second, the animation will play according to each frame's frame delay (see [method set_frame_delay]).
60-
For example, an animation with 8 frames, no frame delay and a [code]fps[/code] value of 2 will run for 4 seconds, with each frame lasting 0.5 seconds.
61-
</member>
6251
<member name="frames" type="int" setter="set_frames" getter="get_frames" default="1">
6352
Number of frames to use in the animation. While you can create the frames independently with [method set_frame_texture], you need to set this value for the animation to take new frames into account. The maximum number of frames is [constant MAX_FRAMES].
6453
</member>
@@ -68,6 +57,9 @@
6857
<member name="pause" type="bool" setter="set_pause" getter="get_pause" default="false">
6958
If [code]true[/code], the animation will pause where it currently is (i.e. at [member current_frame]). The animation will continue from where it was paused when changing this property to [code]false[/code].
7059
</member>
60+
<member name="speed_scale" type="float" setter="set_speed_scale" getter="get_speed_scale" default="1.0">
61+
The animation speed is multiplied by this value. If set to a negative value, the animation is played in reverse.
62+
</member>
7163
</members>
7264
<constants>
7365
<constant name="MAX_FRAMES" value="256">

scene/resources/texture.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,26 +2617,30 @@ void AnimatedTexture::_update_proxy() {
26172617

26182618
time += delta;
26192619

2620-
float limit;
2621-
2622-
if (fps == 0) {
2623-
limit = 0;
2624-
} else {
2625-
limit = 1.0 / fps;
2626-
}
2620+
float speed = speed_scale == 0 ? 0 : abs(1.0 / speed_scale);
26272621

26282622
int iter_max = frame_count;
26292623
while (iter_max && !pause) {
2630-
float frame_limit = limit + frames[current_frame].delay_sec;
2624+
float frame_limit = frames[current_frame].duration * speed;
26312625

26322626
if (time > frame_limit) {
2633-
current_frame++;
2627+
if (speed_scale > 0.0) {
2628+
current_frame++;
2629+
} else {
2630+
current_frame--;
2631+
}
26342632
if (current_frame >= frame_count) {
26352633
if (one_shot) {
26362634
current_frame = frame_count - 1;
26372635
} else {
26382636
current_frame = 0;
26392637
}
2638+
} else if (current_frame < 0) {
2639+
if (one_shot) {
2640+
current_frame = 0;
2641+
} else {
2642+
current_frame = frame_count - 1;
2643+
}
26402644
}
26412645
time -= frame_limit;
26422646

@@ -2710,30 +2714,30 @@ Ref<Texture2D> AnimatedTexture::get_frame_texture(int p_frame) const {
27102714
return frames[p_frame].texture;
27112715
}
27122716

2713-
void AnimatedTexture::set_frame_delay(int p_frame, float p_delay_sec) {
2717+
void AnimatedTexture::set_frame_duration(int p_frame, float p_duration) {
27142718
ERR_FAIL_INDEX(p_frame, MAX_FRAMES);
27152719

27162720
RWLockRead r(rw_lock);
27172721

2718-
frames[p_frame].delay_sec = p_delay_sec;
2722+
frames[p_frame].duration = p_duration;
27192723
}
27202724

2721-
float AnimatedTexture::get_frame_delay(int p_frame) const {
2725+
float AnimatedTexture::get_frame_duration(int p_frame) const {
27222726
ERR_FAIL_INDEX_V(p_frame, MAX_FRAMES, 0);
27232727

27242728
RWLockRead r(rw_lock);
27252729

2726-
return frames[p_frame].delay_sec;
2730+
return frames[p_frame].duration;
27272731
}
27282732

2729-
void AnimatedTexture::set_fps(float p_fps) {
2730-
ERR_FAIL_COND(p_fps < 0 || p_fps >= 1000);
2733+
void AnimatedTexture::set_speed_scale(float p_scale) {
2734+
ERR_FAIL_COND(p_scale < -1000 || p_scale >= 1000);
27312735

2732-
fps = p_fps;
2736+
speed_scale = p_scale;
27332737
}
27342738

2735-
float AnimatedTexture::get_fps() const {
2736-
return fps;
2739+
float AnimatedTexture::get_speed_scale() const {
2740+
return speed_scale;
27372741
}
27382742

27392743
int AnimatedTexture::get_width() const {
@@ -2812,24 +2816,24 @@ void AnimatedTexture::_bind_methods() {
28122816
ClassDB::bind_method(D_METHOD("set_one_shot", "one_shot"), &AnimatedTexture::set_one_shot);
28132817
ClassDB::bind_method(D_METHOD("get_one_shot"), &AnimatedTexture::get_one_shot);
28142818

2815-
ClassDB::bind_method(D_METHOD("set_fps", "fps"), &AnimatedTexture::set_fps);
2816-
ClassDB::bind_method(D_METHOD("get_fps"), &AnimatedTexture::get_fps);
2819+
ClassDB::bind_method(D_METHOD("set_speed_scale", "scale"), &AnimatedTexture::set_speed_scale);
2820+
ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedTexture::get_speed_scale);
28172821

28182822
ClassDB::bind_method(D_METHOD("set_frame_texture", "frame", "texture"), &AnimatedTexture::set_frame_texture);
28192823
ClassDB::bind_method(D_METHOD("get_frame_texture", "frame"), &AnimatedTexture::get_frame_texture);
28202824

2821-
ClassDB::bind_method(D_METHOD("set_frame_delay", "frame", "delay"), &AnimatedTexture::set_frame_delay);
2822-
ClassDB::bind_method(D_METHOD("get_frame_delay", "frame"), &AnimatedTexture::get_frame_delay);
2825+
ClassDB::bind_method(D_METHOD("set_frame_duration", "frame", "duration"), &AnimatedTexture::set_frame_duration);
2826+
ClassDB::bind_method(D_METHOD("get_frame_duration", "frame"), &AnimatedTexture::get_frame_duration);
28232827

28242828
ADD_PROPERTY(PropertyInfo(Variant::INT, "frames", PROPERTY_HINT_RANGE, "1," + itos(MAX_FRAMES), PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_frames", "get_frames");
28252829
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_frame", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_frame", "get_current_frame");
28262830
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "pause"), "set_pause", "get_pause");
28272831
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
2828-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fps", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_fps", "get_fps");
2832+
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "speed_scale", PROPERTY_HINT_RANGE, "-60,60,0.1,or_greater,or_lesser"), "set_speed_scale", "get_speed_scale");
28292833

28302834
for (int i = 0; i < MAX_FRAMES; i++) {
28312835
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "frame_" + itos(i) + "/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_texture", "get_frame_texture", i);
2832-
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/delay_sec", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_delay", "get_frame_delay", i);
2836+
ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "frame_" + itos(i) + "/duration", PROPERTY_HINT_RANGE, "0.0,16.0,0.01,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_frame_duration", "get_frame_duration", i);
28332837
}
28342838

28352839
BIND_CONSTANT(MAX_FRAMES);

scene/resources/texture.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -922,15 +922,15 @@ class AnimatedTexture : public Texture2D {
922922

923923
struct Frame {
924924
Ref<Texture2D> texture;
925-
float delay_sec = 0.0;
925+
float duration = 1.0;
926926
};
927927

928928
Frame frames[MAX_FRAMES];
929929
int frame_count = 1.0;
930930
int current_frame = 0;
931931
bool pause = false;
932932
bool one_shot = false;
933-
float fps = 4.0;
933+
float speed_scale = 1.0;
934934

935935
float time = 0.0;
936936

@@ -958,11 +958,11 @@ class AnimatedTexture : public Texture2D {
958958
void set_frame_texture(int p_frame, const Ref<Texture2D> &p_texture);
959959
Ref<Texture2D> get_frame_texture(int p_frame) const;
960960

961-
void set_frame_delay(int p_frame, float p_delay_sec);
962-
float get_frame_delay(int p_frame) const;
961+
void set_frame_duration(int p_frame, float p_duration);
962+
float get_frame_duration(int p_frame) const;
963963

964-
void set_fps(float p_fps);
965-
float get_fps() const;
964+
void set_speed_scale(float p_scale);
965+
float get_speed_scale() const;
966966

967967
virtual int get_width() const override;
968968
virtual int get_height() const override;

0 commit comments

Comments
 (0)