1 /*************************************************************************/
2 /* animated_sprite.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "animated_sprite.h"
31 #include "os/os.h"
32 #include "scene/scene_string_names.h"
33
34 ////////////////////////////
35
add_frame(const StringName & p_anim,const Ref<Texture> & p_frame,int p_at_pos)36 void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) {
37
38 Map<StringName, Anim>::Element *E = animations.find(p_anim);
39 ERR_FAIL_COND(!E);
40
41 if (p_at_pos >= 0 && p_at_pos < E->get().frames.size())
42 E->get().frames.insert(p_at_pos, p_frame);
43 else
44 E->get().frames.push_back(p_frame);
45
46 emit_changed();
47 }
48
get_frame_count(const StringName & p_anim) const49 int SpriteFrames::get_frame_count(const StringName &p_anim) const {
50 const Map<StringName, Anim>::Element *E = animations.find(p_anim);
51 ERR_FAIL_COND_V(!E, 0);
52
53 return E->get().frames.size();
54 }
55
remove_frame(const StringName & p_anim,int p_idx)56 void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) {
57
58 Map<StringName, Anim>::Element *E = animations.find(p_anim);
59 ERR_FAIL_COND(!E);
60
61 E->get().frames.remove(p_idx);
62 emit_changed();
63 }
clear(const StringName & p_anim)64 void SpriteFrames::clear(const StringName &p_anim) {
65
66 Map<StringName, Anim>::Element *E = animations.find(p_anim);
67 ERR_FAIL_COND(!E);
68
69 E->get().frames.clear();
70 emit_changed();
71 }
72
clear_all()73 void SpriteFrames::clear_all() {
74
75 animations.clear();
76 add_animation("default");
77 }
78
add_animation(const StringName & p_anim)79 void SpriteFrames::add_animation(const StringName &p_anim) {
80
81 ERR_FAIL_COND(animations.has(p_anim));
82
83 animations[p_anim] = Anim();
84 }
85
has_animation(const StringName & p_anim) const86 bool SpriteFrames::has_animation(const StringName &p_anim) const {
87
88 return animations.has(p_anim);
89 }
remove_animation(const StringName & p_anim)90 void SpriteFrames::remove_animation(const StringName &p_anim) {
91
92 animations.erase(p_anim);
93 }
94
rename_animation(const StringName & p_prev,const StringName & p_next)95 void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) {
96
97 ERR_FAIL_COND(!animations.has(p_prev));
98 ERR_FAIL_COND(animations.has(p_next));
99
100 Anim anim = animations[p_prev];
101 animations.erase(p_prev);
102 animations[p_next] = anim;
103 }
104
_get_animation_list() const105 Vector<String> SpriteFrames::_get_animation_list() const {
106
107 Vector<String> ret;
108 List<StringName> al;
109 get_animation_list(&al);
110 for (List<StringName>::Element *E = al.front(); E; E = E->next()) {
111
112 ret.push_back(E->get());
113 }
114
115 return ret;
116 }
117
get_animation_list(List<StringName> * r_animations) const118 void SpriteFrames::get_animation_list(List<StringName> *r_animations) const {
119
120 for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
121 r_animations->push_back(E->key());
122 }
123 }
124
set_animation_speed(const StringName & p_anim,float p_fps)125 void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) {
126
127 ERR_FAIL_COND(p_fps < 0);
128 Map<StringName, Anim>::Element *E = animations.find(p_anim);
129 ERR_FAIL_COND(!E);
130 E->get().speed = p_fps;
131 }
get_animation_speed(const StringName & p_anim) const132 float SpriteFrames::get_animation_speed(const StringName &p_anim) const {
133
134 const Map<StringName, Anim>::Element *E = animations.find(p_anim);
135 ERR_FAIL_COND_V(!E, 0);
136 return E->get().speed;
137 }
138
set_animation_loop(const StringName & p_anim,bool p_loop)139 void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) {
140 Map<StringName, Anim>::Element *E = animations.find(p_anim);
141 ERR_FAIL_COND(!E);
142 E->get().loop = p_loop;
143 }
get_animation_loop(const StringName & p_anim) const144 bool SpriteFrames::get_animation_loop(const StringName &p_anim) const {
145 const Map<StringName, Anim>::Element *E = animations.find(p_anim);
146 ERR_FAIL_COND_V(!E, false);
147 return E->get().loop;
148 }
149
_set_frames(const Array & p_frames)150 void SpriteFrames::_set_frames(const Array &p_frames) {
151
152 clear_all();
153 Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default);
154 ERR_FAIL_COND(!E);
155
156 E->get().frames.resize(p_frames.size());
157 for (int i = 0; i < E->get().frames.size(); i++)
158 E->get().frames[i] = p_frames[i];
159 }
_get_frames() const160 Array SpriteFrames::_get_frames() const {
161
162 return Array();
163 }
164
_get_animations() const165 Array SpriteFrames::_get_animations() const {
166
167 Array anims;
168 for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) {
169 Dictionary d;
170 d["name"] = E->key();
171 d["speed"] = E->get().speed;
172 d["loop"] = E->get().loop;
173 Array frames;
174 for (int i = 0; i < E->get().frames.size(); i++) {
175 frames.push_back(E->get().frames[i]);
176 }
177 d["frames"] = frames;
178 anims.push_back(d);
179 }
180
181 return anims;
182 }
_set_animations(const Array & p_animations)183 void SpriteFrames::_set_animations(const Array &p_animations) {
184
185 animations.clear();
186 for (int i = 0; i < p_animations.size(); i++) {
187
188 Dictionary d = p_animations[i];
189
190 ERR_CONTINUE(!d.has("name"));
191 ERR_CONTINUE(!d.has("speed"));
192 ERR_CONTINUE(!d.has("loop"));
193 ERR_CONTINUE(!d.has("frames"));
194
195 Anim anim;
196 anim.speed = d["speed"];
197 anim.loop = d["loop"];
198 Array frames = d["frames"];
199 for (int i = 0; i < frames.size(); i++) {
200
201 RES res = frames[i];
202 anim.frames.push_back(res);
203 }
204
205 animations[d["name"]] = anim;
206 }
207 }
208
_bind_methods()209 void SpriteFrames::_bind_methods() {
210
211 ObjectTypeDB::bind_method(_MD("add_animation", "anim"), &SpriteFrames::add_animation);
212 ObjectTypeDB::bind_method(_MD("has_animation", "anim"), &SpriteFrames::has_animation);
213 ObjectTypeDB::bind_method(_MD("remove_animation", "anim"), &SpriteFrames::remove_animation);
214 ObjectTypeDB::bind_method(_MD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation);
215
216 ObjectTypeDB::bind_method(_MD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed);
217 ObjectTypeDB::bind_method(_MD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed);
218
219 ObjectTypeDB::bind_method(_MD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop);
220 ObjectTypeDB::bind_method(_MD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop);
221
222 ObjectTypeDB::bind_method(_MD("add_frame", "anim", "frame", "atpos"), &SpriteFrames::add_frame, DEFVAL(-1));
223 ObjectTypeDB::bind_method(_MD("get_frame_count", "anim"), &SpriteFrames::get_frame_count);
224 ObjectTypeDB::bind_method(_MD("get_frame", "anim", "idx"), &SpriteFrames::get_frame);
225 ObjectTypeDB::bind_method(_MD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame);
226 ObjectTypeDB::bind_method(_MD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame);
227 ObjectTypeDB::bind_method(_MD("clear", "anim"), &SpriteFrames::clear);
228 ObjectTypeDB::bind_method(_MD("clear_all"), &SpriteFrames::clear_all);
229
230 ObjectTypeDB::bind_method(_MD("_set_frames"), &SpriteFrames::_set_frames);
231 ObjectTypeDB::bind_method(_MD("_get_frames"), &SpriteFrames::_get_frames);
232
233 ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), _SCS("_set_frames"), _SCS("_get_frames")); //compatibility
234
235 ObjectTypeDB::bind_method(_MD("_set_animations"), &SpriteFrames::_set_animations);
236 ObjectTypeDB::bind_method(_MD("_get_animations"), &SpriteFrames::_get_animations);
237
238 ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_animations"), _SCS("_get_animations")); //compatibility
239 }
240
SpriteFrames()241 SpriteFrames::SpriteFrames() {
242
243 add_animation(SceneStringNames::get_singleton()->_default);
244 }
245
edit_set_pivot(const Point2 & p_pivot)246 void AnimatedSprite::edit_set_pivot(const Point2 &p_pivot) {
247
248 set_offset(p_pivot);
249 }
250
edit_get_pivot() const251 Point2 AnimatedSprite::edit_get_pivot() const {
252
253 return get_offset();
254 }
edit_has_pivot() const255 bool AnimatedSprite::edit_has_pivot() const {
256
257 return true;
258 }
259
_validate_property(PropertyInfo & property) const260 void AnimatedSprite::_validate_property(PropertyInfo &property) const {
261
262 if (!frames.is_valid())
263 return;
264 if (property.name == "animation") {
265
266 property.hint = PROPERTY_HINT_ENUM;
267 List<StringName> names;
268 frames->get_animation_list(&names);
269 names.sort_custom<StringName::AlphCompare>();
270
271 bool current_found = false;
272
273 for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
274 if (E->prev()) {
275 property.hint_string += ",";
276 }
277
278 property.hint_string += String(E->get());
279 if (animation == E->get()) {
280 current_found = true;
281 }
282 }
283
284 if (!current_found) {
285 if (property.hint_string == String()) {
286 property.hint_string = String(animation);
287 } else {
288 property.hint_string = String(animation) + "," + property.hint_string;
289 }
290 }
291 }
292
293 if (property.name == "frame") {
294
295 property.hint = PROPERTY_HINT_SPRITE_FRAME;
296
297 if (frames->has_animation(animation)) {
298 property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
299 } else {
300 property.hint_string = "0,0,0";
301 }
302 }
303 }
304
_notification(int p_what)305 void AnimatedSprite::_notification(int p_what) {
306
307 switch (p_what) {
308 case NOTIFICATION_PROCESS: {
309
310 if (frames.is_null())
311 return;
312 if (!frames->has_animation(animation))
313 return;
314 if (frame < 0)
315 return;
316
317 float speed = frames->get_animation_speed(animation);
318 if (speed == 0)
319 return; //do nothing
320
321 float remaining = get_process_delta_time();
322
323 while (remaining) {
324
325 if (timeout <= 0) {
326
327 timeout = 1.0 / speed;
328
329 int fc = frames->get_frame_count(animation);
330 if (frame >= fc - 1) {
331 if (frames->get_animation_loop(animation)) {
332 frame = 0;
333 } else {
334 frame = fc - 1;
335 }
336 } else {
337 frame++;
338 if (frame == fc - 1) {
339 emit_signal(SceneStringNames::get_singleton()->finished);
340 }
341 }
342
343 update();
344 _change_notify("frame");
345 emit_signal(SceneStringNames::get_singleton()->frame_changed);
346 }
347
348 float to_process = MIN(timeout, remaining);
349 remaining -= to_process;
350 timeout -= to_process;
351 }
352 } break;
353
354 case NOTIFICATION_DRAW: {
355
356 if (frames.is_null()) {
357 print_line("no draw no faemos");
358 return;
359 }
360
361 if (frame < 0) {
362 print_line("no draw frame <0");
363 return;
364 }
365
366 if (!frames->has_animation(animation)) {
367 print_line("no draw no anim: " + String(animation));
368 return;
369 }
370
371 Ref<Texture> texture = frames->get_frame(animation, frame);
372 if (texture.is_null()) {
373 print_line("no draw texture is null");
374 return;
375 }
376
377 //print_line("DECIDED TO DRAW");
378
379 RID ci = get_canvas_item();
380
381 /*
382 texture->draw(ci,Point2());
383 break;
384 */
385
386 Size2i s;
387 s = texture->get_size();
388 Point2 ofs = offset;
389 if (centered)
390 ofs -= s / 2;
391
392 if (OS::get_singleton()->get_use_pixel_snap()) {
393 ofs = ofs.floor();
394 }
395 Rect2 dst_rect(ofs, s);
396
397 if (hflip)
398 dst_rect.size.x = -dst_rect.size.x;
399 if (vflip)
400 dst_rect.size.y = -dst_rect.size.y;
401
402 //texture->draw_rect(ci,dst_rect,false,modulate);
403 texture->draw_rect_region(ci, dst_rect, Rect2(Vector2(), texture->get_size()), modulate);
404 // VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate);
405
406 } break;
407 }
408 }
409
set_sprite_frames(const Ref<SpriteFrames> & p_frames)410 void AnimatedSprite::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
411
412 if (frames.is_valid())
413 frames->disconnect("changed", this, "_res_changed");
414 frames = p_frames;
415 if (frames.is_valid())
416 frames->connect("changed", this, "_res_changed");
417
418 if (!frames.is_valid()) {
419 frame = 0;
420 } else {
421 set_frame(frame);
422 }
423
424 _change_notify();
425 _reset_timeout();
426 update();
427 update_configuration_warning();
428 }
429
get_sprite_frames() const430 Ref<SpriteFrames> AnimatedSprite::get_sprite_frames() const {
431
432 return frames;
433 }
434
set_frame(int p_frame)435 void AnimatedSprite::set_frame(int p_frame) {
436
437 if (!frames.is_valid()) {
438 return;
439 }
440
441 if (frames->has_animation(animation)) {
442 int limit = frames->get_frame_count(animation);
443 if (p_frame >= limit)
444 p_frame = limit - 1;
445 }
446
447 if (p_frame < 0)
448 p_frame = 0;
449
450 if (frame == p_frame)
451 return;
452
453 frame = p_frame;
454 _reset_timeout();
455 update();
456 _change_notify("frame");
457 emit_signal(SceneStringNames::get_singleton()->frame_changed);
458 }
get_frame() const459 int AnimatedSprite::get_frame() const {
460
461 return frame;
462 }
463
set_centered(bool p_center)464 void AnimatedSprite::set_centered(bool p_center) {
465
466 centered = p_center;
467 update();
468 item_rect_changed();
469 }
470
is_centered() const471 bool AnimatedSprite::is_centered() const {
472
473 return centered;
474 }
475
set_offset(const Point2 & p_offset)476 void AnimatedSprite::set_offset(const Point2 &p_offset) {
477
478 offset = p_offset;
479 update();
480 item_rect_changed();
481 _change_notify("offset");
482 }
get_offset() const483 Point2 AnimatedSprite::get_offset() const {
484
485 return offset;
486 }
487
set_flip_h(bool p_flip)488 void AnimatedSprite::set_flip_h(bool p_flip) {
489
490 hflip = p_flip;
491 update();
492 }
is_flipped_h() const493 bool AnimatedSprite::is_flipped_h() const {
494
495 return hflip;
496 }
497
set_flip_v(bool p_flip)498 void AnimatedSprite::set_flip_v(bool p_flip) {
499
500 vflip = p_flip;
501 update();
502 }
is_flipped_v() const503 bool AnimatedSprite::is_flipped_v() const {
504
505 return vflip;
506 }
507
set_modulate(const Color & p_color)508 void AnimatedSprite::set_modulate(const Color &p_color) {
509
510 modulate = p_color;
511 update();
512 }
513
get_modulate() const514 Color AnimatedSprite::get_modulate() const {
515
516 return modulate;
517 }
518
get_item_rect() const519 Rect2 AnimatedSprite::get_item_rect() const {
520
521 if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
522 return Node2D::get_item_rect();
523 }
524
525 Ref<Texture> t;
526 if (animation)
527 t = frames->get_frame(animation, frame);
528 if (t.is_null())
529 return Node2D::get_item_rect();
530 Size2i s = t->get_size();
531
532 Point2 ofs = offset;
533 if (centered)
534 ofs -= s / 2;
535
536 if (s == Size2(0, 0))
537 s = Size2(1, 1);
538
539 return Rect2(ofs, s);
540 }
541
_res_changed()542 void AnimatedSprite::_res_changed() {
543
544 set_frame(frame);
545 _change_notify("frame");
546 _change_notify("animation");
547 update();
548 }
549
_set_playing(bool p_playing)550 void AnimatedSprite::_set_playing(bool p_playing) {
551
552 if (playing == p_playing)
553 return;
554 playing = p_playing;
555 _reset_timeout();
556 set_process(playing);
557 }
558
_is_playing() const559 bool AnimatedSprite::_is_playing() const {
560
561 return playing;
562 }
563
play(const StringName & p_animation)564 void AnimatedSprite::play(const StringName &p_animation) {
565
566 if (p_animation)
567 set_animation(p_animation);
568 _set_playing(true);
569 }
570
stop()571 void AnimatedSprite::stop() {
572
573 _set_playing(false);
574 }
575
is_playing() const576 bool AnimatedSprite::is_playing() const {
577
578 return is_processing();
579 }
580
_reset_timeout()581 void AnimatedSprite::_reset_timeout() {
582
583 if (!playing)
584 return;
585
586 if (frames.is_valid() && frames->has_animation(animation)) {
587 float speed = frames->get_animation_speed(animation);
588 if (speed > 0) {
589 timeout = 1.0 / speed;
590 } else {
591 timeout = 0;
592 }
593 } else {
594 timeout = 0;
595 }
596 }
597
set_animation(const StringName & p_animation)598 void AnimatedSprite::set_animation(const StringName &p_animation) {
599
600 if (animation == p_animation)
601 return;
602
603 animation = p_animation;
604 _reset_timeout();
605 set_frame(0);
606 _change_notify();
607 update();
608 }
get_animation() const609 StringName AnimatedSprite::get_animation() const {
610
611 return animation;
612 }
613
get_configuration_warning() const614 String AnimatedSprite::get_configuration_warning() const {
615
616 if (frames.is_null()) {
617 return TTR("A SpriteFrames resource must be created or set in the 'Frames' property in order for AnimatedSprite to display frames.");
618 }
619
620 return String();
621 }
622
_bind_methods()623 void AnimatedSprite::_bind_methods() {
624
625 ObjectTypeDB::bind_method(_MD("set_sprite_frames", "sprite_frames:SpriteFrames"), &AnimatedSprite::set_sprite_frames);
626 ObjectTypeDB::bind_method(_MD("get_sprite_frames:SpriteFrames"), &AnimatedSprite::get_sprite_frames);
627
628 ObjectTypeDB::bind_method(_MD("set_animation", "animation"), &AnimatedSprite::set_animation);
629 ObjectTypeDB::bind_method(_MD("get_animation"), &AnimatedSprite::get_animation);
630
631 ObjectTypeDB::bind_method(_MD("_set_playing", "playing"), &AnimatedSprite::_set_playing);
632 ObjectTypeDB::bind_method(_MD("_is_playing"), &AnimatedSprite::_is_playing);
633
634 ObjectTypeDB::bind_method(_MD("play", "anim"), &AnimatedSprite::play, DEFVAL(StringName()));
635 ObjectTypeDB::bind_method(_MD("stop"), &AnimatedSprite::stop);
636 ObjectTypeDB::bind_method(_MD("is_playing"), &AnimatedSprite::is_playing);
637
638 ObjectTypeDB::bind_method(_MD("set_centered", "centered"), &AnimatedSprite::set_centered);
639 ObjectTypeDB::bind_method(_MD("is_centered"), &AnimatedSprite::is_centered);
640
641 ObjectTypeDB::bind_method(_MD("set_offset", "offset"), &AnimatedSprite::set_offset);
642 ObjectTypeDB::bind_method(_MD("get_offset"), &AnimatedSprite::get_offset);
643
644 ObjectTypeDB::bind_method(_MD("set_flip_h", "flip_h"), &AnimatedSprite::set_flip_h);
645 ObjectTypeDB::bind_method(_MD("is_flipped_h"), &AnimatedSprite::is_flipped_h);
646
647 ObjectTypeDB::bind_method(_MD("set_flip_v", "flip_v"), &AnimatedSprite::set_flip_v);
648 ObjectTypeDB::bind_method(_MD("is_flipped_v"), &AnimatedSprite::is_flipped_v);
649
650 ObjectTypeDB::bind_method(_MD("set_frame", "frame"), &AnimatedSprite::set_frame);
651 ObjectTypeDB::bind_method(_MD("get_frame"), &AnimatedSprite::get_frame);
652
653 ObjectTypeDB::bind_method(_MD("set_modulate", "modulate"), &AnimatedSprite::set_modulate);
654 ObjectTypeDB::bind_method(_MD("get_modulate"), &AnimatedSprite::get_modulate);
655
656 ObjectTypeDB::bind_method(_MD("_res_changed"), &AnimatedSprite::_res_changed);
657
658 ADD_SIGNAL(MethodInfo("frame_changed"));
659 ADD_SIGNAL(MethodInfo("finished"));
660
661 ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), _SCS("set_sprite_frames"), _SCS("get_sprite_frames"));
662 ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), _SCS("set_animation"), _SCS("get_animation"));
663 ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"), _SCS("get_frame"));
664 ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "playing"), _SCS("_set_playing"), _SCS("_is_playing"));
665 ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), _SCS("set_centered"), _SCS("is_centered"));
666 ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), _SCS("set_offset"), _SCS("get_offset"));
667 ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), _SCS("set_flip_h"), _SCS("is_flipped_h"));
668 ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), _SCS("set_flip_v"), _SCS("is_flipped_v"));
669 ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
670 }
671
AnimatedSprite()672 AnimatedSprite::AnimatedSprite() {
673
674 centered = true;
675 hflip = false;
676 vflip = false;
677
678 frame = 0;
679 playing = false;
680 animation = "default";
681 modulate = Color(1, 1, 1, 1);
682 timeout = 0;
683 }
684