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