[godot] Fix SpineBone::set_global_transform and examples

This commit is contained in:
badlogic 2022-05-02 16:57:46 +02:00
parent 47f21e24b0
commit 2a4adc282e
21 changed files with 151 additions and 65 deletions

View File

@ -1,3 +1,8 @@
[gd_resource type="SpineSkeletonDataResource" format=2]
[gd_resource type="SpineSkeletonDataResource" load_steps=3 format=2]
[ext_resource path="res://assets/raggedyspineboy/Raggedy Spineboy.atlas" type="SpineAtlasResource" id=1]
[ext_resource path="res://assets/raggedyspineboy/raggedy spineboy.json" type="SpineSkeletonFileResource" id=2]
[resource]
atlas_res = ExtResource( 1 )
skeleton_file_res = ExtResource( 2 )

View File

@ -9,4 +9,7 @@
position = Vector2( 496.207, 477.185 )
scale = Vector2( 0.466832, 0.466832 )
skeleton_data_res = ExtResource( 3 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
script = ExtResource( 1 )

View File

@ -11,6 +11,9 @@ script = ExtResource( 1 )
position = Vector2( 473, 487 )
scale = Vector2( 0.575051, 0.575051 )
skeleton_data_res = ExtResource( 2 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="FootstepAudio" type="AudioStreamPlayer" parent="."]
stream = ExtResource( 3 )

View File

@ -9,4 +9,7 @@
position = Vector2( 532.982, 480.287 )
scale = Vector2( 0.441932, 0.441932 )
skeleton_data_res = ExtResource( 1 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
script = ExtResource( 2 )

View File

@ -9,4 +9,7 @@
position = Vector2( 501.503, 472.035 )
scale = Vector2( 0.518624, 0.518624 )
skeleton_data_res = ExtResource( 1 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
script = ExtResource( 2 )

View File

@ -22,5 +22,4 @@ scale = Vector2( 1, 1 )
bone_name = "gun-tip"
[node name="Sprite" type="Sprite" parent="Spineboy/GunTipBone"]
scale = Vector2( 1, 1 )
texture = ExtResource( 3 )

View File

@ -12,6 +12,9 @@ script = ExtResource( 1 )
position = Vector2( 474, 506 )
scale = Vector2( 0.560712, 0.560712 )
skeleton_data_res = ExtResource( 2 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="GunSlot" type="SpineSlotNode" parent="Spineboy"]
position = Vector2( 40.8753, -276.036 )
@ -23,6 +26,9 @@ slot_name = "gun"
position = Vector2( 84.6909, -67.9174 )
scale = Vector2( 0.193472, 0.193472 )
skeleton_data_res = ExtResource( 3 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="EyeSlot" type="SpineSlotNode" parent="Spineboy"]
position = Vector2( -23.4598, -402.301 )
@ -45,3 +51,6 @@ slot_name = "front-fist"
position = Vector2( -2.64624, -10.8111 )
scale = Vector2( 0.193389, 0.193389 )
skeleton_data_res = ExtResource( 2 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0

View File

@ -1850,6 +1850,9 @@ script = ExtResource( 2 )
position = Vector2( 72.0001, 520 )
scale = Vector2( 0.323942, 0.323942 )
skeleton_data_res = ExtResource( 1 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="SpineAnimationTrack" type="SpineAnimationTrack" parent="Spineboy"]
track_index = 0
@ -1916,6 +1919,9 @@ anims/walk_looped = SubResource( 129 )
position = Vector2( 1284, 520 )
scale = Vector2( -0.328761, 0.328761 )
skeleton_data_res = ExtResource( 3 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="SpineAnimationTrack" type="SpineAnimationTrack" parent="Raptor"]
track_index = 0

View File

@ -31,9 +31,12 @@ position = Vector2( 501, 507 )
scale = Vector2( 0.546374, 0.546373 )
skeleton_data_res = ExtResource( 1 )
normal_material = SubResource( 2 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="GunSlot" type="SpineSlotNode" parent="SpineSprite"]
position = Vector2( 40.8752, -276.036 )
position = Vector2( 40.8753, -276.036 )
rotation = 0.837234
scale = Vector2( 1, 1 )
slot_name = "gun"

View File

@ -11,6 +11,9 @@ script = ExtResource( 3 )
position = Vector2( 576, 506 )
scale = Vector2( 0.458967, 0.458967 )
skeleton_data_res = ExtResource( 1 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="Light2D" type="Light2D" parent="."]
position = Vector2( 822, 270 )

View File

@ -5,24 +5,15 @@ 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():
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
spineboy.global_position.y = center_bone.global_position.y

View File

@ -7,7 +7,7 @@
script = ExtResource( 1 )
[node name="SpineSprite" type="SpineSprite" parent="."]
position = Vector2( 63, 549 )
position = Vector2( 8, 553 )
scale = Vector2( 0.278096, 0.278096 )
skeleton_data_res = ExtResource( 2 )
preview_animation = "hoverboard"
@ -15,7 +15,6 @@ preview_frame = true
preview_time = 0.0
[node name="HoverboardCenterBone" type="SpineBoneNode" parent="SpineSprite"]
position = Vector2( 21.5753, -111.472 )
bone_name = "hoverboard-controller"
bone_mode = 1
@ -24,7 +23,8 @@ enabled = true
cast_to = Vector2( 0, 1000 )
[node name="HoverboardTargetBone" type="SpineBoneNode" parent="SpineSprite"]
position = Vector2( 265.717, -112.716 )
position = Vector2( 262.499, 0 )
rotation = -0.000872665
bone_name = "board-ik"
bone_mode = 1
@ -33,7 +33,8 @@ enabled = true
cast_to = Vector2( 0, 1000 )
[node name="HipBone" type="SpineBoneNode" parent="SpineSprite"]
position = Vector2( -36.9481, -338.198 )
position = Vector2( 0, -169.006 )
rotation = -0.000872665
bone_name = "hip"
bone_mode = 1

View File

@ -0,0 +1,20 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://assets/raggedyspineboy/raggedy spineboy-res.tres" type="SpineSkeletonDataResource" id=1]
[node name="Node2D" type="Node2D"]
[node name="SpineSprite" type="SpineSprite" parent="."]
position = Vector2( 502, 480 )
skeleton_data_res = ExtResource( 1 )
preview_animation = "-- Empty --"
preview_frame = false
preview_time = 0.0
[node name="Ragdoll" type="Node2D" parent="SpineSprite"]
[node name="SpineBoneNode" type="SpineBoneNode" parent="SpineSprite/Ragdoll"]
position = Vector2( -11.8961, -346.865 )
rotation = 3.0463
bone_name = "hair2"
bone_mode = 1

View File

@ -6,8 +6,6 @@
[node name="Node2D" type="Node2D"]
[node name="SpineSprite" type="SpineSprite" parent="."]
position = Vector2( 483, 490 )
scale = Vector2( 0.548763, 0.548763 )
skeleton_data_res = ExtResource( 1 )
preview_animation = ""
preview_frame = false
@ -16,11 +14,8 @@ preview_time = 0.0
[node name="SpineBoneNode" type="SpineBoneNode" parent="SpineSprite"]
position = Vector2( 40.8752, -276.036 )
rotation = 0.837234
scale = Vector2( 1, 1 )
bone_name = "gun"
bone_mode = 1
[node name="Sprite" type="Sprite" parent="."]
visible = false
position = Vector2( 505.431, 338.522 )
[node name="Sprite" type="Sprite" parent="SpineSprite/SpineBoneNode"]
texture = ExtResource( 2 )

View File

@ -431,17 +431,16 @@ void SpineBone::apply_world_transform_2d(const Variant &o) {
Transform2D SpineBone::get_transform() {
SPINE_CHECK(get_spine_object(), Transform2D())
Transform2D transform;
transform.rotate(Math::deg2rad(-get_rotation()));
transform.rotate(Math::deg2rad(get_rotation()));
transform.scale(Size2(get_scale_x(), get_scale_y()));
transform.set_origin(Vector2(get_x(), -get_y()));
transform.set_origin(Vector2(get_x(), get_y()));
return transform;
}
void SpineBone::set_transform(Transform2D transform) {
SPINE_CHECK(get_spine_object(),)
Vector2 position = transform.get_origin();
position.y *= -1;
float rotation = Math::rad2deg(-transform.get_rotation());
float rotation = Math::rad2deg(transform.get_rotation());
Vector2 scale = transform.get_scale();
set_x(position.x);
@ -474,19 +473,17 @@ void SpineBone::set_global_transform(Transform2D transform) {
Transform2D inverse_sprite_transform = get_spine_owner()->get_global_transform().affine_inverse();
transform = inverse_sprite_transform * transform;
Vector2 position = transform.get_origin();
float local_x = position.x, local_y = position.y;
float local_rotation = Math::rad2deg(transform.get_rotation());
Vector2 local_scale = transform.get_scale();
float rotation = Math::rad2deg(transform.get_rotation());
Vector2 scale = transform.get_scale();
Vector2 local_position = position;
float local_rotation = bone->worldToLocalRotation(rotation) - 180;
Vector2 local_scale = scale;
spine::Bone *parent = bone->getParent();
if (parent) {
parent->worldToLocal(local_x, local_y, local_x, local_y);
parent->worldToLocal(position.x + local_scale.x, position.y + local_scale.y, local_scale.x, local_scale.y);
local_scale.x = (local_scale.x - local_x);
local_scale.y = -(local_scale.y - local_y);
local_rotation = 180 + bone->worldToLocalRotation(local_rotation);
parent->worldToLocal(local_position.x, local_position.y, local_position.x, local_position.y);
}
bone->setX(local_x);
bone->setY(local_y);
bone->setX(local_position.x);
bone->setY(local_position.y);
bone->setRotation(local_rotation);
bone->setScaleX(local_scale.x);
bone->setScaleY(local_scale.y);

View File

@ -29,6 +29,8 @@
#include "SpineBoneNode.h"
#include "core/engine.h"
void SpineBoneNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_mode"), &SpineBoneNode::set_bone_mode);
ClassDB::bind_method(D_METHOD("get_bone_mode"), &SpineBoneNode::get_bone_mode);
@ -40,7 +42,7 @@ void SpineBoneNode::_bind_methods() {
void SpineBoneNode::_notification(int what) {
switch(what) {
case NOTIFICATION_PARENTED: {
SpineSprite *sprite = cast_to<SpineSprite>(get_parent());
SpineSprite *sprite = find_parent_sprite();
if (sprite) {
#if VERSION_MAJOR > 3
sprite->connect("world_transforms_changed", callable_mp(this, &SpineSlotNode::on_world_transforms_changed));
@ -64,14 +66,19 @@ void SpineBoneNode::_notification(int what) {
break;
}
case NOTIFICATION_UNPARENTED: {
SpineSprite *sprite = cast_to<SpineSprite>(get_parent());
SpineSprite *sprite = find_parent_sprite();
if (sprite) {
#if VERSION_MAJOR > 3
sprite->disconnect("world_transforms_changed", callable_mp(this, &SpineSlotNode::on_world_transforms_changed));
#else
sprite->disconnect("world_transforms_changed", this, "_on_world_transforms_changed");
#endif
}
}
break;
}
case NOTIFICATION_DRAW: {
draw();
break;
}
default:
break;
@ -80,7 +87,7 @@ void SpineBoneNode::_notification(int what) {
void SpineBoneNode::_get_property_list(List<PropertyInfo>* list) const {
Vector<String> bone_names;
SpineSprite *sprite = cast_to<SpineSprite>(get_parent());
SpineSprite *sprite = find_parent_sprite();
if (sprite) sprite->get_skeleton_data_res()->get_bone_names(bone_names);
else bone_names.push_back(bone_name);
auto element = list->front();
@ -109,7 +116,7 @@ bool SpineBoneNode::_get(const StringName& property, Variant& value) const {
bool SpineBoneNode::_set(const StringName& property, const Variant& value) {
if (property == "bone_name") {
bone_name = value;
SpineSprite *sprite = cast_to<SpineSprite>(get_parent());
SpineSprite *sprite = find_parent_sprite();
init_transform(sprite);
return true;
}
@ -119,19 +126,32 @@ bool SpineBoneNode::_set(const StringName& property, const Variant& value) {
void SpineBoneNode::on_world_transforms_changed(const Variant& _sprite) {
SpineSprite* sprite = cast_to<SpineSprite>(_sprite.operator Object*());
update_transform(sprite);
update();
}
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);
Ref<SpineBone> bone = find_bone();
if (!bone.is_valid()) return;
Transform2D bone_transform = bone->get_global_transform();
Transform2D this_transform = get_global_transform();
if (bone_mode == SpineConstant::BoneMode_Drive) {
bone->set_global_transform(get_global_transform());
bone->set_global_transform(this_transform);
} else {
this->set_global_transform(bone->get_global_transform());
set_global_transform(bone_transform);
}
if (Engine::get_singleton()->is_editor_hint()) {
#if VERSION_MAJOR == 3
_change_notify("transform/translation");
_change_notify("transform/rotation");
_change_notify("transform/scale");
_change_notify("translation");
_change_notify("rotation");
_change_notify("rotation_deg");
_change_notify("scale");
#endif
}
}
@ -139,17 +159,38 @@ void SpineBoneNode::init_transform(SpineSprite* sprite) {
if (!sprite) return;
if (bone_mode == SpineConstant::BoneMode_Drive) return;
sprite->get_skeleton()->set_to_setup_pose();
set_global_transform(sprite->get_global_bone_transform(bone_name));
sprite->get_skeleton()->update_world_transform();
Transform2D global_transform = sprite->get_global_bone_transform(bone_name);
set_global_transform(global_transform);
update_transform(sprite);
#if VERSION_MAJOR == 3
_change_notify("transform/translation");
_change_notify("transform/rotation");
_change_notify("transform/scale");
_change_notify("translation");
_change_notify("rotation");
_change_notify("rotation_deg");
_change_notify("scale");
#endif
}
SpineSprite *SpineBoneNode::find_parent_sprite() const {
auto parent = get_parent();
SpineSprite *sprite = nullptr;
while (parent) {
sprite = cast_to<SpineSprite>(parent);
if (sprite) break;
parent = parent->get_parent();
}
return sprite;
}
Ref<SpineBone> SpineBoneNode::find_bone() const {
if (!is_visible_in_tree()) return nullptr;
SpineSprite *sprite = find_parent_sprite();
if (!sprite) return nullptr;
if (!sprite->get_skeleton().is_valid() || !sprite->get_skeleton()->get_spine_object()) return nullptr;
auto bone = sprite->get_skeleton()->find_bone(bone_name);
return bone;
}
void SpineBoneNode::draw() {
if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) return;
Ref<SpineBone> bone = find_bone();
if (!bone.is_valid()) return;
draw_circle(get_global_position(), 10, Color::hex(0xffff0000));
}
SpineConstant::BoneMode SpineBoneNode::get_bone_mode() {
@ -158,6 +199,6 @@ SpineConstant::BoneMode SpineBoneNode::get_bone_mode() {
void SpineBoneNode::set_bone_mode(SpineConstant::BoneMode _bone_mode) {
bone_mode = _bone_mode;
SpineSprite *sprite = cast_to<SpineSprite>(get_parent());
SpineSprite *sprite = find_parent_sprite();
init_transform(sprite);
}

View File

@ -48,6 +48,9 @@ protected:
void on_world_transforms_changed(const Variant &_sprite);
void update_transform(SpineSprite *sprite);
void init_transform(SpineSprite *sprite);
SpineSprite *find_parent_sprite() const;
Ref<SpineBone> find_bone() const;
void draw();;
public:
SpineBoneNode(): bone_mode(SpineConstant::BoneMode_Follow) {}

View File

@ -354,5 +354,5 @@ float SpineSkeleton::get_scale_y() {
void SpineSkeleton::set_scale_y(float v) {
SPINE_CHECK(skeleton,)
skeleton->setScaleY(-v);
skeleton->setScaleY(v);
}

View File

@ -149,6 +149,7 @@ void SpineSlotNode::on_world_transforms_changed(const Variant& _sprite) {
}
void SpineSlotNode::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 slot = sprite->get_skeleton()->find_slot(slot_name);
@ -160,7 +161,6 @@ void SpineSlotNode::update_transform(SpineSprite *sprite) {
}
auto bone = slot->get_bone();
if (!bone.is_valid()) return;
if (!is_visible_in_tree()) return;
this->set_global_transform(bone->get_global_transform());
}

View File

@ -90,7 +90,7 @@ void SpineSprite::_bind_methods() {
ADD_GROUP("Preview", "");
}
SpineSprite::SpineSprite() : update_mode(SpineConstant::UpdateMode_Process), skeleton_clipper(nullptr), preview_frame(false), preview_time(0), modified_bones(false) {
SpineSprite::SpineSprite() : update_mode(SpineConstant::UpdateMode_Process), preview_animation("-- Empty --"), preview_frame(false), preview_time(0), skeleton_clipper(nullptr), modified_bones(false) {
skeleton_clipper = new spine::SkeletonClipping();
// One material per blend mode, shared across all sprites.
@ -162,7 +162,6 @@ void SpineSprite::on_skeleton_data_changed() {
if (skeleton_data_res.is_valid() && skeleton_data_res->is_skeleton_data_loaded()) {
skeleton = Ref<SpineSkeleton>(memnew(SpineSkeleton));
skeleton->set_spine_sprite(this);
skeleton->get_spine_object()->setScaleY(-1);
animation_state = Ref<SpineAnimationState>(memnew(SpineAnimationState));
animation_state->set_spine_sprite(this);

View File

@ -72,6 +72,8 @@ void register_spine_godot_types() {
EditorNode::add_init_callback(editor_init_callback);
ClassDB::register_class<SpineEditorPropertyAnimationMixes>();
#endif
spine::Bone::setYDown(true);
ClassDB::register_class<SpineAtlasResource>();
ClassDB::register_class<SpineSkeletonFileResource>();
ClassDB::register_class<SpineSkeletonDataResource>();