Selaa lähdekoodia

tween:
1、add follow/targeting support
2、update demo

sanikoyes 11 vuotta sitten
vanhempi
commit
64413191a9
4 muutettua tiedostoa jossa 428 lisäystä ja 47 poistoa
  1. 24 5
      demos/misc/tween/main.gd
  2. 12 7
      demos/misc/tween/main.xml
  3. 336 30
      scene/animation/tween.cpp
  4. 56 5
      scene/animation/tween.h

+ 24 - 5
demos/misc/tween/main.gd

@@ -7,7 +7,7 @@ extends Control
 
 
 var trans = ["linear", "sine", "quint", "quart", "quad", "expo", "elastic", "cubic", "circ", "bounce", "back"]
 var trans = ["linear", "sine", "quint", "quart", "quad", "expo", "elastic", "cubic", "circ", "bounce", "back"]
 var eases = ["in", "out", "in_out", "out_in"]
 var eases = ["in", "out", "in_out", "out_in"]
-var modes = ["move", "color", "scale", "rotate", "callback", "repeat", "pause"]
+var modes = ["move", "color", "scale", "rotate", "callback", "follow", "repeat", "pause"]
 
 
 var state = {
 var state = {
 	trans = Tween.TRANS_LINEAR,
 	trans = Tween.TRANS_LINEAR,
@@ -82,35 +82,54 @@ func on_color_changed(color):
 	
 	
 func reset_tween():
 func reset_tween():
 	var tween = get_node("tween")
 	var tween = get_node("tween")
+	var pos = tween.tell()
 	tween.reset_all()
 	tween.reset_all()
 	tween.remove_all()
 	tween.remove_all()
 	
 	
 	var sprite = get_node("tween/area/sprite")
 	var sprite = get_node("tween/area/sprite")
+	var follow = get_node("tween/area/follow")
+	var follow_2 = get_node("tween/area/follow_2")
 	
 	
 	if get_node("modes/move").is_pressed():
 	if get_node("modes/move").is_pressed():
 		tween.interpolate_method(sprite, "set_pos", Vector2(0,0), Vector2(736, 184), 2, state.trans, state.eases)
 		tween.interpolate_method(sprite, "set_pos", Vector2(0,0), Vector2(736, 184), 2, state.trans, state.eases)
-		tween.interpolate_method(sprite, "set_pos", Vector2(736,184), Vector2(0, 0), 2, state.trans, state.eases, 2)
+		tween.interpolate_property(sprite, "transform/pos", Vector2(736,184), Vector2(0, 0), 2, state.trans, state.eases, 2)
 	
 	
 	if get_node("modes/color").is_pressed():
 	if get_node("modes/color").is_pressed():
 		tween.interpolate_method(sprite, "set_modulate", get_node("color/color_from").get_color(), get_node("color/color_to").get_color(), 2, state.trans, state.eases)
 		tween.interpolate_method(sprite, "set_modulate", get_node("color/color_from").get_color(), get_node("color/color_to").get_color(), 2, state.trans, state.eases)
-		tween.interpolate_method(sprite, "set_modulate", get_node("color/color_to").get_color(), get_node("color/color_from").get_color(), 2, state.trans, state.eases, 2)
+		tween.interpolate_property(sprite, "modulate", get_node("color/color_to").get_color(), get_node("color/color_from").get_color(), 2, state.trans, state.eases, 2)
 	else:
 	else:
 		sprite.set_modulate(Color(1, 1, 1, 1))
 		sprite.set_modulate(Color(1, 1, 1, 1))
 	
 	
 	if get_node("modes/scale").is_pressed():
 	if get_node("modes/scale").is_pressed():
 		tween.interpolate_method(sprite, "set_scale", Vector2(0.5,0.5), Vector2(1.5, 1.5), 2, state.trans, state.eases)
 		tween.interpolate_method(sprite, "set_scale", Vector2(0.5,0.5), Vector2(1.5, 1.5), 2, state.trans, state.eases)
-		tween.interpolate_method(sprite, "set_scale", Vector2(1.5,1.5), Vector2(0.5, 0.5), 2, state.trans, state.eases, 2)
+		tween.interpolate_property(sprite, "transform/scale", Vector2(1.5,1.5), Vector2(0.5, 0.5), 2, state.trans, state.eases, 2)
+	else:
+		sprite.set_scale(Vector2(1, 1))
 	
 	
 	if get_node("modes/rotate").is_pressed():
 	if get_node("modes/rotate").is_pressed():
 		tween.interpolate_method(sprite, "set_rot", 0, 6.28, 2, state.trans, state.eases)
 		tween.interpolate_method(sprite, "set_rot", 0, 6.28, 2, state.trans, state.eases)
-		tween.interpolate_method(sprite, "set_rot", 6.28, 0, 2, state.trans, state.eases, 2)
+		tween.interpolate_property(sprite, "transform/rot", 6.28, 0, 2, state.trans, state.eases, 2)
 	
 	
 	if get_node("modes/callback").is_pressed():
 	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", 0.5, "0.5 second's after")
 		tween.interpolate_callback(self, "on_callback", 1.2, "1.2 second's after")
 		tween.interpolate_callback(self, "on_callback", 1.2, "1.2 second's after")
 	
 	
+	if get_node("modes/follow").is_pressed():
+		follow.show()
+		follow_2.show()
+		
+		tween.follow_method(follow, "set_pos", Vector2(0, 184), sprite, "get_pos", 2, state.trans, state.eases)
+		tween.targeting_method(follow, "set_pos", sprite, "get_pos", Vector2(0, 184), 2, state.trans, state.eases, 2)
+		
+		tween.targeting_property(follow_2, "transform/pos", sprite, "transform/pos", Vector2(736, 0), 2, state.trans, state.eases)
+		tween.follow_property(follow_2, "transform/pos", Vector2(736, 0), sprite, "transform/pos", 2, state.trans, state.eases, 2)
+	else:
+		follow.hide()
+		follow_2.hide()
+	
 	tween.set_repeat(get_node("modes/repeat").is_pressed())
 	tween.set_repeat(get_node("modes/repeat").is_pressed())
 	tween.start()
 	tween.start()
+	tween.seek(pos)
 	
 	
 	if get_node("modes/pause").is_pressed():
 	if get_node("modes/pause").is_pressed():
 		tween.stop_all()
 		tween.stop_all()

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 12 - 7
demos/misc/tween/main.xml


+ 336 - 30
scene/animation/tween.cpp

@@ -138,6 +138,10 @@ void Tween::_bind_methods() {
 	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_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_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("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) );
 
 
 	ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) );
 	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_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) );
@@ -164,10 +168,94 @@ void Tween::_bind_methods() {
 	BIND_CONSTANT(EASE_OUT_IN);
 	BIND_CONSTANT(EASE_OUT_IN);
 }
 }
 
 
+Variant& Tween::_get_initial_val(InterpolateData& p_data) {
+
+	switch(p_data.type) {
+		case INTER_PROPERTY:
+		case INTER_METHOD:
+		case FOLLOW_PROPERTY:
+		case FOLLOW_METHOD:
+			return p_data.initial_val;
+
+		case TARGETING_PROPERTY:
+		case TARGETING_METHOD: {
+
+				Node *node = get_node(p_data.target);
+				ERR_FAIL_COND_V(node == 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);
+					ERR_FAIL_COND_V(!valid,p_data.initial_val);
+				} else {
+
+					Variant::CallError error;
+					initial_val = node->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;
+			}
+			break;
+	}
+	return p_data.delta_val;
+}
+
+Variant& Tween::_get_delta_val(InterpolateData& p_data) {
+
+	switch(p_data.type) {
+		case INTER_PROPERTY:
+		case INTER_METHOD:
+			return p_data.delta_val;
+
+		case FOLLOW_PROPERTY:
+		case FOLLOW_METHOD: {
+
+				Node *target = get_node(p_data.target);
+				ERR_FAIL_COND_V(target == NULL,p_data.initial_val);
+
+				Variant final_val;
+
+				if(p_data.type == FOLLOW_PROPERTY) {
+
+					bool valid = false;
+					final_val = target->get(p_data.target_key, &valid);
+					ERR_FAIL_COND_V(!valid,p_data.initial_val);
+				} else {
+
+					Variant::CallError error;
+					final_val = target->call(p_data.target_key, NULL, 0, error);
+					ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val);
+				}
+
+				// convert INT to REAL is better for interpolaters
+				if(final_val.get_type() == Variant::INT) final_val = final_val.operator real_t();
+				_calc_delta_val(p_data.initial_val, final_val, p_data.delta_val);
+				return p_data.delta_val;
+			}
+			break;
+
+		case TARGETING_PROPERTY:
+		case TARGETING_METHOD: {
+
+				Variant initial_val = _get_initial_val(p_data);
+				// convert INT to REAL is better for interpolaters
+				if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+
+				//_calc_delta_val(p_data.initial_val, p_data.final_val, p_data.delta_val);
+				_calc_delta_val(initial_val, p_data.final_val, p_data.delta_val);
+				return p_data.delta_val;
+			}
+			break;
+	}
+	return p_data.initial_val;
+}
+
 Variant Tween::_run_equation(InterpolateData& p_data) {
 Variant Tween::_run_equation(InterpolateData& p_data) {
 
 
-	Variant& initial_val = p_data.initial_val;
-	Variant& delta_val = p_data.delta_val;
+	Variant& initial_val = _get_initial_val(p_data);
+	Variant& delta_val = _get_delta_val(p_data);
 	Variant result;
 	Variant result;
 
 
 #define APPLY_EQUATION(element)\
 #define APPLY_EQUATION(element)\
@@ -326,6 +414,8 @@ bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
 	switch(p_data.type) {
 	switch(p_data.type) {
 
 
 		case INTER_PROPERTY:
 		case INTER_PROPERTY:
+		case FOLLOW_PROPERTY:
+		case TARGETING_PROPERTY:
 			{
 			{
 				bool valid = false;
 				bool valid = false;
 				object->set(p_data.key,value, &valid);
 				object->set(p_data.key,value, &valid);
@@ -333,11 +423,17 @@ bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) {
 			}
 			}
 
 
 		case INTER_METHOD:
 		case INTER_METHOD:
+		case FOLLOW_METHOD:
+		case TARGETING_METHOD:
 			{
 			{
-				Variant *arg[1] = { &value };
-
 				Variant::CallError error;
 				Variant::CallError error;
-				object->call(p_data.key, (const Variant **) arg, 1, error);
+				if (value.get_type() != Variant::NIL) {
+					Variant *arg[1] = { &value };
+					object->call(p_data.key, (const Variant **) arg, 1, error);
+				} else {
+					object->call(p_data.key, NULL, 0, error);
+				}
+
 				if(error.error == Variant::CallError::CALL_OK)
 				if(error.error == Variant::CallError::CALL_OK)
 					return true;
 					return true;
 				return false;
 				return false;
@@ -387,8 +483,11 @@ void Tween::_tween_process(float p_delta) {
 		data.elapsed += p_delta;
 		data.elapsed += p_delta;
 		if(data.elapsed < data.delay)
 		if(data.elapsed < data.delay)
 			continue;
 			continue;
-		else if(prev_delaying)
+		else if(prev_delaying) {
+
 			emit_signal("tween_start",object,data.key);
 			emit_signal("tween_start",object,data.key);
+			_apply_tween_value(data, data.initial_val);
+		}
 
 
 		if(data.elapsed > (data.delay + data.times_in_sec)) {
 		if(data.elapsed > (data.delay + data.times_in_sec)) {
 
 
@@ -404,10 +503,13 @@ void Tween::_tween_process(float p_delta) {
 		case INTER_CALLBACK:
 		case INTER_CALLBACK:
 			if(data.finish) {
 			if(data.finish) {
 
 
-				Variant *arg[1] = { &data.args };
-
 				Variant::CallError error;
 				Variant::CallError error;
-				object->call(data.key, (const Variant **) arg, 1, error);
+				if (data.arg.get_type() != Variant::NIL) {
+					Variant *arg[1] = { &data.arg };
+					object->call(data.key, (const Variant **) arg, 1, error);
+				} else {
+					object->call(data.key, NULL, 0, error);
+				}
 			}
 			}
 			continue;
 			continue;
 		}
 		}
@@ -669,11 +771,11 @@ real_t Tween::get_runtime() const {
 	return runtime;
 	return runtime;
 }
 }
 
 
-bool Tween::_calc_delta_val(InterpolateData& p_data) {
+bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final_val, Variant& p_delta_val) {
 
 
-	Variant& initial_val = p_data.initial_val;
-	Variant& delta_val = p_data.delta_val;
-	Variant& final_val = p_data.final_val;
+	const Variant& initial_val = p_initial_val;
+	const Variant& final_val = p_final_val;
+	Variant& delta_val = p_delta_val;
 
 
 	switch(initial_val.get_type()) {
 	switch(initial_val.get_type()) {
 		case Variant::INT:
 		case Variant::INT:
@@ -790,19 +892,9 @@ bool Tween::interpolate_property(Node *p_node
 	ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_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_delay < 0, false);
 
 
-	bool prop_found = false;
-	List<PropertyInfo> props;
-	p_node->get_property_list(&props);
-	for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
-
-		PropertyInfo& prop=E->get();
-		if(prop.name==p_property)
-		{
-			prop_found = true;
-			break;
-		}
-	}
-	ERR_FAIL_COND_V(!prop_found, false);
+	bool prop_valid = false;
+	p_node->get(p_property,&prop_valid);
+	ERR_FAIL_COND_V(!prop_valid, false);
 
 
 	InterpolateData data;
 	InterpolateData data;
 	data.active = true;
 	data.active = true;
@@ -819,7 +911,7 @@ bool Tween::interpolate_property(Node *p_node
 	data.ease_type = p_ease_type;
 	data.ease_type = p_ease_type;
 	data.delay = p_delay;
 	data.delay = p_delay;
 
 
-	if(!_calc_delta_val(data))
+	if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
 		return false;
 		return false;
 
 
 	interpolates.push_back(data);
 	interpolates.push_back(data);
@@ -863,7 +955,7 @@ bool Tween::interpolate_method(Node *p_node
 	data.ease_type = p_ease_type;
 	data.ease_type = p_ease_type;
 	data.delay = p_delay;
 	data.delay = p_delay;
 
 
-	if(!_calc_delta_val(data))
+	if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
 		return false;
 		return false;
 
 
 	interpolates.push_back(data);
 	interpolates.push_back(data);
@@ -873,7 +965,7 @@ bool Tween::interpolate_method(Node *p_node
 bool Tween::interpolate_callback(Node *p_node
 bool Tween::interpolate_callback(Node *p_node
 	, String p_callback
 	, String p_callback
 	, real_t p_times_in_sec
 	, real_t p_times_in_sec
-	, Variant p_args
+	, Variant p_arg
 ) {
 ) {
 
 
 	ERR_FAIL_COND_V(p_node == NULL, false);
 	ERR_FAIL_COND_V(p_node == NULL, false);
@@ -891,13 +983,227 @@ bool Tween::interpolate_callback(Node *p_node
 	data.key = p_callback;
 	data.key = p_callback;
 	data.times_in_sec = p_times_in_sec;
 	data.times_in_sec = p_times_in_sec;
 	data.delay = 0;
 	data.delay = 0;
-	data.args = p_args;
+	data.arg = p_arg;
+
+	interpolates.push_back(data);
+	return true;
+}
+
+bool Tween::follow_property(Node *p_node
+	, String p_property
+	, Variant p_initial_val
+	, Node *p_target
+	, String p_target_property
+	, real_t p_times_in_sec
+	, TransitionType p_trans_type
+	, EaseType p_ease_type
+	, real_t p_delay
+) {
+	// 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_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);
+
+	bool prop_valid = false;
+	p_node->get(p_property,&prop_valid);
+	ERR_FAIL_COND_V(!prop_valid, false);
+
+	bool target_prop_valid = false;
+	Variant target_val = p_target->get(p_target_property,&target_prop_valid);
+	ERR_FAIL_COND_V(!target_prop_valid, false);
+
+	// convert INT to REAL is better for interpolaters
+	if(target_val.get_type() == Variant::INT) target_val = target_val.operator real_t();
+	ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false);
+
+	InterpolateData data;
+	data.active = true;
+	data.type = FOLLOW_PROPERTY;
+	data.finish = false;
+	data.elapsed = 0;
+
+	data.path = p_node->get_path();
+	data.key = p_property;
+	data.initial_val = p_initial_val;
+	data.target = p_target->get_path();
+	data.target_key = p_target_property;
+	data.times_in_sec = p_times_in_sec;
+	data.trans_type = p_trans_type;
+	data.ease_type = p_ease_type;
+	data.delay = p_delay;
+
+	interpolates.push_back(data);
+	return true;
+}
+
+bool Tween::follow_method(Node *p_node
+	, String p_method
+	, Variant p_initial_val
+	, Node *p_target
+	, String p_target_method
+	, real_t p_times_in_sec
+	, TransitionType p_trans_type
+	, EaseType p_ease_type
+	, real_t p_delay
+) {
+	// 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_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_target->has_method(p_target_method), false);
+
+	Variant::CallError error;
+	Variant target_val = p_target->call(p_target_method, NULL, 0, error);
+	ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false);
+
+	// convert INT to REAL is better for interpolaters
+	if(target_val.get_type() == Variant::INT) target_val = target_val.operator real_t();
+	ERR_FAIL_COND_V(target_val.get_type() != p_initial_val.get_type(), false);
+
+	InterpolateData data;
+	data.active = true;
+	data.type = FOLLOW_METHOD;
+	data.finish = false;
+	data.elapsed = 0;
+
+	data.path = p_node->get_path();
+	data.key = p_method;
+	data.initial_val = p_initial_val;
+	data.target = p_target->get_path();
+	data.target_key = p_target_method;
+	data.times_in_sec = p_times_in_sec;
+	data.trans_type = p_trans_type;
+	data.ease_type = p_ease_type;
+	data.delay = p_delay;
+
+	interpolates.push_back(data);
+	return true;
+}
+
+bool Tween::targeting_property(Node *p_node
+	, String p_property
+	, Node *p_initial
+	, String p_initial_property
+	, Variant p_final_val
+	, real_t p_times_in_sec
+	, TransitionType p_trans_type
+	, EaseType p_ease_type
+	, real_t p_delay
+) {
+	// 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_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);
+
+	bool prop_valid = false;
+	p_node->get(p_property,&prop_valid);
+	ERR_FAIL_COND_V(!prop_valid, false);
+
+	bool initial_prop_valid = false;
+	Variant initial_val = p_initial->get(p_initial_property,&initial_prop_valid);
+	ERR_FAIL_COND_V(!initial_prop_valid, false);
+
+	// convert INT to REAL is better for interpolaters
+	if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+	ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false);
+
+	InterpolateData data;
+	data.active = true;
+	data.type = TARGETING_PROPERTY;
+	data.finish = false;
+	data.elapsed = 0;
+
+	data.path = p_node->get_path();
+	data.key = p_property;
+	data.target = p_initial->get_path();
+	data.target_key = p_initial_property;
+	data.initial_val = initial_val;
+	data.final_val = p_final_val;
+	data.times_in_sec = p_times_in_sec;
+	data.trans_type = p_trans_type;
+	data.ease_type = p_ease_type;
+	data.delay = p_delay;
+
+	if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+		return false;
 
 
 	interpolates.push_back(data);
 	interpolates.push_back(data);
 	return true;
 	return true;
 }
 }
 
 
 
 
+bool Tween::targeting_method(Node *p_node
+	, String p_method
+	, Node *p_initial
+	, String p_initial_method
+	, Variant p_final_val
+	, real_t p_times_in_sec
+	, TransitionType p_trans_type
+	, EaseType p_ease_type
+	, real_t p_delay
+) {
+	// 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_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_initial->has_method(p_initial_method), false);
+
+	Variant::CallError error;
+	Variant initial_val = p_initial->call(p_initial_method, NULL, 0, error);
+	ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK, false);
+
+	// convert INT to REAL is better for interpolaters
+	if(initial_val.get_type() == Variant::INT) initial_val = initial_val.operator real_t();
+	ERR_FAIL_COND_V(initial_val.get_type() != p_final_val.get_type(), false);
+
+	InterpolateData data;
+	data.active = true;
+	data.type = TARGETING_METHOD;
+	data.finish = false;
+	data.elapsed = 0;
+
+	data.path = p_node->get_path();
+	data.key = p_method;
+	data.target = p_initial->get_path();
+	data.target_key = p_initial_method;
+	data.initial_val = initial_val;
+	data.final_val = p_final_val;
+	data.times_in_sec = p_times_in_sec;
+	data.trans_type = p_trans_type;
+	data.ease_type = p_ease_type;
+	data.delay = p_delay;
+
+	if(!_calc_delta_val(data.initial_val, data.final_val, data.delta_val))
+		return false;
+
+	interpolates.push_back(data);
+	return true;
+}
+
 Tween::Tween() {
 Tween::Tween() {
 
 
 	//String autoplay;
 	//String autoplay;

+ 56 - 5
scene/animation/tween.h

@@ -72,6 +72,10 @@ private:
 
 
 		INTER_PROPERTY,
 		INTER_PROPERTY,
 		INTER_METHOD,
 		INTER_METHOD,
+		FOLLOW_PROPERTY,
+		FOLLOW_METHOD,
+		TARGETING_PROPERTY,
+		TARGETING_METHOD,
 		INTER_CALLBACK,
 		INTER_CALLBACK,
 	};
 	};
 
 
@@ -80,17 +84,18 @@ private:
 		InterpolateType type;
 		InterpolateType type;
 		bool finish;
 		bool finish;
 		real_t elapsed;
 		real_t elapsed;
-
 		NodePath path;
 		NodePath path;
-		String key;
+		StringName key;
 		Variant initial_val;
 		Variant initial_val;
 		Variant delta_val;
 		Variant delta_val;
 		Variant final_val;
 		Variant final_val;
+		NodePath target;
+		StringName target_key;
 		real_t times_in_sec;
 		real_t times_in_sec;
 		TransitionType trans_type;
 		TransitionType trans_type;
 		EaseType ease_type;
 		EaseType ease_type;
 		real_t delay;
 		real_t delay;
-		Variant args;
+		Variant arg;
 	};
 	};
 
 
 	String autoplay;
 	String autoplay;
@@ -106,8 +111,10 @@ private:
 	static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
 	static interpolater interpolaters[TRANS_COUNT][EASE_COUNT];
 
 
 	real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
 	real_t _run_equation(TransitionType p_trans_type, EaseType p_ease_type, real_t t, real_t b, real_t c, real_t d);
+	Variant& _get_delta_val(InterpolateData& p_data);
+	Variant& _get_initial_val(InterpolateData& p_data);
 	Variant _run_equation(InterpolateData& p_data);
 	Variant _run_equation(InterpolateData& p_data);
-	bool _calc_delta_val(InterpolateData& p_data);
+	bool _calc_delta_val(const Variant& p_initial_val, const Variant& p_final_val, Variant& p_delta_val);
 	bool _apply_tween_value(InterpolateData& p_data, Variant& value);
 	bool _apply_tween_value(InterpolateData& p_data, Variant& value);
 
 
 	void _tween_process(float p_delta);
 	void _tween_process(float p_delta);
@@ -173,7 +180,51 @@ public:
 	bool interpolate_callback(Node *p_node
 	bool interpolate_callback(Node *p_node
 		, String p_callback
 		, String p_callback
 		, real_t p_times_in_sec
 		, real_t p_times_in_sec
-		, Variant p_args = Variant()
+		, Variant p_arg = Variant()
+	);
+
+	bool follow_property(Node *p_node
+		, String p_property
+		, Variant p_initial_val
+		, Node *p_target
+		, String p_target_property
+		, real_t p_times_in_sec
+		, TransitionType p_trans_type
+		, EaseType p_ease_type
+		, real_t p_delay = 0
+	);
+
+	bool follow_method(Node *p_node
+		, String p_method
+		, Variant p_initial_val
+		, Node *p_target
+		, String p_target_method
+		, real_t p_times_in_sec
+		, TransitionType p_trans_type
+		, EaseType p_ease_type
+		, real_t p_delay = 0
+	);
+
+	bool targeting_property(Node *p_node
+		, String p_property
+		, Node *p_initial
+		, String p_initial_property
+		, Variant p_final_val
+		, real_t p_times_in_sec
+		, TransitionType p_trans_type
+		, EaseType p_ease_type
+		, real_t p_delay = 0
+	);
+
+	bool targeting_method(Node *p_node
+		, String p_method
+		, Node *p_initial
+		, String p_initial_method
+		, Variant p_final_val
+		, real_t p_times_in_sec
+		, TransitionType p_trans_type
+		, EaseType p_ease_type
+		, real_t p_delay = 0
 	);
 	);
 
 
 	Tween();
 	Tween();

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä