mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-25 22:23:42 +08:00
[godot] Replaced bind nodes in SpineSprite with much more powerful SpineSlotNode. Added example scene.
This commit is contained in:
parent
b24f7e53c6
commit
a2b2189faa
@ -1,6 +1,11 @@
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
onready var spineboy: SpineSprite = $Spineboy
|
onready var spineboy: SpineSprite = $Spineboy
|
||||||
|
onready var raptor: SpineSprite = $Spineboy/SlotNodeGun/Raptor
|
||||||
|
onready var tiny_spineboy: SpineSprite = $Spineboy/SlotNodeFrontFist/TinySpineboy
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
spineboy.get_animation_state().set_animation("walk", true, 0)
|
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)
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
[ext_resource path="res://examples/07-slot-node/slot-node.gd" type="Script" id=1]
|
[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://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"]
|
[node name="Node2D" type="Node2D"]
|
||||||
script = ExtResource( 1 )
|
script = ExtResource( 1 )
|
||||||
@ -12,11 +12,24 @@ position = Vector2( 506, 480 )
|
|||||||
scale = Vector2( 0.560712, 0.560712 )
|
scale = Vector2( 0.560712, 0.560712 )
|
||||||
skeleton_data_res = ExtResource( 2 )
|
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 )
|
position = Vector2( 40.8752, -276.036 )
|
||||||
rotation = 0.837234
|
rotation = 0.837234
|
||||||
scale = Vector2( 1, 1 )
|
scale = Vector2( 1, 1 )
|
||||||
slot_name = "gun"
|
slot_name = "gun"
|
||||||
|
|
||||||
[node name="Sprite" type="Sprite" parent="Spineboy/SpineSlotNode"]
|
[node name="Raptor" type="SpineSprite" parent="Spineboy/SlotNodeGun"]
|
||||||
texture = ExtResource( 3 )
|
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 )
|
||||||
|
|||||||
@ -9,7 +9,7 @@ void SpineSlotNode::_bind_methods() {
|
|||||||
ClassDB::bind_method(D_METHOD("_on_world_transforms_changed", "spine_sprite"), &SpineSlotNode::on_world_transforms_changed);
|
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) {
|
void SpineSlotNode::_notification(int what) {
|
||||||
@ -87,7 +87,12 @@ void SpineSlotNode::on_world_transforms_changed(const Variant& _sprite) {
|
|||||||
void SpineSlotNode::update_transform(SpineSprite *sprite) {
|
void SpineSlotNode::update_transform(SpineSprite *sprite) {
|
||||||
if (!sprite) return;
|
if (!sprite) return;
|
||||||
auto slot = sprite->get_skeleton()->find_slot(slot_name);
|
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();
|
auto bone = slot->get_bone();
|
||||||
if (!bone.is_valid()) return;
|
if (!bone.is_valid()) return;
|
||||||
this->set_global_transform(bone->get_global_transform());
|
this->set_global_transform(bone->get_global_transform());
|
||||||
|
|||||||
@ -10,6 +10,7 @@ class SpineSlotNode: public Node2D {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
String slot_name;
|
String slot_name;
|
||||||
|
int slot_index;
|
||||||
SpineSprite *sprite;
|
SpineSprite *sprite;
|
||||||
|
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
@ -25,6 +26,8 @@ public:
|
|||||||
void set_slot_name(const String &_slot_name);
|
void set_slot_name(const String &_slot_name);
|
||||||
|
|
||||||
String get_slot_name();
|
String get_slot_name();
|
||||||
|
|
||||||
|
int get_slot_index() { return slot_index; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -32,6 +32,7 @@
|
|||||||
#include "SpineTrackEntry.h"
|
#include "SpineTrackEntry.h"
|
||||||
#include "SpineSkeleton.h"
|
#include "SpineSkeleton.h"
|
||||||
#include "SpineRendererObject.h"
|
#include "SpineRendererObject.h"
|
||||||
|
#include "SpineSlotNode.h"
|
||||||
|
|
||||||
Ref<CanvasItemMaterial> SpineSprite::default_materials[4] = {};
|
Ref<CanvasItemMaterial> SpineSprite::default_materials[4] = {};
|
||||||
static int sprite_count = 0;
|
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_skeleton"), &SpineSprite::get_skeleton);
|
||||||
ClassDB::bind_method(D_METHOD("get_animation_state"), &SpineSprite::get_animation_state);
|
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("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("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);
|
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<SpineSkeleton> skeleton_ref) {
|
|||||||
add_child(mesh_instance);
|
add_child(mesh_instance);
|
||||||
mesh_instance->set_owner(this);
|
mesh_instance->set_owner(this);
|
||||||
mesh_instances.push_back(mesh_instance);
|
mesh_instances.push_back(mesh_instance);
|
||||||
|
slot_nodes.add(spine::Vector<SpineSlotNode*>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +171,33 @@ void SpineSprite::remove_meshes() {
|
|||||||
memdelete(mesh_instances[i]);
|
memdelete(mesh_instances[i]);
|
||||||
}
|
}
|
||||||
mesh_instances.clear();
|
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<SpineSlotNode>(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<SpineSlotNode*> &nodes = slot_nodes[slot_index];
|
||||||
|
for (int j = 0; j < nodes.size(); j++) {
|
||||||
|
auto node = nodes[j];
|
||||||
|
move_child(node, mesh_index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<SpineSkeleton> SpineSprite::get_skeleton() {
|
Ref<SpineSkeleton> SpineSprite::get_skeleton() {
|
||||||
@ -217,88 +244,7 @@ void SpineSprite::update_skeleton(float delta) {
|
|||||||
emit_signal("world_transforms_changed", this);
|
emit_signal("world_transforms_changed", this);
|
||||||
update_meshes(skeleton);
|
update_meshes(skeleton);
|
||||||
update();
|
update();
|
||||||
update_bind_slot_nodes();
|
sort_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<MeshInstance2D>(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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TEMP_COPY(t, get_res) \
|
#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) {
|
Transform2D SpineSprite::get_global_bone_transform(const String &bone_name) {
|
||||||
if (!animation_state.is_valid() && !skeleton.is_valid()) {
|
if (!animation_state.is_valid() && !skeleton.is_valid()) {
|
||||||
return get_global_transform();
|
return get_global_transform();
|
||||||
|
|||||||
@ -36,6 +36,8 @@
|
|||||||
#include "scene/2d/mesh_instance_2d.h"
|
#include "scene/2d/mesh_instance_2d.h"
|
||||||
#include "scene/resources/texture.h"
|
#include "scene/resources/texture.h"
|
||||||
|
|
||||||
|
class SpineSlotNode;
|
||||||
|
|
||||||
class SpineSprite : public Node2D, public spine::AnimationStateListenerObject {
|
class SpineSprite : public Node2D, public spine::AnimationStateListenerObject {
|
||||||
GDCLASS(SpineSprite, Node2D)
|
GDCLASS(SpineSprite, Node2D)
|
||||||
|
|
||||||
@ -50,9 +52,9 @@ protected:
|
|||||||
Ref<SpineSkeletonDataResource> skeleton_data_res;
|
Ref<SpineSkeletonDataResource> skeleton_data_res;
|
||||||
Ref<SpineSkeleton> skeleton;
|
Ref<SpineSkeleton> skeleton;
|
||||||
Ref<SpineAnimationState> animation_state;
|
Ref<SpineAnimationState> animation_state;
|
||||||
Array bind_slot_nodes;
|
|
||||||
UpdateMode update_mode;
|
UpdateMode update_mode;
|
||||||
|
|
||||||
|
spine::Vector<spine::Vector<SpineSlotNode*> > slot_nodes;
|
||||||
Vector<MeshInstance2D *> mesh_instances;
|
Vector<MeshInstance2D *> mesh_instances;
|
||||||
spine::SkeletonClipping *skeleton_clipper;
|
spine::SkeletonClipping *skeleton_clipper;
|
||||||
static Ref<CanvasItemMaterial> default_materials[4];
|
static Ref<CanvasItemMaterial> default_materials[4];
|
||||||
@ -62,12 +64,9 @@ protected:
|
|||||||
|
|
||||||
void generate_meshes_for_slots(Ref<SpineSkeleton> skeleton_ref);
|
void generate_meshes_for_slots(Ref<SpineSkeleton> skeleton_ref);
|
||||||
void remove_meshes();
|
void remove_meshes();
|
||||||
|
void sort_slot_nodes();
|
||||||
void update_meshes(Ref<SpineSkeleton> skeleton);
|
void update_meshes(Ref<SpineSkeleton> 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);
|
void callback(spine::AnimationState *state, spine::EventType type, spine::TrackEntry *entry, spine::Event *event);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user