Bläddra i källkod

Merge pull request #1000 from sanikoyes/Pr-tween-fix

Pr-tween-fix
Juan Linietsky 10 år sedan
förälder
incheckning
7dbc19f32d
3 ändrade filer med 146 tillägg och 98 borttagningar
  1. 2 2
      demos/misc/tween/main.gd
  2. 120 75
      scene/animation/tween.cpp
  3. 24 21
      scene/animation/tween.h

+ 2 - 2
demos/misc/tween/main.gd

@@ -112,8 +112,8 @@ func reset_tween():
 		tween.interpolate_property(sprite, "transform/rot", 360, 0, 2, state.trans, state.eases, 2)
 	
 	if get_node("modes/callback").is_pressed():
-		tween.interpolate_callback(self, "on_callback", 0.5, "0.5 second's after")
-		tween.interpolate_callback(self, "on_callback", 1.2, "1.2 second's after")
+		tween.interpolate_callback(self, 0.5, "on_callback", "0.5 second's after")
+		tween.interpolate_callback(self, 0.2, "on_callback", "1.2 second's after")
 	
 	if get_node("modes/follow").is_pressed():
 		follow.show()

+ 120 - 75
scene/animation/tween.cpp

@@ -124,32 +124,34 @@ void Tween::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode);
 
 	ObjectTypeDB::bind_method(_MD("start"),&Tween::start );
-	ObjectTypeDB::bind_method(_MD("reset","node","key"),&Tween::reset );
+	ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset );
 	ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all );
-	ObjectTypeDB::bind_method(_MD("stop","node","key"),&Tween::stop );
+	ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop );
 	ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all );
-	ObjectTypeDB::bind_method(_MD("resume","node","key"),&Tween::resume );
+	ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume );
 	ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all );
-	ObjectTypeDB::bind_method(_MD("remove","node","key"),&Tween::remove );
+	ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove );
 	ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all );
 	ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek );
 	ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell );
 	ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime );
 
-	ObjectTypeDB::bind_method(_MD("interpolate_property","node","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("interpolate_method","node","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("interpolate_callback","node","callback","times_in_sec","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
-	ObjectTypeDB::bind_method(_MD("follow_property","node","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("follow_method","node","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("targeting_property","node","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
-	ObjectTypeDB::bind_method(_MD("targeting_method","node","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","args"),&Tween::interpolate_callback, DEFVAL(Variant()) );
+	ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) );
+	ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) );
 
-	ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
-	ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
-	ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
+	ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
+	ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
+	ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) );
 
 	ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode"));
-	//ADD_PROPERTY( PropertyInfo( Variant::BOOL, "activate"), _SCS("set_active"), _SCS("is_active"));
+
+	BIND_CONSTANT(TWEEN_PROCESS_FIXED);
+	BIND_CONSTANT(TWEEN_PROCESS_IDLE);
 
 	BIND_CONSTANT(TRANS_LINEAR);
 	BIND_CONSTANT(TRANS_SINE);
@@ -181,19 +183,19 @@ Variant& Tween::_get_initial_val(InterpolateData& p_data) {
 		case TARGETING_PROPERTY:
 		case TARGETING_METHOD: {
 
-				Node *node = get_node(p_data.target);
-				ERR_FAIL_COND_V(node == NULL,p_data.initial_val);
+				Object *object = ObjectDB::get_instance(p_data.target_id);
+				ERR_FAIL_COND_V(object == NULL,p_data.initial_val);
 
 				static Variant initial_val;
 				if(p_data.type == TARGETING_PROPERTY) {
 
 					bool valid = false;
-					initial_val = node->get(p_data.target_key, &valid);
+					initial_val = object->get(p_data.target_key, &valid);
 					ERR_FAIL_COND_V(!valid,p_data.initial_val);
 				} else {
 
 					Variant::CallError error;
-					initial_val = node->call(p_data.target_key, NULL, 0, error);
+					initial_val = object->call(p_data.target_key, NULL, 0, error);
 					ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
 				}
 				return initial_val;
@@ -213,7 +215,7 @@ Variant& Tween::_get_delta_val(InterpolateData& p_data) {
 		case FOLLOW_PROPERTY:
 		case FOLLOW_METHOD: {
 
-				Node *target = get_node(p_data.target);
+				Object *target = ObjectDB::get_instance(p_data.target_id);
 				ERR_FAIL_COND_V(target == NULL,p_data.initial_val);
 
 				Variant final_val;
@@ -264,6 +266,11 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
 
 	switch(initial_val.get_type())
 	{
+
+	case Variant::BOOL:
+		result = ((int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec)) >= 0.5;
+		break;
+
 	case Variant::INT:
 		result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec);
 		break;
@@ -409,7 +416,7 @@ Variant Tween::_run_equation(InterpolateData& p_data) {
 
 bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
 
-	Object *object = get_node(p_data.path);
+	Object *object = ObjectDB::get_instance(p_data.id);
 	ERR_FAIL_COND_V(object == NULL, false);
 
 	switch(p_data.type) {
@@ -452,6 +459,7 @@ void Tween::_tween_process(float p_delta) {
 		return;
 	p_delta *= speed_scale;
 
+	pending_update ++;
 	// if repeat and all interpolates was finished then reset all interpolates
 	if(repeat) {
 		bool all_finished = true;
@@ -476,7 +484,7 @@ void Tween::_tween_process(float p_delta) {
 		if(!data.active || data.finish)
 			continue;
 
-		Object *object = get_node(data.path);
+		Object *object = ObjectDB::get_instance(data.id);
 		if(object == NULL)
 			continue;
 
@@ -523,6 +531,7 @@ void Tween::_tween_process(float p_delta) {
 		if(data.finish)
 			emit_signal("tween_complete",object,data.key);
 	}
+	pending_update --;
 }
 
 void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
@@ -598,16 +607,17 @@ bool Tween::start() {
 	return true;
 }
 
-bool Tween::reset(Node *p_node, String p_key) {
+bool Tween::reset(Object *p_object, String p_key) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
 
-		if(node == p_node && data.key == p_key) {
+		if(object == p_object && data.key == p_key) {
 
 			data.elapsed = 0;
 			data.finish = false;
@@ -615,11 +625,13 @@ bool Tween::reset(Node *p_node, String p_key) {
 				_apply_tween_value(data, data.initial_val);
 		}
 	}
+	pending_update --;
 	return true;
 }
 
 bool Tween::reset_all() {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
@@ -628,20 +640,23 @@ bool Tween::reset_all() {
 		if(data.delay == 0)
 			_apply_tween_value(data, data.initial_val);
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::stop(Node *p_node, String p_key) {
+bool Tween::stop(Object *p_object, String p_key) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key)
+		if(object == p_object && data.key == p_key)
 			data.active = false;
 	}
+	pending_update --;
 	return true;
 }
 
@@ -650,28 +665,32 @@ bool Tween::stop_all() {
 	set_active(false);
 	_set_process(false);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
 		data.active = false;
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::resume(Node *p_node, String p_key) {
+bool Tween::resume(Object *p_object, String p_key) {
 
 	set_active(true);
 	_set_process(true);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key)
+		if(object == p_object && data.key == p_key)
 			data.active = true;
 	}
+	pending_update --;
 	return true;
 }
 
@@ -680,23 +699,26 @@ bool Tween::resume_all() {
 	set_active(true);
 	_set_process(true);
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
 		data.active = true;
 	}
+	pending_update --;
 	return true;
 }
 
-bool Tween::remove(Node *p_node, String p_key) {
+bool Tween::remove(Object *p_object, String p_key) {
 
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
-		Node *node = get_node(data.path);
-		if(node == NULL)
+		Object *object = ObjectDB::get_instance(data.id);
+		if(object == NULL)
 			continue;
-		if(node == p_node && data.key == p_key) {
+		if(object == p_object && data.key == p_key) {
 			interpolates.erase(E);
 			return true;
 		}
@@ -706,6 +728,7 @@ bool Tween::remove(Node *p_node, String p_key) {
 
 bool Tween::remove_all() {
 
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	set_active(false);
 	_set_process(false);
 	interpolates.clear();
@@ -714,6 +737,7 @@ bool Tween::remove_all() {
 
 bool Tween::seek(real_t p_time) {
 
+	pending_update ++;
 	for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
 		InterpolateData& data = E->get();
@@ -744,11 +768,13 @@ bool Tween::seek(real_t p_time) {
 
 		_apply_tween_value(data, result);
 	}
+	pending_update --;
 	return true;
 }
 
 real_t Tween::tell() const {
 
+	pending_update ++;
 	real_t pos = 0;
 	for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
@@ -756,11 +782,13 @@ real_t Tween::tell() const {
 		if(data.elapsed > pos)
 			pos = data.elapsed;
 	}
+	pending_update --;
 	return pos;
 }
 
 real_t Tween::get_runtime() const {
 
+	pending_update ++;
 	real_t runtime = 0;
 	for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) {
 
@@ -769,6 +797,7 @@ real_t Tween::get_runtime() const {
 		if(t > runtime)
 			runtime = t;
 	}
+	pending_update --;
 	return runtime;
 }
 
@@ -779,6 +808,12 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
 	Variant& delta_val = p_delta_val;
 
 	switch(initial_val.get_type()) {
+
+		case Variant::BOOL:
+			//delta_val = p_final_val;
+			delta_val = (int) p_final_val - (int) p_initial_val;
+			break;
+
 		case Variant::INT:
 			delta_val = (int) final_val - (int) initial_val;
 			break;
@@ -873,7 +908,7 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final
 	return true;
 }
 
-bool Tween::interpolate_property(Node *p_node
+bool Tween::interpolate_property(Object *p_object
 	, String p_property
 	, Variant p_initial_val
 	, Variant p_final_val
@@ -882,11 +917,12 @@ bool Tween::interpolate_property(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -894,7 +930,7 @@ bool Tween::interpolate_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	InterpolateData data;
@@ -903,7 +939,7 @@ bool Tween::interpolate_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
 	data.initial_val = p_initial_val;
 	data.final_val = p_final_val;
@@ -919,7 +955,7 @@ bool Tween::interpolate_property(Node *p_node
 	return true;
 }
 
-bool Tween::interpolate_method(Node *p_node
+bool Tween::interpolate_method(Object *p_object
 	, String p_method
 	, Variant p_initial_val
 	, Variant p_final_val
@@ -928,18 +964,19 @@ bool Tween::interpolate_method(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 
 	InterpolateData data;
 	data.active = true;
@@ -947,7 +984,7 @@ bool Tween::interpolate_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
 	data.initial_val = p_initial_val;
 	data.final_val = p_final_val;
@@ -963,16 +1000,17 @@ bool Tween::interpolate_method(Node *p_node
 	return true;
 }
 
-bool Tween::interpolate_callback(Node *p_node
-	, String p_callback
+bool Tween::interpolate_callback(Object *p_object
 	, real_t p_times_in_sec
+	, String p_callback
 	, Variant p_arg
 ) {
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(pending_update != 0, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_callback), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_callback), false);
 
 	InterpolateData data;
 	data.active = true;
@@ -980,30 +1018,33 @@ bool Tween::interpolate_callback(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_callback;
 	data.times_in_sec = p_times_in_sec;
 	data.delay = 0;
 	data.arg = p_arg;
 
+	pending_update ++;
 	interpolates.push_back(data);
+	pending_update --;
 	return true;
 }
 
-bool Tween::follow_property(Node *p_node
+bool Tween::follow_property(Object *p_object
 	, String p_property
 	, Variant p_initial_val
-	, Node *p_target
+	, Object *p_target
 	, String p_target_property
 	, real_t p_times_in_sec
 	, TransitionType p_trans_type
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_target == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -1011,7 +1052,7 @@ bool Tween::follow_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	bool target_prop_valid = false;
@@ -1028,10 +1069,10 @@ bool Tween::follow_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
 	data.initial_val = p_initial_val;
-	data.target = p_target->get_path();
+	data.target_id = p_target->get_instance_ID();
 	data.target_key = p_target_property;
 	data.times_in_sec = p_times_in_sec;
 	data.trans_type = p_trans_type;
@@ -1042,27 +1083,28 @@ bool Tween::follow_property(Node *p_node
 	return true;
 }
 
-bool Tween::follow_method(Node *p_node
+bool Tween::follow_method(Object *p_object
 	, String p_method
 	, Variant p_initial_val
-	, Node *p_target
+	, Object *p_target
 	, String p_target_method
 	, real_t p_times_in_sec
 	, TransitionType p_trans_type
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_target == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 	ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false);
 
 	Variant::CallError error;
@@ -1079,10 +1121,10 @@ bool Tween::follow_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
 	data.initial_val = p_initial_val;
-	data.target = p_target->get_path();
+	data.target_id = p_target->get_instance_ID();
 	data.target_key = p_target_method;
 	data.times_in_sec = p_times_in_sec;
 	data.trans_type = p_trans_type;
@@ -1093,9 +1135,9 @@ bool Tween::follow_method(Node *p_node
 	return true;
 }
 
-bool Tween::targeting_property(Node *p_node
+bool Tween::targeting_property(Object *p_object
 	, String p_property
-	, Node *p_initial
+	, Object *p_initial
 	, String p_initial_property
 	, Variant p_final_val
 	, real_t p_times_in_sec
@@ -1103,10 +1145,11 @@ bool Tween::targeting_property(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
@@ -1114,7 +1157,7 @@ bool Tween::targeting_property(Node *p_node
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
 	bool prop_valid = false;
-	p_node->get(p_property,&prop_valid);
+	p_object->get(p_property,&prop_valid);
 	ERR_FAIL_COND_V(!prop_valid, false);
 
 	bool initial_prop_valid = false;
@@ -1131,9 +1174,9 @@ bool Tween::targeting_property(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_property;
-	data.target = p_initial->get_path();
+	data.target_id = p_initial->get_instance_ID();
 	data.target_key = p_initial_property;
 	data.initial_val = initial_val;
 	data.final_val = p_final_val;
@@ -1150,9 +1193,9 @@ bool Tween::targeting_property(Node *p_node
 }
 
 
-bool Tween::targeting_method(Node *p_node
+bool Tween::targeting_method(Object *p_object
 	, String p_method
-	, Node *p_initial
+	, Object *p_initial
 	, String p_initial_method
 	, Variant p_final_val
 	, real_t p_times_in_sec
@@ -1160,17 +1203,18 @@ bool Tween::targeting_method(Node *p_node
 	, EaseType p_ease_type
 	, real_t p_delay
 ) {
+	ERR_FAIL_COND_V(pending_update != 0, false);
 	// convert INT to REAL is better for interpolaters
 	if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t();
 
-	ERR_FAIL_COND_V(p_node == NULL, false);
+	ERR_FAIL_COND_V(p_object == NULL, false);
 	ERR_FAIL_COND_V(p_initial == NULL, false);
 	ERR_FAIL_COND_V(p_times_in_sec <= 0, false);
 	ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false);
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false);
 	ERR_FAIL_COND_V(p_delay < 0, false);
 
-	ERR_FAIL_COND_V(!p_node->has_method(p_method), false);
+	ERR_FAIL_COND_V(!p_object->has_method(p_method), false);
 	ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false);
 
 	Variant::CallError error;
@@ -1187,9 +1231,9 @@ bool Tween::targeting_method(Node *p_node
 	data.finish = false;
 	data.elapsed = 0;
 
-	data.path = p_node->get_path();
+	data.id = p_object->get_instance_ID();
 	data.key = p_method;
-	data.target = p_initial->get_path();
+	data.target_id = p_initial->get_instance_ID();
 	data.target_key = p_initial_method;
 	data.initial_val = initial_val;
 	data.final_val = p_final_val;
@@ -1213,6 +1257,7 @@ Tween::Tween() {
 	active=false;
 	repeat=false;
 	speed_scale=1;
+	pending_update=0;
 }
 
 Tween::~Tween() {

+ 24 - 21
scene/animation/tween.h

@@ -54,15 +54,17 @@ public:
         TRANS_CIRC,
         TRANS_BOUNCE,
         TRANS_BACK,
-	TRANS_COUNT,
+
+		TRANS_COUNT,
     };
         
     enum EaseType {
         EASE_IN,
         EASE_OUT,
         EASE_IN_OUT,
-	EASE_OUT_IN,
-	EASE_COUNT,
+		EASE_OUT_IN,
+
+		EASE_COUNT,
     };
 
 private:
@@ -82,12 +84,12 @@ private:
 		InterpolateType type;
 		bool finish;
 		real_t elapsed;
-		NodePath path;
+		ObjectID id;
 		StringName key;
 		Variant initial_val;
 		Variant delta_val;
 		Variant final_val;
-		NodePath target;
+		ObjectID target_id;
 		StringName target_key;
 		real_t times_in_sec;
 		TransitionType trans_type;
@@ -102,6 +104,7 @@ private:
 	bool active;
 	bool repeat;
 	float speed_scale;
+	mutable int pending_update;
 
 	List<InterpolateData> interpolates;
 
@@ -142,20 +145,20 @@ public:
 	float get_speed() const;
 
 	bool start();
-	bool reset(Node *p_node, String p_key);
+	bool reset(Object *p_node, String p_key);
 	bool reset_all();
-	bool stop(Node *p_node, String p_key);
+	bool stop(Object *p_node, String p_key);
 	bool stop_all();
-	bool resume(Node *p_node, String p_key);
+	bool resume(Object *p_node, String p_key);
 	bool resume_all();
-	bool remove(Node *p_node, String p_key);
+	bool remove(Object *p_node, String p_key);
 	bool remove_all();
 
 	bool seek(real_t p_time);
 	real_t tell() const;
 	real_t get_runtime() const;
 
-	bool interpolate_property(Node *p_node
+	bool interpolate_property(Object *p_node
 		, String p_property
 		, Variant p_initial_val
 		, Variant p_final_val
@@ -165,7 +168,7 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool interpolate_method(Node *p_node
+	bool interpolate_method(Object *p_node
 		, String p_method
 		, Variant p_initial_val
 		, Variant p_final_val
@@ -175,16 +178,16 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool interpolate_callback(Node *p_node
-		, String p_callback
+	bool interpolate_callback(Object *p_node
 		, real_t p_times_in_sec
+		, String p_callback
 		, Variant p_arg = Variant()
 	);
 
-	bool follow_property(Node *p_node
+	bool follow_property(Object *p_node
 		, String p_property
 		, Variant p_initial_val
-		, Node *p_target
+		, Object *p_target
 		, String p_target_property
 		, real_t p_times_in_sec
 		, TransitionType p_trans_type
@@ -192,10 +195,10 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool follow_method(Node *p_node
+	bool follow_method(Object *p_node
 		, String p_method
 		, Variant p_initial_val
-		, Node *p_target
+		, Object *p_target
 		, String p_target_method
 		, real_t p_times_in_sec
 		, TransitionType p_trans_type
@@ -203,9 +206,9 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool targeting_property(Node *p_node
+	bool targeting_property(Object *p_node
 		, String p_property
-		, Node *p_initial
+		, Object *p_initial
 		, String p_initial_property
 		, Variant p_final_val
 		, real_t p_times_in_sec
@@ -214,9 +217,9 @@ public:
 		, real_t p_delay = 0
 	);
 
-	bool targeting_method(Node *p_node
+	bool targeting_method(Object *p_node
 		, String p_method
-		, Node *p_initial
+		, Object *p_initial
 		, String p_initial_method
 		, Variant p_final_val
 		, real_t p_times_in_sec