summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite_2d.cpp73
-rw-r--r--scene/2d/animated_sprite_2d.h6
-rw-r--r--scene/3d/sprite_3d.cpp69
-rw-r--r--scene/3d/sprite_3d.h6
-rw-r--r--scene/resources/sprite_frames.cpp62
-rw-r--r--scene/resources/sprite_frames.h32
6 files changed, 144 insertions, 104 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 50892b72e2..a4a965aa41 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -72,7 +72,7 @@ bool AnimatedSprite2D::_edit_use_rect() const {
Ref<Texture2D> t;
if (animation) {
- t = frames->get_frame(animation, frame);
+ t = frames->get_frame_texture(animation, frame);
}
return t.is_valid();
}
@@ -92,7 +92,7 @@ Rect2 AnimatedSprite2D::_get_rect() const {
Ref<Texture2D> t;
if (animation) {
- t = frames->get_frame(animation, frame);
+ t = frames->get_frame_texture(animation, frame);
}
if (t.is_null()) {
return Rect2();
@@ -172,17 +172,21 @@ void AnimatedSprite2D::_notification(int p_what) {
return;
}
- double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
- if (speed == 0) {
- return; // Do nothing.
- }
- int last_frame = frames->get_frame_count(animation) - 1;
-
double remaining = get_process_delta_time();
+ int i = 0;
while (remaining) {
- if (timeout <= 0) {
- timeout = _get_frame_duration();
+ // Animation speed may be changed by animation_finished or frame_changed signals.
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
+ }
+
+ // Frame count may be changed by animation_finished or frame_changed signals.
+ int fc = frames->get_frame_count(animation);
+
+ if (timeout <= 0) {
+ int last_frame = fc - 1;
if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
@@ -217,14 +221,21 @@ void AnimatedSprite2D::_notification(int p_what) {
}
}
+ timeout = _get_frame_duration();
+
queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
- double to_process = MIN(timeout, remaining);
+ double to_process = MIN(timeout / speed, remaining);
+ timeout -= to_process * speed;
remaining -= to_process;
- timeout -= to_process;
+
+ i++;
+ if (i > fc) {
+ return; // Prevents freezing if to_process is each time much less than remaining.
+ }
}
} break;
@@ -233,7 +244,7 @@ void AnimatedSprite2D::_notification(int p_what) {
return;
}
- Ref<Texture2D> texture = frames->get_frame(animation, frame);
+ Ref<Texture2D> texture = frames->get_frame_texture(animation, frame);
if (texture.is_null()) {
return;
}
@@ -312,7 +323,6 @@ void AnimatedSprite2D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
queue_redraw();
-
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -320,22 +330,12 @@ int AnimatedSprite2D::get_frame() const {
return frame;
}
-void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
- if (speed_scale == p_speed_scale) {
- return;
- }
-
- double elapsed = _get_frame_duration() - timeout;
-
+void AnimatedSprite2D::set_speed_scale(float p_speed_scale) {
speed_scale = p_speed_scale;
playing_backwards = signbit(speed_scale) != backwards;
-
- // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
- _reset_timeout();
- timeout -= elapsed;
}
-double AnimatedSprite2D::get_speed_scale() const {
+float AnimatedSprite2D::get_speed_scale() const {
return speed_scale;
}
@@ -379,8 +379,8 @@ bool AnimatedSprite2D::is_flipped_v() const {
void AnimatedSprite2D::_res_changed() {
set_frame(frame);
-
queue_redraw();
+ notify_property_list_changed();
}
void AnimatedSprite2D::set_playing(bool p_playing) {
@@ -388,7 +388,7 @@ void AnimatedSprite2D::set_playing(bool p_playing) {
return;
}
playing = p_playing;
- _reset_timeout();
+ playing_backwards = signbit(speed_scale) != backwards;
set_process_internal(playing);
notify_property_list_changed();
}
@@ -414,23 +414,18 @@ void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) {
void AnimatedSprite2D::stop() {
set_playing(false);
+ backwards = false;
+ _reset_timeout();
}
double AnimatedSprite2D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
- if (speed > 0) {
- return 1.0 / speed;
- }
+ return frames->get_frame_duration(animation, frame);
}
return 0.0;
}
void AnimatedSprite2D::_reset_timeout() {
- if (!playing) {
- return;
- }
-
timeout = _get_frame_duration();
is_over = false;
}
@@ -444,8 +439,8 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) {
}
animation = p_animation;
- _reset_timeout();
set_frame(0);
+ _reset_timeout();
notify_property_list_changed();
queue_redraw();
}
@@ -455,12 +450,10 @@ StringName AnimatedSprite2D::get_animation() const {
}
PackedStringArray AnimatedSprite2D::get_configuration_warnings() const {
- PackedStringArray warnings = Node::get_configuration_warnings();
-
+ PackedStringArray warnings = Node2D::get_configuration_warnings();
if (frames.is_null()) {
warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite2D to display frames."));
}
-
return warnings;
}
diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h
index 492917cf89..c1d35f3a2f 100644
--- a/scene/2d/animated_sprite_2d.h
+++ b/scene/2d/animated_sprite_2d.h
@@ -43,7 +43,7 @@ class AnimatedSprite2D : public Node2D {
bool backwards = false;
StringName animation = "default";
int frame = 0;
- float speed_scale = 1.0f;
+ float speed_scale = 1.0;
bool centered = true;
Point2 offset;
@@ -94,8 +94,8 @@ public:
void set_frame(int p_frame);
int get_frame() const;
- void set_speed_scale(double p_speed_scale);
- double get_speed_scale() const;
+ void set_speed_scale(float p_speed_scale);
+ float get_speed_scale() const;
void set_centered(bool p_center);
bool is_centered() const;
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 864a5332dc..71d76c0d1c 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -837,7 +837,7 @@ void AnimatedSprite3D::_draw() {
return;
}
- Ref<Texture2D> texture = frames->get_frame(animation, frame);
+ Ref<Texture2D> texture = frames->get_frame_texture(animation, frame);
if (texture.is_null()) {
set_base(RID());
return;
@@ -921,17 +921,21 @@ void AnimatedSprite3D::_notification(int p_what) {
return;
}
- double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
- if (speed == 0) {
- return; // Do nothing.
- }
- int last_frame = frames->get_frame_count(animation) - 1;
-
double remaining = get_process_delta_time();
+ int i = 0;
while (remaining) {
- if (timeout <= 0) {
- timeout = _get_frame_duration();
+ // Animation speed may be changed by animation_finished or frame_changed signals.
+ double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
+ if (speed == 0) {
+ return; // Do nothing.
+ }
+
+ // Frame count may be changed by animation_finished or frame_changed signals.
+ int fc = frames->get_frame_count(animation);
+
+ if (timeout <= 0) {
+ int last_frame = fc - 1;
if (!playing_backwards) {
// Forward.
if (frame >= last_frame) {
@@ -966,14 +970,21 @@ void AnimatedSprite3D::_notification(int p_what) {
}
}
+ timeout = _get_frame_duration();
+
_queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
- double to_process = MIN(timeout, remaining);
+ double to_process = MIN(timeout / speed, remaining);
+ timeout -= to_process * speed;
remaining -= to_process;
- timeout -= to_process;
+
+ i++;
+ if (i > fc) {
+ return; // Prevents freezing if to_process is each time much less than remaining.
+ }
}
} break;
}
@@ -1028,7 +1039,6 @@ void AnimatedSprite3D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
_queue_redraw();
-
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -1036,22 +1046,12 @@ int AnimatedSprite3D::get_frame() const {
return frame;
}
-void AnimatedSprite3D::set_speed_scale(double p_speed_scale) {
- if (speed_scale == p_speed_scale) {
- return;
- }
-
- double elapsed = _get_frame_duration() - timeout;
-
+void AnimatedSprite3D::set_speed_scale(float p_speed_scale) {
speed_scale = p_speed_scale;
playing_backwards = signbit(speed_scale) != backwards;
-
- // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed.
- _reset_timeout();
- timeout -= elapsed;
}
-double AnimatedSprite3D::get_speed_scale() const {
+float AnimatedSprite3D::get_speed_scale() const {
return speed_scale;
}
@@ -1065,7 +1065,7 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
Ref<Texture2D> t;
if (animation) {
- t = frames->get_frame(animation, frame);
+ t = frames->get_frame_texture(animation, frame);
}
if (t.is_null()) {
return Rect2(0, 0, 1, 1);
@@ -1086,8 +1086,8 @@ Rect2 AnimatedSprite3D::get_item_rect() const {
void AnimatedSprite3D::_res_changed() {
set_frame(frame);
-
_queue_redraw();
+ notify_property_list_changed();
}
void AnimatedSprite3D::set_playing(bool p_playing) {
@@ -1095,7 +1095,7 @@ void AnimatedSprite3D::set_playing(bool p_playing) {
return;
}
playing = p_playing;
- _reset_timeout();
+ playing_backwards = signbit(speed_scale) != backwards;
set_process_internal(playing);
notify_property_list_changed();
}
@@ -1121,23 +1121,18 @@ void AnimatedSprite3D::play(const StringName &p_animation, bool p_backwards) {
void AnimatedSprite3D::stop() {
set_playing(false);
+ backwards = false;
+ _reset_timeout();
}
double AnimatedSprite3D::_get_frame_duration() {
if (frames.is_valid() && frames->has_animation(animation)) {
- double speed = frames->get_animation_speed(animation) * Math::abs(speed_scale);
- if (speed > 0) {
- return 1.0 / speed;
- }
+ return frames->get_frame_duration(animation, frame);
}
return 0.0;
}
void AnimatedSprite3D::_reset_timeout() {
- if (!playing) {
- return;
- }
-
timeout = _get_frame_duration();
is_over = false;
}
@@ -1145,13 +1140,14 @@ void AnimatedSprite3D::_reset_timeout() {
void AnimatedSprite3D::set_animation(const StringName &p_animation) {
ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", p_animation));
ERR_FAIL_COND_MSG(!frames->get_animation_names().has(p_animation), vformat("There is no animation with name '%s'.", p_animation));
+
if (animation == p_animation) {
return;
}
animation = p_animation;
- _reset_timeout();
set_frame(0);
+ _reset_timeout();
notify_property_list_changed();
_queue_redraw();
}
@@ -1165,7 +1161,6 @@ PackedStringArray AnimatedSprite3D::get_configuration_warnings() const {
if (frames.is_null()) {
warnings.push_back(RTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames."));
}
-
return warnings;
}
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index 276c4fe1cc..c5509aa723 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -214,7 +214,7 @@ class AnimatedSprite3D : public SpriteBase3D {
bool backwards = false;
StringName animation = "default";
int frame = 0;
- float speed_scale = 1.0f;
+ float speed_scale = 1.0;
bool centered = false;
@@ -248,8 +248,8 @@ public:
void set_frame(int p_frame);
int get_frame() const;
- void set_speed_scale(double p_speed_scale);
- double get_speed_scale() const;
+ void set_speed_scale(float p_speed_scale);
+ float get_speed_scale() const;
virtual Rect2 get_item_rect() const override;
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 4892f4cd17..c101974248 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -32,19 +32,40 @@
#include "scene/scene_string_names.h"
-void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) {
+void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_texture, float p_duration, int p_at_pos) {
HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ p_duration = MAX(0.0, p_duration);
+
+ Frame frame = { p_texture, p_duration };
+
if (p_at_pos >= 0 && p_at_pos < E->value.frames.size()) {
- E->value.frames.insert(p_at_pos, p_frame);
+ E->value.frames.insert(p_at_pos, frame);
} else {
- E->value.frames.push_back(p_frame);
+ E->value.frames.push_back(frame);
}
emit_changed();
}
+void SpriteFrames::set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_texture, float p_duration) {
+ HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
+ ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND(p_idx < 0);
+ if (p_idx >= E->value.frames.size()) {
+ return;
+ }
+
+ p_duration = MAX(0.0, p_duration);
+
+ Frame frame = { p_texture, p_duration };
+
+ E->value.frames.write[p_idx] = frame;
+
+ emit_changed();
+}
+
int SpriteFrames::get_frame_count(const StringName &p_anim) const {
HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist.");
@@ -57,6 +78,7 @@ void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->value.frames.remove_at(p_idx);
+
emit_changed();
}
@@ -65,6 +87,7 @@ void SpriteFrames::clear(const StringName &p_anim) {
ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
E->value.frames.clear();
+
emit_changed();
}
@@ -151,7 +174,10 @@ Array SpriteFrames::_get_animations() const {
d["loop"] = anim.loop;
Array frames;
for (int i = 0; i < anim.frames.size(); i++) {
- frames.push_back(anim.frames[i]);
+ Dictionary f;
+ f["texture"] = anim.frames[i].texture;
+ f["duration"] = anim.frames[i].duration;
+ frames.push_back(f);
}
d["frames"] = frames;
anims.push_back(d);
@@ -175,8 +201,21 @@ void SpriteFrames::_set_animations(const Array &p_animations) {
anim.loop = d["loop"];
Array frames = d["frames"];
for (int j = 0; j < frames.size(); j++) {
+ // For compatibility.
Ref<Resource> res = frames[j];
- anim.frames.push_back(res);
+ if (res.is_valid()) {
+ Frame frame = { res, 1.0 };
+ anim.frames.push_back(frame);
+ continue;
+ }
+
+ Dictionary f = frames[j];
+
+ ERR_CONTINUE(!f.has("texture"));
+ ERR_CONTINUE(!f.has("duration"));
+
+ Frame frame = { f["texture"], f["duration"] };
+ anim.frames.push_back(frame);
}
animations[d["name"]] = anim;
@@ -191,17 +230,20 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names);
- ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
+ ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "fps"), &SpriteFrames::set_animation_speed);
ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
- ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
- ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
- ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
+ ClassDB::bind_method(D_METHOD("add_frame", "anim", "texture", "duration", "at_position"), &SpriteFrames::add_frame, DEFVAL(1.0), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "texture", "duration"), &SpriteFrames::set_frame, DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
+
+ ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
+ ClassDB::bind_method(D_METHOD("get_frame_texture", "anim", "idx"), &SpriteFrames::get_frame_texture);
+ ClassDB::bind_method(D_METHOD("get_frame_duration", "anim", "idx"), &SpriteFrames::get_frame_duration);
+
ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear);
ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all);
diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h
index 56fd2b8b56..61bead6948 100644
--- a/scene/resources/sprite_frames.h
+++ b/scene/resources/sprite_frames.h
@@ -36,10 +36,15 @@
class SpriteFrames : public Resource {
GDCLASS(SpriteFrames, Resource);
+ struct Frame {
+ Ref<Texture2D> texture;
+ float duration = 1.0;
+ };
+
struct Anim {
double speed = 5.0;
bool loop = true;
- Vector<Ref<Texture2D>> frames;
+ Vector<Frame> frames;
};
HashMap<StringName, Anim> animations;
@@ -65,9 +70,13 @@ public:
void set_animation_loop(const StringName &p_anim, bool p_loop);
bool get_animation_loop(const StringName &p_anim) const;
- void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1);
+ void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_texture, float p_duration = 1.0, int p_at_pos = -1);
+ void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_texture, float p_duration = 1.0);
+ void remove_frame(const StringName &p_anim, int p_idx);
+
int get_frame_count(const StringName &p_anim) const;
- _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const {
+
+ _FORCE_INLINE_ Ref<Texture2D> get_frame_texture(const StringName &p_anim, int p_idx) const {
HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist.");
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
@@ -75,19 +84,20 @@ public:
return Ref<Texture2D>();
}
- return E->value.frames[p_idx];
+ return E->value.frames[p_idx].texture;
}
- void set_frame(const StringName &p_anim, int p_idx, const Ref<Texture2D> &p_frame) {
- HashMap<StringName, Anim>::Iterator E = animations.find(p_anim);
- ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist.");
- ERR_FAIL_COND(p_idx < 0);
+ _FORCE_INLINE_ float get_frame_duration(const StringName &p_anim, int p_idx) const {
+ HashMap<StringName, Anim>::ConstIterator E = animations.find(p_anim);
+ ERR_FAIL_COND_V_MSG(!E, 0.0, "Animation '" + String(p_anim) + "' doesn't exist.");
+ ERR_FAIL_COND_V(p_idx < 0, 0.0);
if (p_idx >= E->value.frames.size()) {
- return;
+ return 0.0;
}
- E->value.frames.write[p_idx] = p_frame;
+
+ return E->value.frames[p_idx].duration;
}
- void remove_frame(const StringName &p_anim, int p_idx);
+
void clear(const StringName &p_anim);
void clear_all();