浏览代码

[godot] SpineSprite preview properties, finished SpineBoneNode, bone node example.

badlogic 3 年之前
父节点
当前提交
e5393dfed9

+ 24 - 1
spine-godot/example/examples/11-bone-node/bone-node.gd

@@ -1,5 +1,28 @@
 extends Node2D
 
+onready var spineboy = $SpineSprite
+onready var center_bone = $SpineSprite/HoverboardCenterBone
+onready var center_ray = $SpineSprite/HoverboardCenterBone/RayCast2D
+onready var target_bone = $SpineSprite/HoverboardTargetBone
+onready var target_ray = $SpineSprite/HoverboardTargetBone/RayCast2D
+onready var hip_bone = $SpineSprite/HipBone
+onready var root_bone = $SpineSprite/RootBone
+var center_hip_y_distance = 0
+var center_root_y_distance = 0
+
 func _ready():
-	$SpineSprite.get_animation_state().set_animation("hoverboard", true, 0)
+	center_hip_y_distance = hip_bone.global_position.y - center_bone.global_position.y
+	center_root_y_distance = spineboy.global_position.y - center_bone.global_position.y
+	spineboy.get_animation_state().set_animation("hoverboard", true, 0)
+	
+	
+func _process(delta):
+	if target_ray.is_colliding():
+		target_bone.global_position.y = target_ray.get_collision_point().y - 50
+	if center_ray.is_colliding():
+		center_bone.global_position.y = center_ray.get_collision_point().y - 50
+		hip_bone.global_position.y = center_bone.global_position.y + center_hip_y_distance
+		
+	spineboy.global_position.x += delta * 150;
+	spineboy.global_position.y = center_bone.global_position.y + center_root_y_distance
 	pass

+ 33 - 5
spine-godot/example/examples/11-bone-node/bone-node.tscn

@@ -7,13 +7,41 @@
 script = ExtResource( 1 )
 
 [node name="SpineSprite" type="SpineSprite" parent="."]
-position = Vector2( 461, 491 )
-scale = Vector2( 0.479082, 0.479082 )
+position = Vector2( 63, 549 )
+scale = Vector2( 0.278096, 0.278096 )
 skeleton_data_res = ExtResource( 2 )
 
-[node name="SpineBoneNode" type="SpineBoneNode" parent="SpineSprite"]
-position = Vector2( -329.751, -69.5322 )
-rotation = 0.00281584
+[node name="HoverboardCenterBone" type="SpineBoneNode" parent="SpineSprite"]
+position = Vector2( -6.26196, -111.618 )
+rotation = -0.0046904
 scale = Vector2( 1, 1 )
 bone_name = "hoverboard-controller"
 bone_mode = 1
+
+[node name="RayCast2D" type="RayCast2D" parent="SpineSprite/HoverboardCenterBone"]
+enabled = true
+cast_to = Vector2( 0, 1000 )
+
+[node name="HoverboardTargetBone" type="SpineBoneNode" parent="SpineSprite"]
+position = Vector2( 265.717, -112.716 )
+bone_name = "board-ik"
+bone_mode = 1
+
+[node name="RayCast2D" type="RayCast2D" parent="SpineSprite/HoverboardTargetBone"]
+enabled = true
+cast_to = Vector2( 0, 1000 )
+
+[node name="HipBone" type="SpineBoneNode" parent="SpineSprite"]
+position = Vector2( -36.9481, -338.198 )
+rotation = 3.14072
+scale = Vector2( 1, 1 )
+bone_name = "hip"
+bone_mode = 1
+
+[node name="Polygon2D" type="Polygon2D" parent="."]
+polygon = PoolVector2Array( 0, 596, 309, 471, 516, 515, 762, 447, 984, 504, 1023, 505, 1024, 596 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Polygon2D"]
+
+[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="Polygon2D/StaticBody2D"]
+polygon = PoolVector2Array( 3, 592, 304, 469, 516, 514, 762, 443, 984, 499, 1252, 498, 1280, 596 )

+ 1 - 1
spine-godot/example/project.godot

@@ -11,7 +11,7 @@ config_version=4
 [application]
 
 config/name="spine-godot-examples"
-run/main_scene="res://examples/08-animation-player/animation-player.tscn"
+run/main_scene="res://examples/11-bone-node/bone-node.tscn"
 run/low_processor_mode=true
 config/icon="res://icon.png"
 

+ 1 - 0
spine-godot/spine_godot/SpineBoneNode.cpp

@@ -130,6 +130,7 @@ void SpineBoneNode::on_world_transforms_changed(const Variant& _sprite) {
 }
 
 void SpineBoneNode::update_transform(SpineSprite* sprite) {
+	if (!is_visible_in_tree()) return;
 	if (!sprite) return;
 	if (!sprite->get_skeleton().is_valid() || !sprite->get_skeleton()->get_spine_object()) return;
 	auto bone = sprite->get_skeleton()->find_bone(bone_name);

+ 89 - 0
spine-godot/spine_godot/SpineSprite.cpp

@@ -87,6 +87,7 @@ void SpineSprite::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "additive_material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_additive_material", "get_additive_material");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiply_material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_multiply_material", "get_multiply_material");
 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "screen_material", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_screen_material", "get_screen_material");
+	ADD_GROUP("Preview", "");
 }
 
 SpineSprite::SpineSprite() : update_mode(SpineConstant::UpdateMode_Process), skeleton_clipper(nullptr) {
@@ -259,6 +260,94 @@ void SpineSprite::_notification(int what) {
 	}
 }
 
+void SpineSprite::_get_property_list(List<PropertyInfo>* list) const {
+	if (!skeleton_data_res.is_valid() || !skeleton_data_res->is_skeleton_data_loaded()) return;
+	Vector<String> animation_names;
+	skeleton_data_res->get_animation_names(animation_names);
+	animation_names.insert(0, "-- Empty --");
+	
+	PropertyInfo preview_anim_property; 
+	preview_anim_property.name = "preview_animation";
+	preview_anim_property.type = Variant::STRING;
+	preview_anim_property.usage = PROPERTY_USAGE_EDITOR;
+	preview_anim_property.hint_string = String(",").join(animation_names);
+	preview_anim_property.hint = PROPERTY_HINT_ENUM;
+	list->push_back(preview_anim_property);
+
+	PropertyInfo preview_frame_property; 
+	preview_frame_property.name = "preview_frame";
+	preview_frame_property.type = Variant::BOOL;
+	preview_frame_property.usage = PROPERTY_USAGE_EDITOR;
+	list->push_back(preview_frame_property);
+
+	PropertyInfo preview_time_property; 
+	preview_time_property.name = "preview_time";
+	preview_time_property.type = VARIANT_FLOAT;
+	preview_time_property.usage = PROPERTY_USAGE_EDITOR;
+	float animation_duration = 0;
+	if (!EMPTY(preview_animation) && preview_animation != "-- Empty --") {
+		auto animation = skeleton_data_res->find_animation(preview_animation);
+		if (animation.is_valid()) animation_duration = animation->get_duration();
+	}
+	preview_time_property.hint_string = String("0.0,{0},0.01").format(varray(animation_duration));
+	preview_time_property.hint = PROPERTY_HINT_RANGE;
+	list->push_back(preview_time_property);
+}
+
+bool SpineSprite::_get(const StringName& property, Variant& value) const {
+	if (property == "preview_animation") {
+		value = preview_animation;
+		return true;
+	}
+
+	if (property == "preview_frame") {
+		value = preview_frame;
+		return true;
+	}
+
+	if (property == "preview_time") {
+		value = preview_time;
+		return true;
+	}
+	return false;
+}
+
+static void update_preview_animation(SpineSprite *sprite, const String &animation, bool frame, float time) {
+	if (EMPTY(animation) || animation == "-- Empty --") {
+		sprite->get_animation_state()->set_empty_animation(0, 0);
+		return;
+	}
+
+	auto track_entry = sprite->get_animation_state()->set_animation(animation, true, 0);
+	track_entry->set_mix_duration(0);
+	if (frame) {
+		track_entry->set_time_scale(0);
+		track_entry->set_track_time(time);
+	}
+}
+
+bool SpineSprite::_set(const StringName& property, const Variant& value) {
+	if (property == "preview_animation") {
+		preview_animation = value;
+		update_preview_animation(this, preview_animation, preview_frame, preview_time);
+		return true;
+	}
+
+	if (property == "preview_frame") {
+		preview_frame = value;
+		update_preview_animation(this, preview_animation, preview_frame, preview_time);
+		return true;
+	}
+
+	if (property == "preview_time") {
+		preview_time = value;
+		update_preview_animation(this, preview_animation, preview_frame, preview_time);
+		return true;
+	}
+	
+	return false;
+}
+
 void SpineSprite::update_skeleton(float delta) {
 	if (!skeleton_data_res.is_valid() ||
 		!skeleton_data_res->is_skeleton_data_loaded() ||

+ 7 - 0
spine-godot/spine_godot/SpineSprite.h

@@ -45,6 +45,10 @@ protected:
 	Ref<SpineSkeleton> skeleton;
 	Ref<SpineAnimationState> animation_state;
 	SpineConstant::UpdateMode update_mode;
+	
+	String preview_animation;
+	bool preview_frame;
+	float preview_time;
 
 	spine::Vector<spine::Vector<SpineSlotNode*> > slot_nodes;
 	Vector<MeshInstance2D *> mesh_instances;
@@ -57,6 +61,9 @@ protected:
 	
 	static void _bind_methods();
 	void _notification(int what);
+	void _get_property_list(List<PropertyInfo> *list) const;
+	bool _get(const StringName &property, Variant &value) const;
+	bool _set(const StringName &property, const Variant &value);
 
 	void generate_meshes_for_slots(Ref<SpineSkeleton> skeleton_ref);
 	void remove_meshes();