From a2b2189faa5f689124f2392eb10633e1fd2a2fd4 Mon Sep 17 00:00:00 2001 From: badlogic Date: Fri, 22 Apr 2022 20:09:26 +0200 Subject: [PATCH] [godot] Replaced bind nodes in SpineSprite with much more powerful SpineSlotNode. Added example scene. --- .../examples/07-slot-node/slot-node.gd | 9 +- .../examples/07-slot-node/slot-node.tscn | 21 ++- spine-godot/spine_godot/SpineSlotNode.cpp | 9 +- spine-godot/spine_godot/SpineSlotNode.h | 3 + spine-godot/spine_godot/SpineSprite.cpp | 122 +++++------------- spine-godot/spine_godot/SpineSprite.h | 9 +- 6 files changed, 68 insertions(+), 105 deletions(-) diff --git a/spine-godot/example/examples/07-slot-node/slot-node.gd b/spine-godot/example/examples/07-slot-node/slot-node.gd index 44704bffb..fb039416f 100644 --- a/spine-godot/example/examples/07-slot-node/slot-node.gd +++ b/spine-godot/example/examples/07-slot-node/slot-node.gd @@ -1,6 +1,11 @@ extends Node2D onready var spineboy: SpineSprite = $Spineboy +onready var raptor: SpineSprite = $Spineboy/SlotNodeGun/Raptor +onready var tiny_spineboy: SpineSprite = $Spineboy/SlotNodeFrontFist/TinySpineboy -func _ready(): - spineboy.get_animation_state().set_animation("walk", true, 0) +func _ready(): + var entry = spineboy.get_animation_state().set_animation("run", true, 0) + entry.set_time_scale(0.1) + raptor.get_animation_state().set_animation("walk", true, 0) + tiny_spineboy.get_animation_state().set_animation("walk", true, 0) diff --git a/spine-godot/example/examples/07-slot-node/slot-node.tscn b/spine-godot/example/examples/07-slot-node/slot-node.tscn index 6e7afd66b..5fae91e55 100644 --- a/spine-godot/example/examples/07-slot-node/slot-node.tscn +++ b/spine-godot/example/examples/07-slot-node/slot-node.tscn @@ -2,7 +2,7 @@ [ext_resource path="res://examples/07-slot-node/slot-node.gd" type="Script" id=1] [ext_resource path="res://assets/spineboy/spinebody-data-res.tres" type="SpineSkeletonDataResource" id=2] -[ext_resource path="res://icon.png" type="Texture" id=3] +[ext_resource path="res://assets/raptor/raprot-data.tres" type="SpineSkeletonDataResource" id=3] [node name="Node2D" type="Node2D"] script = ExtResource( 1 ) @@ -12,11 +12,24 @@ position = Vector2( 506, 480 ) scale = Vector2( 0.560712, 0.560712 ) skeleton_data_res = ExtResource( 2 ) -[node name="SpineSlotNode" type="SpineSlotNode" parent="Spineboy"] +[node name="SlotNodeGun" type="SpineSlotNode" parent="Spineboy"] position = Vector2( 40.8752, -276.036 ) rotation = 0.837234 scale = Vector2( 1, 1 ) slot_name = "gun" -[node name="Sprite" type="Sprite" parent="Spineboy/SpineSlotNode"] -texture = ExtResource( 3 ) +[node name="Raptor" type="SpineSprite" parent="Spineboy/SlotNodeGun"] +position = Vector2( 84.6909, -67.9174 ) +scale = Vector2( 0.193472, 0.193472 ) +skeleton_data_res = ExtResource( 3 ) + +[node name="SlotNodeFrontFist" type="SpineSlotNode" parent="Spineboy"] +position = Vector2( -29.0298, -241.577 ) +rotation = 0.995187 +scale = Vector2( 1, 1 ) +slot_name = "front-fist" + +[node name="TinySpineboy" type="SpineSprite" parent="Spineboy/SlotNodeFrontFist"] +position = Vector2( -2.64624, -10.8111 ) +scale = Vector2( 0.193389, 0.193389 ) +skeleton_data_res = ExtResource( 2 ) diff --git a/spine-godot/spine_godot/SpineSlotNode.cpp b/spine-godot/spine_godot/SpineSlotNode.cpp index ab0951cbd..e30859a5c 100644 --- a/spine-godot/spine_godot/SpineSlotNode.cpp +++ b/spine-godot/spine_godot/SpineSlotNode.cpp @@ -9,7 +9,7 @@ void SpineSlotNode::_bind_methods() { ClassDB::bind_method(D_METHOD("_on_world_transforms_changed", "spine_sprite"), &SpineSlotNode::on_world_transforms_changed); } -SpineSlotNode::SpineSlotNode(): sprite(nullptr) { +SpineSlotNode::SpineSlotNode(): slot_index(-1), sprite(nullptr) { } void SpineSlotNode::_notification(int what) { @@ -87,7 +87,12 @@ void SpineSlotNode::on_world_transforms_changed(const Variant& _sprite) { void SpineSlotNode::update_transform(SpineSprite *sprite) { if (!sprite) return; auto slot = sprite->get_skeleton()->find_slot(slot_name); - if (!slot.is_valid()) return; + if (!slot.is_valid()) { + slot_index = -1; + return; + } else { + slot_index = slot->get_data()->get_index(); + } auto bone = slot->get_bone(); if (!bone.is_valid()) return; this->set_global_transform(bone->get_global_transform()); diff --git a/spine-godot/spine_godot/SpineSlotNode.h b/spine-godot/spine_godot/SpineSlotNode.h index 75f30d244..5344172cf 100644 --- a/spine-godot/spine_godot/SpineSlotNode.h +++ b/spine-godot/spine_godot/SpineSlotNode.h @@ -10,6 +10,7 @@ class SpineSlotNode: public Node2D { protected: String slot_name; + int slot_index; SpineSprite *sprite; static void _bind_methods(); @@ -25,6 +26,8 @@ public: void set_slot_name(const String &_slot_name); String get_slot_name(); + + int get_slot_index() { return slot_index; } }; #endif diff --git a/spine-godot/spine_godot/SpineSprite.cpp b/spine-godot/spine_godot/SpineSprite.cpp index e4aaef4e6..e78c53761 100644 --- a/spine-godot/spine_godot/SpineSprite.cpp +++ b/spine-godot/spine_godot/SpineSprite.cpp @@ -32,6 +32,7 @@ #include "SpineTrackEntry.h" #include "SpineSkeleton.h" #include "SpineRendererObject.h" +#include "SpineSlotNode.h" Ref SpineSprite::default_materials[4] = {}; static int sprite_count = 0; @@ -42,8 +43,6 @@ void SpineSprite::_bind_methods() { ClassDB::bind_method(D_METHOD("get_skeleton"), &SpineSprite::get_skeleton); ClassDB::bind_method(D_METHOD("get_animation_state"), &SpineSprite::get_animation_state); ClassDB::bind_method(D_METHOD("on_skeleton_data_changed"), &SpineSprite::on_skeleton_data_changed); - ClassDB::bind_method(D_METHOD("get_bind_slot_nodes"), &SpineSprite::get_bind_slot_nodes); - ClassDB::bind_method(D_METHOD("set_bind_slot_nodes", "v"), &SpineSprite::set_bind_slot_nodes); ClassDB::bind_method(D_METHOD("get_global_bone_transform", "bone_name"), &SpineSprite::get_global_bone_transform); ClassDB::bind_method(D_METHOD("set_global_bone_transform", "bone_name", "global_transform"), &SpineSprite::set_global_bone_transform); @@ -162,6 +161,7 @@ void SpineSprite::generate_meshes_for_slots(Ref skeleton_ref) { add_child(mesh_instance); mesh_instance->set_owner(this); mesh_instances.push_back(mesh_instance); + slot_nodes.add(spine::Vector()); } } @@ -171,6 +171,33 @@ void SpineSprite::remove_meshes() { memdelete(mesh_instances[i]); } mesh_instances.clear(); + slot_nodes.clear(); +} + +void SpineSprite::sort_slot_nodes() { + for (int i = 0; i < slot_nodes.size(); i++) { + slot_nodes[i].setSize(0, nullptr); + } + + auto draw_order = skeleton->get_spine_object()->getDrawOrder(); + for (int i = 0; i < get_child_count(); i++) { + auto slot_node = Object::cast_to(get_child(i)); + if (!slot_node) continue; + if (slot_node->get_slot_index() == -1 || slot_node->get_slot_index() >= draw_order.size()) { + continue; + } + slot_nodes[slot_node->get_slot_index()].add(slot_node); + } + + for (int i = 0; i < draw_order.size(); i++) { + int slot_index = draw_order[i]->getData().getIndex(); + int mesh_index = mesh_instances[i]->get_index(); + spine::Vector &nodes = slot_nodes[slot_index]; + for (int j = 0; j < nodes.size(); j++) { + auto node = nodes[j]; + move_child(node, mesh_index + 1); + } + } } Ref SpineSprite::get_skeleton() { @@ -217,88 +244,7 @@ void SpineSprite::update_skeleton(float delta) { emit_signal("world_transforms_changed", this); update_meshes(skeleton); update(); - update_bind_slot_nodes(); -} - -void SpineSprite::update_bind_slot_nodes() { - if (animation_state.is_valid() && skeleton.is_valid()) { - for (int i = 0, n = bind_slot_nodes.size(); i < n; ++i) { - auto a = bind_slot_nodes[i]; - if (a.get_type() == Variant::DICTIONARY) { - auto d = (Dictionary) a; - if (d.has("slot_name") && d.has("node_path")) { - NodePath node_path = d["node_path"]; - Node *node = get_node_or_null(node_path); - if (node && node->is_class("Node2D")) { - auto *node2d = (Node2D *) node; - - String slot_name = d["slot_name"]; - auto slot = skeleton->find_slot(slot_name); - if (slot.is_valid()) { - auto bone = slot->get_bone(); - if (bone.is_valid()) { - bone->apply_world_transform_2d(node2d); - update_bind_slot_node_draw_order(slot_name, node2d); - } - } - } - } - } else if (a.get_type() == Variant::ARRAY) { - auto as = (Array) a;// 0: slot_name, 1: node_path - if (as.size() >= 2 && as[0].get_type() == Variant::STRING && as[1].get_type() == Variant::NODE_PATH) { - NodePath node_path = as[1]; - Node *node = get_node_or_null(node_path); - if (node && node->is_class("Node2D")) { - auto *node2d = (Node2D *) node; - - String slot_name = as[0]; - auto slot = skeleton->find_slot(slot_name); - if (slot.is_valid()) { - auto bone = slot->get_bone(); - if (bone.is_valid()) { - bone->apply_world_transform_2d(node2d); - update_bind_slot_node_draw_order(slot_name, node2d); - } - } - } - } - } - } - } -} - -void SpineSprite::update_bind_slot_node_draw_order(const String &slot_name, Node2D *node2d) { -#if VERSION_MAJOR > 3 - auto nodes = find_nodes(slot_name); - if (!nodes.is_empty()) { - auto mesh_ins = Object::cast_to(nodes[0]); - if (mesh_ins) { - auto pos = mesh_ins->get_index(); - - // get child - auto node = find_child_node_by_node(node2d); - if (node && node->get_index() != pos + 1) { - move_child(node, pos + 1); - } - } - } -#else - auto mesh_ins = find_node(slot_name); - if (mesh_ins) { - auto pos = mesh_ins->get_index(); - - // get child - auto node = find_child_node_by_node(node2d); - if (node && node->get_index() != pos + 1) { - move_child(node, pos + 1); - } - } -#endif -} -Node *SpineSprite::find_child_node_by_node(Node *node) { - if (node == nullptr) return nullptr; - while (node && node->get_parent() != this) node = node->get_parent(); - return node; + sort_slot_nodes(); } #define TEMP_COPY(t, get_res) \ @@ -534,14 +480,6 @@ void SpineSprite::callback(spine::AnimationState *state, spine::EventType type, } } -Array SpineSprite::get_bind_slot_nodes() { - return bind_slot_nodes; -} - -void SpineSprite::set_bind_slot_nodes(Array v) { - bind_slot_nodes = v; -} - Transform2D SpineSprite::get_global_bone_transform(const String &bone_name) { if (!animation_state.is_valid() && !skeleton.is_valid()) { return get_global_transform(); diff --git a/spine-godot/spine_godot/SpineSprite.h b/spine-godot/spine_godot/SpineSprite.h index 32f59fa56..4573bc32a 100644 --- a/spine-godot/spine_godot/SpineSprite.h +++ b/spine-godot/spine_godot/SpineSprite.h @@ -36,6 +36,8 @@ #include "scene/2d/mesh_instance_2d.h" #include "scene/resources/texture.h" +class SpineSlotNode; + class SpineSprite : public Node2D, public spine::AnimationStateListenerObject { GDCLASS(SpineSprite, Node2D) @@ -50,9 +52,9 @@ protected: Ref skeleton_data_res; Ref skeleton; Ref animation_state; - Array bind_slot_nodes; UpdateMode update_mode; + spine::Vector > slot_nodes; Vector mesh_instances; spine::SkeletonClipping *skeleton_clipper; static Ref default_materials[4]; @@ -62,12 +64,9 @@ protected: void generate_meshes_for_slots(Ref skeleton_ref); void remove_meshes(); + void sort_slot_nodes(); void update_meshes(Ref skeleton); - void update_bind_slot_nodes(); - void update_bind_slot_node_draw_order(const String &slot_name, Node2D *node2d); - Node *find_child_node_by_node(Node *node); - void callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event); public: