From e5393dfed992090bbb3ecd98f9e1df77045548cc Mon Sep 17 00:00:00 2001 From: badlogic Date: Sun, 1 May 2022 05:00:03 +0200 Subject: [PATCH] [godot] SpineSprite preview properties, finished SpineBoneNode, bone node example. --- .../examples/11-bone-node/bone-node.gd | 25 +++++- .../examples/11-bone-node/bone-node.tscn | 38 ++++++-- spine-godot/example/project.godot | 2 +- spine-godot/spine_godot/SpineBoneNode.cpp | 1 + spine-godot/spine_godot/SpineSprite.cpp | 89 +++++++++++++++++++ spine-godot/spine_godot/SpineSprite.h | 7 ++ 6 files changed, 155 insertions(+), 7 deletions(-) diff --git a/spine-godot/example/examples/11-bone-node/bone-node.gd b/spine-godot/example/examples/11-bone-node/bone-node.gd index e2cf328ce..1d1182012 100644 --- a/spine-godot/example/examples/11-bone-node/bone-node.gd +++ b/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 diff --git a/spine-godot/example/examples/11-bone-node/bone-node.tscn b/spine-godot/example/examples/11-bone-node/bone-node.tscn index 4233e2b39..16e237913 100644 --- a/spine-godot/example/examples/11-bone-node/bone-node.tscn +++ b/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 ) diff --git a/spine-godot/example/project.godot b/spine-godot/example/project.godot index 6011be217..9716ff8a6 100644 --- a/spine-godot/example/project.godot +++ b/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" diff --git a/spine-godot/spine_godot/SpineBoneNode.cpp b/spine-godot/spine_godot/SpineBoneNode.cpp index 51db381ca..91554d61b 100644 --- a/spine-godot/spine_godot/SpineBoneNode.cpp +++ b/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); diff --git a/spine-godot/spine_godot/SpineSprite.cpp b/spine-godot/spine_godot/SpineSprite.cpp index 037c3d55d..182b931aa 100644 --- a/spine-godot/spine_godot/SpineSprite.cpp +++ b/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* list) const { + if (!skeleton_data_res.is_valid() || !skeleton_data_res->is_skeleton_data_loaded()) return; + Vector 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() || diff --git a/spine-godot/spine_godot/SpineSprite.h b/spine-godot/spine_godot/SpineSprite.h index d18451a73..0363fc466 100644 --- a/spine-godot/spine_godot/SpineSprite.h +++ b/spine-godot/spine_godot/SpineSprite.h @@ -45,6 +45,10 @@ protected: Ref skeleton; Ref animation_state; SpineConstant::UpdateMode update_mode; + + String preview_animation; + bool preview_frame; + float preview_time; spine::Vector > slot_nodes; Vector mesh_instances; @@ -57,6 +61,9 @@ protected: static void _bind_methods(); void _notification(int what); + void _get_property_list(List *list) const; + bool _get(const StringName &property, Variant &value) const; + bool _set(const StringName &property, const Variant &value); void generate_meshes_for_slots(Ref skeleton_ref); void remove_meshes();