[godot] Add SpineSlotNode to attach arbitrary trees to skeleton slots, have skeleton, bone, slot, and transforms reference the enclosing SpineSprite.

This commit is contained in:
badlogic 2022-04-22 13:20:26 +02:00
parent 8cabfa370f
commit 19fc6bab8b
20 changed files with 196 additions and 54 deletions

View File

@ -0,0 +1,6 @@
extends Node2D
onready var spineboy: SpineSprite = $Spineboy
func _ready():
spineboy.get_animation_state().set_animation("walk", true, 0)

View File

@ -0,0 +1,22 @@
[gd_scene load_steps=4 format=2]
[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]
[node name="Node2D" type="Node2D"]
script = ExtResource( 1 )
[node name="Spineboy" type="SpineSprite" parent="."]
position = Vector2( 506, 480 )
scale = Vector2( 0.560712, 0.560712 )
skeleton_data_res = ExtResource( 2 )
[node name="SpineSlotNode" 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 )

View File

@ -11,7 +11,7 @@ config_version=4
[application]
config/name="spine-godot-examples"
run/main_scene="res://examples/01-helloworld/helloworld.tscn"
run/main_scene="res://examples/07-slot-node/slot-node.tscn"
run/low_processor_mode=true
config/icon="res://icon.png"

View File

@ -101,10 +101,6 @@ void SpineBone::_bind_methods() {
SpineBone::SpineBone() : bone(nullptr), sprite(nullptr) {}
void SpineBone::set_spine_sprite(SpineSprite* _sprite) {
this->sprite = _sprite;
}
void SpineBone::update_world_transform() {
SPINE_CHECK(bone,)
bone->updateWorldTransform();
@ -166,8 +162,7 @@ Ref<SpineSkeleton> SpineBone::get_skeleton() {
SPINE_CHECK(bone, nullptr)
auto &skeleton = bone->getSkeleton();
Ref<SpineSkeleton> skeleton_ref(memnew(SpineSkeleton));
skeleton_ref->set_spine_object(&skeleton);
skeleton_ref->set_spine_sprite(sprite);
skeleton_ref->set_spine_object(sprite, &skeleton);
return skeleton_ref;
}
@ -176,8 +171,7 @@ Ref<SpineBone> SpineBone::get_parent() {
auto parent = bone->getParent();
if (!parent) return nullptr;
Ref<SpineBone> parent_ref(memnew(SpineBone));
parent_ref->set_spine_object(parent);
parent_ref->set_spine_sprite(sprite);
parent_ref->set_spine_object(sprite, parent);
return parent_ref;
}
@ -189,8 +183,7 @@ Array SpineBone::get_children() {
for (int i = 0; i < children.size(); ++i) {
auto child = children[i];
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(child);
bone_ref->set_spine_sprite(sprite);
bone_ref->set_spine_object(sprite, child);
result[i] = bone_ref;
}
return result;

View File

@ -51,11 +51,9 @@ private:
public:
SpineBone();
void set_spine_object(spine::Bone *_bone) { bone = _bone; }
void set_spine_object(SpineSprite *_sprite, spine::Bone *_bone) { sprite = _sprite; bone = _bone; }
spine::Bone *get_spine_object() { return bone; }
void set_spine_sprite(SpineSprite* _sprite);
SpineSprite *get_spine_sprite() { return sprite; }
void update_world_transform();

View File

@ -52,7 +52,7 @@ void SpineIkConstraint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineIkConstraint::set_active);
}
SpineIkConstraint::SpineIkConstraint() : ik_constraint(nullptr) {
SpineIkConstraint::SpineIkConstraint() : ik_constraint(nullptr), sprite(nullptr) {
}
void SpineIkConstraint::update() {
@ -81,7 +81,7 @@ Array SpineIkConstraint::get_bones() {
for (int i = 0; i < bones.size(); ++i) {
auto bone = bones[i];
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_object(sprite, bone);
result[i] = bone_ref;
}
return result;
@ -92,7 +92,7 @@ Ref<SpineBone> SpineIkConstraint::get_target() {
auto target = ik_constraint->getTarget();
if (!target) return nullptr;
Ref<SpineBone> target_ref(memnew(SpineBone));
target_ref->set_spine_object(target);
target_ref->set_spine_object(sprite, target);
return target_ref;
}

View File

@ -34,6 +34,7 @@
#include <spine/IkConstraint.h>
class SpineBone;
class SpineSprite;
class SpineIkConstraint : public REFCOUNTED {
GDCLASS(SpineIkConstraint, REFCOUNTED);
@ -43,13 +44,14 @@ protected:
private:
spine::IkConstraint *ik_constraint;
SpineSprite *sprite;
public:
SpineIkConstraint();
void set_spine_object(spine::IkConstraint *_ik_constraint) { ik_constraint = _ik_constraint; }
void set_spine_object(SpineSprite *_sprite, spine::IkConstraint *_ik_constraint) { sprite = _sprite; ik_constraint = _ik_constraint; }
spine::IkConstraint *get_spine_object() { return ik_constraint; }
SpineSprite *get_spine_sprite() { return sprite; }
void update();

View File

@ -52,7 +52,7 @@ void SpinePathConstraint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "v"), &SpinePathConstraint::set_active);
}
SpinePathConstraint::SpinePathConstraint() : path_constraint(nullptr) {
SpinePathConstraint::SpinePathConstraint() : path_constraint(nullptr), sprite(nullptr) {
}
void SpinePathConstraint::update() {
@ -123,7 +123,7 @@ Array SpinePathConstraint::get_bones() {
for (int i = 0; i < bones.size(); ++i) {
auto bone = bones[i];
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_object(sprite, bone);
result[i] = bone_ref;
}
return result;
@ -134,7 +134,7 @@ Ref<SpineSlot> SpinePathConstraint::get_target() {
auto target = path_constraint->getTarget();
if (!target) return nullptr;
Ref<SpineSlot> target_ref(memnew(SpineSlot));
target_ref->set_spine_object(target);
target_ref->set_spine_object(sprite, target);
return target_ref;
}

View File

@ -42,12 +42,14 @@ protected:
private:
spine::PathConstraint *path_constraint;
SpineSprite *sprite;
public:
SpinePathConstraint();
void set_spine_object(spine::PathConstraint *_path_constraint) { path_constraint = _path_constraint; }
void set_spine_object(SpineSprite *_sprite, spine::PathConstraint *_path_constraint) { sprite = _sprite; path_constraint = _path_constraint; }
spine::PathConstraint *get_spine_object() { return path_constraint; }
SpineSprite *get_spine_sprite() { return sprite; }
void update();

View File

@ -87,10 +87,6 @@ Ref<SpineSkeletonDataResource> SpineSkeleton::get_skeleton_data_res() const {
return skeleton_data_res;
}
void SpineSkeleton::set_spine_sprite(SpineSprite* _sprite) {
this->sprite = _sprite;
}
void SpineSkeleton::update_world_transform() {
SPINE_CHECK(skeleton,)
skeleton->updateWorldTransform();
@ -117,8 +113,7 @@ Ref<SpineBone> SpineSkeleton::find_bone(const String &name) {
auto bone = skeleton->findBone(SPINE_STRING(name));
if (!bone) return nullptr;
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_sprite(sprite);
bone_ref->set_spine_object(sprite, bone);
return bone_ref;
}
@ -128,7 +123,7 @@ Ref<SpineSlot> SpineSkeleton::find_slot(const String &name) {
auto slot = skeleton->findSlot(SPINE_STRING(name));
if (!slot) return nullptr;
Ref<SpineSlot> slot_ref(memnew(SpineSlot));
slot_ref->set_spine_object(slot);
slot_ref->set_spine_object(sprite, slot);
return slot_ref;
}
@ -171,7 +166,7 @@ Ref<SpineIkConstraint> SpineSkeleton::find_ik_constraint(const String &constrain
auto constraint = skeleton->findIkConstraint(SPINE_STRING(constraint_name));
if (!constraint) return nullptr;
Ref<SpineIkConstraint> constraint_ref(memnew(SpineIkConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
return constraint_ref;
}
@ -181,7 +176,7 @@ Ref<SpineTransformConstraint> SpineSkeleton::find_transform_constraint(const Str
auto constraint = skeleton->findTransformConstraint(SPINE_STRING(constraint_name));
if (!constraint) return nullptr;
Ref<SpineTransformConstraint> constraint_ref(memnew(SpineTransformConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
return constraint_ref;
}
@ -191,7 +186,7 @@ Ref<SpinePathConstraint> SpineSkeleton::find_path_constraint(const String &const
auto constraint = skeleton->findPathConstraint(SPINE_STRING(constraint_name));
if (!constraint) return nullptr;
Ref<SpinePathConstraint> constraint_ref(memnew(SpinePathConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
return constraint_ref;
}
@ -207,8 +202,7 @@ Ref<SpineBone> SpineSkeleton::get_root_bone() {
auto bone = skeleton->getRootBone();
if (!bone) return nullptr;
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_sprite(sprite);
bone_ref->set_spine_object(sprite, bone);
return bone_ref;
}
@ -220,8 +214,7 @@ Array SpineSkeleton::get_bones() {
for (int i = 0; i < result.size(); ++i) {
auto bone = bones[i];
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_sprite(sprite);
bone_ref->set_spine_object(sprite, bone);
result[i] = bone_ref;
}
return result;
@ -235,7 +228,7 @@ Array SpineSkeleton::get_slots() {
for (int i = 0; i < result.size(); ++i) {
auto slot = slots[i];
Ref<SpineSlot> slot_ref(memnew(SpineSlot));
slot_ref->set_spine_object(slot);
slot_ref->set_spine_object(sprite, slot);
result[i] = slot_ref;
}
return result;
@ -249,7 +242,7 @@ Array SpineSkeleton::get_draw_order() {
for (int i = 0; i < result.size(); ++i) {
auto slot = slots[i];
Ref<SpineSlot> slot_ref(memnew(SpineSlot));
slot_ref->set_spine_object(slot);
slot_ref->set_spine_object(sprite, slot);
result[i] = slot_ref;
}
return result;
@ -263,7 +256,7 @@ Array SpineSkeleton::get_ik_constraints() {
for (int i = 0; i < result.size(); ++i) {
auto constraint = constraints[i];
Ref<SpineIkConstraint> constraint_ref(memnew(SpineIkConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
result[i] = constraint_ref;
}
return result;
@ -277,7 +270,7 @@ Array SpineSkeleton::get_path_constraints() {
for (int i = 0; i < result.size(); ++i) {
auto constraint = constraints[i];
Ref<SpinePathConstraint> constraint_ref(memnew(SpinePathConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
result[i] = constraint_ref;
}
return result;
@ -290,7 +283,7 @@ Array SpineSkeleton::get_transform_constraints() {
for (int i = 0; i < result.size(); ++i) {
auto constraint = constraints[i];
Ref<SpineTransformConstraint> constraint_ref(memnew(SpineTransformConstraint));
constraint_ref->set_spine_object(constraint);
constraint_ref->set_spine_object(sprite, constraint);
result[i] = constraint_ref;
}
return result;

View File

@ -57,10 +57,10 @@ protected:
void set_skeleton_data_res(Ref<SpineSkeletonDataResource> data_res);
Ref<SpineSkeletonDataResource> get_skeleton_data_res() const;
void set_spine_object(spine::Skeleton *s) { skeleton = s; }
void set_spine_object(SpineSprite *_sprite, spine::Skeleton *_skeleton) { sprite = _sprite; skeleton = _skeleton; }
spine::Skeleton *get_spine_object() { return skeleton; }
void set_spine_sprite(SpineSprite *sprite);
void set_spine_sprite(SpineSprite *_sprite) { sprite = _sprite; }
SpineSprite *get_spine_sprite() { return sprite; }
private:
spine::Skeleton *skeleton;

View File

@ -223,6 +223,16 @@ void SpineSkeletonDataResource::get_skin_names(Vector<String> &skin_names) const
}
}
void SpineSkeletonDataResource::get_slot_names(Vector<String>& slot_names) {
slot_names.clear();
if (!is_skeleton_data_loaded()) return;
auto slots = skeleton_data->getSlots();
for (size_t i = 0; i < slots.size(); ++i) {
auto slot = slots[i];
slot_names.push_back(slot->getName().buffer());
}
}
void SpineSkeletonDataResource::set_default_mix(float _default_mix) {
this->default_mix = _default_mix;
update_mixes();

View File

@ -76,6 +76,8 @@ public:
void get_skin_names(Vector<String> &l) const;
void get_slot_names(Vector<String> &slot_names);
void set_default_mix(float default_mix);
float get_default_mix();

View File

@ -52,7 +52,7 @@ void SpineSlot::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_sequence_index", "v"), &SpineSlot::set_sequence_index);
}
SpineSlot::SpineSlot() : slot(nullptr) {
SpineSlot::SpineSlot() : slot(nullptr), sprite(nullptr) {
}
void SpineSlot::set_to_setup_pose() {
@ -72,7 +72,7 @@ Ref<SpineBone> SpineSlot::get_bone() {
SPINE_CHECK(slot, nullptr)
auto &bone = slot->getBone();
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(&bone);
bone_ref->set_spine_object(sprite, &bone);
return bone_ref;
}
@ -80,7 +80,7 @@ Ref<SpineSkeleton> SpineSlot::get_skeleton() {
SPINE_CHECK(slot, nullptr)
auto &skeleton = slot->getSkeleton();
Ref<SpineSkeleton> skeleton_ref(memnew(SpineSkeleton));
skeleton_ref->set_spine_object(&skeleton);
skeleton_ref->set_spine_object(sprite, &skeleton);
return skeleton_ref;
}

View File

@ -46,12 +46,14 @@ protected:
private:
spine::Slot *slot;
SpineSprite *sprite;
public:
SpineSlot();
void set_spine_object(spine::Slot *s) { slot = s; }
void set_spine_object(SpineSprite *_sprite, spine::Slot *_slot) { sprite = _sprite; slot = _slot; }
spine::Slot *get_spine_object() { return slot; }
SpineSprite *get_spine_sprite() { return sprite; }
void set_to_setup_pose();

View File

@ -0,0 +1,79 @@
#include "SpineSlotNode.h"
void SpineSlotNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_slot_name"), &SpineSlotNode::set_slot_name);
ClassDB::bind_method(D_METHOD("get_slot_name"), &SpineSlotNode::get_slot_name);
ClassDB::bind_method(D_METHOD("_on_world_transforms_changed", "spine_sprite"), &SpineSlotNode::on_world_transforms_changed);
}
SpineSlotNode::SpineSlotNode(): sprite(nullptr) {
}
void SpineSlotNode::_notification(int what) {
switch(what) {
case NOTIFICATION_PARENTED: {
sprite = Object::cast_to<SpineSprite>(get_parent());
if (sprite) {
sprite->connect("world_transforms_changed", this, "_on_world_transforms_changed");
} else {
WARN_PRINT("SpineSlotProxy parent is not a SpineSprite.");
}
NOTIFY_PROPERTY_LIST_CHANGED();
break;
}
case NOTIFICATION_UNPARENTED: {
if (sprite) {
sprite->disconnect("world_transforms_changed", this, "_on_world_transforms_changed");
}
}
default:
break;
}
}
void SpineSlotNode::_get_property_list(List<PropertyInfo>* list) const {
Vector<String> slot_names;
if (sprite) sprite->get_skeleton_data_res()->get_slot_names(slot_names);
else slot_names.push_back(slot_name);
PropertyInfo slot_name_property;
slot_name_property.name = "slot_name";
slot_name_property.type = Variant::STRING;
slot_name_property.hint_string = String(",").join(slot_names);
slot_name_property.hint = PROPERTY_HINT_ENUM;
slot_name_property.usage = PROPERTY_USAGE_DEFAULT;
list->push_back(slot_name_property);
}
bool SpineSlotNode::_get(const StringName& property, Variant& value) const {
if (property == "slot_name") {
value = slot_name;
return true;
}
return false;
}
bool SpineSlotNode::_set(const StringName& property, const Variant& value) {
if (property == "slot_name") {
slot_name = value;
return true;
}
return false;
}
void SpineSlotNode::on_world_transforms_changed(const Variant& _sprite) {
SpineSprite* sprite = Object::cast_to<SpineSprite>(_sprite.operator Object*());
if (!sprite) return;
auto slot = sprite->get_skeleton()->find_slot(slot_name);
if (!slot.is_valid()) return;
auto bone = slot->get_bone();
if (!bone.is_valid()) return;
this->set_global_transform(bone->get_global_transform());
}
void SpineSlotNode::set_slot_name(const String& _slot_name) {
slot_name = _slot_name;
}
String SpineSlotNode::get_slot_name() {
return slot_name;
}

View File

@ -0,0 +1,29 @@
#ifndef GODOT_SPINESLOTNODE_H
#define GODOT_SPINESLOTNODE_H
#include "SpineCommon.h"
#include "SpineSprite.h"
#include "scene/2d/node_2d.h"
class SpineSlotNode: public Node2D {
GDCLASS(SpineSlotNode, Node2D)
protected:
String slot_name;
SpineSprite *sprite;
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 on_world_transforms_changed(const Variant &_sprite);
public:
SpineSlotNode();
void set_slot_name(const String &_slot_name);
String get_slot_name();
};
#endif

View File

@ -52,7 +52,7 @@ void SpineTransformConstraint::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_active", "v"), &SpineTransformConstraint::set_active);
}
SpineTransformConstraint::SpineTransformConstraint() : transform_constraint(nullptr) {
SpineTransformConstraint::SpineTransformConstraint() : transform_constraint(nullptr), sprite(nullptr) {
}
void SpineTransformConstraint::update() {
@ -81,7 +81,7 @@ Array SpineTransformConstraint::get_bones() {
for (int i = 0; i < bones.size(); ++i) {
auto bone = bones[i];
Ref<SpineBone> bone_ref(memnew(SpineBone));
bone_ref->set_spine_object(bone);
bone_ref->set_spine_object(sprite, bone);
result[i] = bone_ref;
}
return result;
@ -92,7 +92,7 @@ Ref<SpineBone> SpineTransformConstraint::get_target() {
auto target = transform_constraint->getTarget();
if (!target) return nullptr;
Ref<SpineBone> target_ref(memnew(SpineBone));
target_ref->set_spine_object(target);
target_ref->set_spine_object(sprite, target);
return target_ref;
}

View File

@ -43,12 +43,14 @@ protected:
private:
spine::TransformConstraint *transform_constraint;
SpineSprite *sprite;
public:
SpineTransformConstraint();
void set_spine_object(spine::TransformConstraint *tc) { transform_constraint = tc; }
void set_spine_object(SpineSprite *_sprite, spine::TransformConstraint *_transform_constraint) { sprite = _sprite; transform_constraint = _transform_constraint; }
spine::TransformConstraint *get_spine_object() { return transform_constraint; }
SpineSprite *get_spine_sprite() { return sprite; }
void update();

View File

@ -49,6 +49,7 @@
#include "SpineTimeline.h"
#include "SpineConstant.h"
#include "SpineCollisionShapeProxy.h"
#include "SpineSlotNode.h"
static Ref<SpineAtlasResourceFormatLoader> atlas_loader;
static Ref<SpineAtlasResourceFormatSaver> atlas_saver;
@ -98,6 +99,7 @@ void register_spine_godot_types() {
ClassDB::register_class<SpineTimeline>();
ClassDB::register_class<SpineConstant>();
ClassDB::register_class<SpineCollisionShapeProxy>();
ClassDB::register_class<SpineSlotNode>();
#if VERSION_MAJOR > 3
atlas_loader.instantiate();