summaryrefslogtreecommitdiffstats
path: root/scene/2d/animated_sprite_2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/2d/animated_sprite_2d.cpp')
-rw-r--r--scene/2d/animated_sprite_2d.cpp274
1 files changed, 142 insertions, 132 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index d56c7b8811..a4a965aa41 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -1,32 +1,32 @@
-/*************************************************************************/
-/* animated_sprite_2d.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* Permission is hereby granted, free of charge, to any person obtaining */
-/* a copy of this software and associated documentation files (the */
-/* "Software"), to deal in the Software without restriction, including */
-/* without limitation the rights to use, copy, modify, merge, publish, */
-/* distribute, sublicense, and/or sell copies of the Software, and to */
-/* permit persons to whom the Software is furnished to do so, subject to */
-/* the following conditions: */
-/* */
-/* The above copyright notice and this permission notice shall be */
-/* included in all copies or substantial portions of the Software. */
-/* */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
-/*************************************************************************/
+/**************************************************************************/
+/* animated_sprite_2d.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
#include "animated_sprite_2d.h"
@@ -63,12 +63,16 @@ Rect2 AnimatedSprite2D::_edit_get_rect() const {
}
bool AnimatedSprite2D::_edit_use_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return false;
}
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return false;
+ }
+
Ref<Texture2D> t;
if (animation) {
- t = frames->get_frame(animation, frame);
+ t = frames->get_frame_texture(animation, frame);
}
return t.is_valid();
}
@@ -79,13 +83,16 @@ Rect2 AnimatedSprite2D::get_anchorable_rect() const {
}
Rect2 AnimatedSprite2D::_get_rect() const {
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
+ return Rect2();
+ }
+ if (frame < 0 || frame >= frames->get_frame_count(animation)) {
return Rect2();
}
Ref<Texture2D> t;
if (animation) {
- t = frames->get_frame(animation, frame);
+ t = frames->get_frame_texture(animation, frame);
}
if (t.is_null()) {
return Rect2();
@@ -104,127 +111,140 @@ Rect2 AnimatedSprite2D::_get_rect() const {
return Rect2(ofs, s);
}
-void AnimatedSprite2D::_validate_property(PropertyInfo &property) const {
+void AnimatedSprite2D::_validate_property(PropertyInfo &p_property) const {
if (!frames.is_valid()) {
return;
}
- if (property.name == "animation") {
- property.hint = PROPERTY_HINT_ENUM;
+
+ if (p_property.name == "animation") {
+ p_property.hint = PROPERTY_HINT_ENUM;
List<StringName> names;
frames->get_animation_list(&names);
names.sort_custom<StringName::AlphCompare>();
bool current_found = false;
+ bool is_first_element = true;
- for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
- if (E->prev()) {
- property.hint_string += ",";
+ for (const StringName &E : names) {
+ if (!is_first_element) {
+ p_property.hint_string += ",";
+ } else {
+ is_first_element = false;
}
- property.hint_string += String(E->get());
- if (animation == E->get()) {
+ p_property.hint_string += String(E);
+ if (animation == E) {
current_found = true;
}
}
if (!current_found) {
- if (property.hint_string.is_empty()) {
- property.hint_string = String(animation);
+ if (p_property.hint_string.is_empty()) {
+ p_property.hint_string = String(animation);
} else {
- property.hint_string = String(animation) + "," + property.hint_string;
+ p_property.hint_string = String(animation) + "," + p_property.hint_string;
}
}
+ return;
}
- if (property.name == "frame") {
- property.hint = PROPERTY_HINT_RANGE;
+ if (p_property.name == "frame") {
+ if (playing) {
+ p_property.usage = PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY;
+ return;
+ }
+
+ p_property.hint = PROPERTY_HINT_RANGE;
if (frames->has_animation(animation) && frames->get_frame_count(animation) > 0) {
- property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
+ p_property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
} else {
// Avoid an error, `hint_string` is required for `PROPERTY_HINT_RANGE`.
- property.hint_string = "0,0,1";
+ p_property.hint_string = "0,0,1";
}
- property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
+ p_property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
}
}
void AnimatedSprite2D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
- if (frames.is_null()) {
- return;
- }
- if (!frames->has_animation(animation)) {
- return;
- }
- if (frame < 0) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
double remaining = get_process_delta_time();
-
+ int i = 0;
while (remaining) {
- double speed = frames->get_animation_speed(animation) * speed_scale;
+ // 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.
}
- if (timeout <= 0) {
- timeout = _get_frame_duration();
-
- int fc = frames->get_frame_count(animation);
- if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) {
- if (frames->get_animation_loop(animation)) {
- if (backwards) {
- frame = fc - 1;
- } else {
- frame = 0;
- }
+ // Frame count may be changed by animation_finished or frame_changed signals.
+ int fc = frames->get_frame_count(animation);
- emit_signal(SceneStringNames::get_singleton()->animation_finished);
- } else {
- if (backwards) {
+ if (timeout <= 0) {
+ int last_frame = fc - 1;
+ if (!playing_backwards) {
+ // Forward.
+ if (frame >= last_frame) {
+ if (frames->get_animation_loop(animation)) {
frame = 0;
- } else {
- frame = fc - 1;
- }
-
- if (!is_over) {
- is_over = true;
emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = last_frame;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
}
+ } else {
+ frame++;
}
} else {
- if (backwards) {
- frame--;
+ // Reversed.
+ if (frame <= 0) {
+ if (frames->get_animation_loop(animation)) {
+ frame = last_frame;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ } else {
+ frame = 0;
+ if (!is_over) {
+ is_over = true;
+ emit_signal(SceneStringNames::get_singleton()->animation_finished);
+ }
+ }
} else {
- frame++;
+ frame--;
}
}
- update();
+ 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;
case NOTIFICATION_DRAW: {
- if (frames.is_null()) {
- return;
- }
- if (frame < 0) {
- return;
- }
- if (!frames->has_animation(animation)) {
+ if (frames.is_null() || !frames->has_animation(animation)) {
return;
}
- Ref<Texture2D> texture = frames->get_frame(animation, frame);
+ Ref<Texture2D> texture = frames->get_frame_texture(animation, frame);
if (texture.is_null()) {
return;
}
@@ -256,14 +276,15 @@ void AnimatedSprite2D::_notification(int p_what) {
void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
if (frames.is_valid()) {
- frames->disconnect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->disconnect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
+
frames = p_frames;
if (frames.is_valid()) {
- frames->connect("changed", callable_mp(this, &AnimatedSprite2D::_res_changed));
+ frames->connect(SceneStringNames::get_singleton()->changed, callable_mp(this, &AnimatedSprite2D::_res_changed));
}
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
frame = 0;
} else {
set_frame(frame);
@@ -271,7 +292,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
notify_property_list_changed();
_reset_timeout();
- update();
+ queue_redraw();
update_configuration_warnings();
}
@@ -280,7 +301,7 @@ Ref<SpriteFrames> AnimatedSprite2D::get_sprite_frames() const {
}
void AnimatedSprite2D::set_frame(int p_frame) {
- if (!frames.is_valid()) {
+ if (frames.is_null()) {
return;
}
@@ -301,8 +322,7 @@ void AnimatedSprite2D::set_frame(int p_frame) {
frame = p_frame;
_reset_timeout();
- update();
-
+ queue_redraw();
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
@@ -310,23 +330,18 @@ int AnimatedSprite2D::get_frame() const {
return frame;
}
-void AnimatedSprite2D::set_speed_scale(double p_speed_scale) {
- double elapsed = _get_frame_duration() - timeout;
-
- speed_scale = MAX(p_speed_scale, 0.0f);
-
- // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
- _reset_timeout();
- timeout -= elapsed;
+void AnimatedSprite2D::set_speed_scale(float p_speed_scale) {
+ speed_scale = p_speed_scale;
+ playing_backwards = signbit(speed_scale) != backwards;
}
-double AnimatedSprite2D::get_speed_scale() const {
+float AnimatedSprite2D::get_speed_scale() const {
return speed_scale;
}
void AnimatedSprite2D::set_centered(bool p_center) {
centered = p_center;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -336,7 +351,7 @@ bool AnimatedSprite2D::is_centered() const {
void AnimatedSprite2D::set_offset(const Point2 &p_offset) {
offset = p_offset;
- update();
+ queue_redraw();
item_rect_changed();
}
@@ -346,7 +361,7 @@ Point2 AnimatedSprite2D::get_offset() const {
void AnimatedSprite2D::set_flip_h(bool p_flip) {
hflip = p_flip;
- update();
+ queue_redraw();
}
bool AnimatedSprite2D::is_flipped_h() const {
@@ -355,7 +370,7 @@ bool AnimatedSprite2D::is_flipped_h() const {
void AnimatedSprite2D::set_flip_v(bool p_flip) {
vflip = p_flip;
- update();
+ queue_redraw();
}
bool AnimatedSprite2D::is_flipped_v() const {
@@ -364,8 +379,8 @@ bool AnimatedSprite2D::is_flipped_v() const {
void AnimatedSprite2D::_res_changed() {
set_frame(frame);
-
- update();
+ queue_redraw();
+ notify_property_list_changed();
}
void AnimatedSprite2D::set_playing(bool p_playing) {
@@ -373,20 +388,22 @@ 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();
}
bool AnimatedSprite2D::is_playing() const {
return playing;
}
-void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) {
+void AnimatedSprite2D::play(const StringName &p_animation, bool p_backwards) {
backwards = p_backwards;
+ playing_backwards = signbit(speed_scale) != backwards;
if (p_animation) {
set_animation(p_animation);
- if (frames.is_valid() && backwards && get_frame() == 0) {
+ if (frames.is_valid() && playing_backwards && get_frame() == 0) {
set_frame(frames->get_frame_count(p_animation) - 1);
}
}
@@ -397,23 +414,18 @@ void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backward
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) * 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;
}
@@ -427,23 +439,21 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) {
}
animation = p_animation;
- _reset_timeout();
set_frame(0);
+ _reset_timeout();
notify_property_list_changed();
- update();
+ queue_redraw();
}
StringName AnimatedSprite2D::get_animation() const {
return animation;
}
-TypedArray<String> AnimatedSprite2D::get_configuration_warnings() const {
- TypedArray<String> warnings = Node::get_configuration_warnings();
-
+PackedStringArray AnimatedSprite2D::get_configuration_warnings() const {
+ 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 AnimatedSprite to display frames."));
+ 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;
}