diff --git a/.github/actions/setup-godot-deps-4/action.yml b/.github/actions/setup-godot-deps-4/action.yml index 3df153ec9..7bfc6ca17 100644 --- a/.github/actions/setup-godot-deps-4/action.yml +++ b/.github/actions/setup-godot-deps-4/action.yml @@ -26,7 +26,7 @@ runs: python -m pip install scons==4.7.0 scons --version - - name: Setup dotnet 6 + - name: Setup dotnet 8 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' \ No newline at end of file + dotnet-version: '8.0.x' \ No newline at end of file diff --git a/spine-godot/spine_godot/SpineAnimationTrack.cpp b/spine-godot/spine_godot/SpineAnimationTrack.cpp index 404beb71f..a6965bbd3 100644 --- a/spine-godot/spine_godot/SpineAnimationTrack.cpp +++ b/spine-godot/spine_godot/SpineAnimationTrack.cpp @@ -251,7 +251,7 @@ Ref SpineAnimationTrack::create_animation(spine::Animation *animation Ref animation_ref; INSTANTIATE(animation_ref); String name; - name.parse_utf8(animation.getName().buffer()); + name.parse_utf8(animation->getName().buffer()); animation_ref->set_name(name + (loop ? "" : "_looped")); #if VERSION_MAJOR > 3 // animation_ref->set_loop(!loop); diff --git a/spine-godot/spine_godot/SpineAtlasResource.cpp b/spine-godot/spine_godot/SpineAtlasResource.cpp index 73ab6f1be..6d8a5251d 100644 --- a/spine-godot/spine_godot/SpineAtlasResource.cpp +++ b/spine-godot/spine_godot/SpineAtlasResource.cpp @@ -62,10 +62,9 @@ class GodotSpineTextureLoader : public spine::TextureLoader { Array *textures; Array *normal_maps; String normal_map_prefix; - bool is_importing; public: - GodotSpineTextureLoader(Array *_textures, Array *_normal_maps, const String &normal_map_prefix, bool is_importing) : textures(_textures), normal_maps(_normal_maps), normal_map_prefix(normal_map_prefix), is_importing(is_importing) { + GodotSpineTextureLoader(Array *_textures, Array *_normal_maps, const String &normal_map_prefix, bool is_importing) : textures(_textures), normal_maps(_normal_maps), normal_map_prefix(normal_map_prefix) { } static bool fix_path(String &path) { diff --git a/spine-godot/spine_godot/SpineSprite.cpp b/spine-godot/spine_godot/SpineSprite.cpp index f89a42633..c29e250bf 100644 --- a/spine-godot/spine_godot/SpineSprite.cpp +++ b/spine-godot/spine_godot/SpineSprite.cpp @@ -434,6 +434,9 @@ void SpineSprite::_bind_methods() { ClassDB::bind_method(D_METHOD("set_screen_material", "material"), &SpineSprite::set_screen_material); ClassDB::bind_method(D_METHOD("get_screen_material"), &SpineSprite::get_screen_material); + ClassDB::bind_method(D_METHOD("get_time_scale"), &SpineSprite::get_time_scale); + ClassDB::bind_method(D_METHOD("set_time_scale", "v"), &SpineSprite::set_time_scale); + ClassDB::bind_method(D_METHOD("set_debug_root", "v"), &SpineSprite::set_debug_root); ClassDB::bind_method(D_METHOD("get_debug_root"), &SpineSprite::get_debug_root); ClassDB::bind_method(D_METHOD("set_debug_root_color", "v"), &SpineSprite::set_debug_root_color); @@ -509,7 +512,7 @@ void SpineSprite::_bind_methods() { // Filled in in _get_property_list() } -SpineSprite::SpineSprite() : update_mode(SpineConstant::UpdateMode_Process), preview_skin("Default"), preview_animation("-- Empty --"), preview_frame(false), preview_time(0), skeleton_clipper(nullptr), modified_bones(false) { +SpineSprite::SpineSprite() : update_mode(SpineConstant::UpdateMode_Process), time_scale(1.0), preview_skin("Default"), preview_animation("-- Empty --"), preview_frame(false), preview_time(0), skeleton_clipper(nullptr), modified_bones(false) { skeleton_clipper = new spine::SkeletonClipping(); auto statics = SpineSpriteStatics::instance(); @@ -817,12 +820,12 @@ void SpineSprite::update_skeleton(float delta) { return; emit_signal(SNAME("before_animation_state_update"), this); - animation_state->update(delta); + animation_state->update(delta * time_scale); if (!is_visible_in_tree()) return; emit_signal(SNAME("before_animation_state_apply"), this); animation_state->apply(skeleton); emit_signal(SNAME("before_world_transforms_change"), this); - skeleton->update(delta); + skeleton->update(delta * time_scale); skeleton->update_world_transform(SpineConstant::Physics_Update); modified_bones = false; emit_signal(SNAME("world_transforms_changed"), this); @@ -1401,6 +1404,14 @@ void SpineSprite::set_screen_material(Ref material) { screen_material = material; } +void SpineSprite::set_time_scale(float time_scale) { + this->time_scale = time_scale; +} + +float SpineSprite::get_time_scale() { + return time_scale; +} + #ifndef SPINE_GODOT_EXTENSION // FIXME #ifdef TOOLS_ENABLED diff --git a/spine-godot/spine_godot/SpineSprite.h b/spine-godot/spine_godot/SpineSprite.h index 92ac4b413..151ec475c 100644 --- a/spine-godot/spine_godot/SpineSprite.h +++ b/spine-godot/spine_godot/SpineSprite.h @@ -141,6 +141,7 @@ protected: Ref skeleton; Ref animation_state; SpineConstant::UpdateMode update_mode; + float time_scale; String preview_skin; String preview_animation; @@ -230,6 +231,10 @@ public: void set_screen_material(Ref material); + void set_time_scale(float time_scale); + + float get_time_scale(); + bool get_debug_root() { return debug_root; } void set_debug_root(bool root) { debug_root = root; } diff --git a/spine-ts/index.html b/spine-ts/index.html index 8ac653b04..2767da1a7 100644 --- a/spine-ts/index.html +++ b/spine-ts/index.html @@ -43,6 +43,7 @@
  • Physics III - (v7)
  • Physics IV - (v7)
  • Slot Objects - (v7)
  • +
  • Slot Objects (Rotation, scale test) - (v7)
  • Bounds - (v7)
  • Bunny Mark - (v7)
  • diff --git a/spine-ts/package-lock.json b/spine-ts/package-lock.json index 314cc0340..05a412d29 100644 --- a/spine-ts/package-lock.json +++ b/spine-ts/package-lock.json @@ -1,12 +1,12 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.2.79", + "version": "4.2.80", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@esotericsoftware/spine-ts", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "workspaces": [ "spine-core", @@ -3244,18 +3244,18 @@ }, "spine-canvas": { "name": "@esotericsoftware/spine-canvas", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" } }, "spine-canvaskit": { "name": "@esotericsoftware/spine-canvaskit", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79", + "@esotericsoftware/spine-core": "4.2.80", "canvaskit-wasm": "0.39.1" }, "devDependencies": { @@ -3265,17 +3265,17 @@ }, "spine-core": { "name": "@esotericsoftware/spine-core", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE" }, "spine-phaser-v3": { "name": "@esotericsoftware/spine-phaser-v3", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-canvas": "4.2.79", - "@esotericsoftware/spine-core": "4.2.79", - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-canvas": "4.2.80", + "@esotericsoftware/spine-core": "4.2.80", + "@esotericsoftware/spine-webgl": "4.2.80" }, "devDependencies": { "phaser": "^3.60.0" @@ -3299,12 +3299,12 @@ }, "spine-phaser-v4": { "name": "@esotericsoftware/spine-phaser-v4", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-canvas": "4.2.79", - "@esotericsoftware/spine-core": "4.2.79", - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-canvas": "4.2.80", + "@esotericsoftware/spine-core": "4.2.80", + "@esotericsoftware/spine-webgl": "4.2.80" }, "devDependencies": { "phaser": "^4.0.0-rc.1" @@ -3315,10 +3315,10 @@ }, "spine-pixi-v7": { "name": "@esotericsoftware/spine-pixi-v7", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "peerDependencies": { "@pixi/assets": "^7.2.4", @@ -3332,10 +3332,10 @@ }, "spine-pixi-v8": { "name": "@esotericsoftware/spine-pixi-v8", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "peerDependencies": { "pixi.js": "^8.4.0" @@ -3343,18 +3343,18 @@ }, "spine-player": { "name": "@esotericsoftware/spine-player", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-webgl": "4.2.80" } }, "spine-threejs": { "name": "@esotericsoftware/spine-threejs", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "devDependencies": { "@types/three": "0.162.0" @@ -3365,10 +3365,10 @@ }, "spine-webgl": { "name": "@esotericsoftware/spine-webgl", - "version": "4.2.79", + "version": "4.2.80", "license": "LicenseRef-LICENSE", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" } } } diff --git a/spine-ts/package.json b/spine-ts/package.json index a775ce469..a29c7d5cb 100644 --- a/spine-ts/package.json +++ b/spine-ts/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-ts", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "type": "module", "files": [ diff --git a/spine-ts/spine-canvas/package.json b/spine-ts/spine-canvas/package.json index 0f0cd077b..57f003436 100644 --- a/spine-ts/spine-canvas/package.json +++ b/spine-ts/spine-canvas/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-canvas", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,6 +31,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" } } \ No newline at end of file diff --git a/spine-ts/spine-canvaskit/package.json b/spine-ts/spine-canvaskit/package.json index 6e1ccb54f..ae6860363 100644 --- a/spine-ts/spine-canvaskit/package.json +++ b/spine-ts/spine-canvaskit/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-canvaskit", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for CanvasKit for NodeJS", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79", + "@esotericsoftware/spine-core": "4.2.80", "canvaskit-wasm": "0.39.1" }, "devDependencies": { diff --git a/spine-ts/spine-core/package.json b/spine-ts/spine-core/package.json index 7bed9eb87..702fb8bb5 100644 --- a/spine-ts/spine-core/package.json +++ b/spine-ts/spine-core/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-core", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/spine-ts/spine-phaser-v3/package.json b/spine-ts/spine-phaser-v3/package.json index 3522ac824..8e2584556 100644 --- a/spine-ts/spine-phaser-v3/package.json +++ b/spine-ts/spine-phaser-v3/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-phaser-v3", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the Phaser v3.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,9 +31,9 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-canvas": "4.2.79", - "@esotericsoftware/spine-core": "4.2.79", - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-canvas": "4.2.80", + "@esotericsoftware/spine-core": "4.2.80", + "@esotericsoftware/spine-webgl": "4.2.80" }, "devDependencies": { "phaser": "^3.60.0" diff --git a/spine-ts/spine-phaser-v4/package.json b/spine-ts/spine-phaser-v4/package.json index c5739752e..1d0733641 100644 --- a/spine-ts/spine-phaser-v4/package.json +++ b/spine-ts/spine-phaser-v4/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-phaser-v4", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the Phaser v4.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,9 +31,9 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-canvas": "4.2.79", - "@esotericsoftware/spine-core": "4.2.79", - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-canvas": "4.2.80", + "@esotericsoftware/spine-core": "4.2.80", + "@esotericsoftware/spine-webgl": "4.2.80" }, "devDependencies": { "phaser": "^4.0.0-rc.1" diff --git a/spine-ts/spine-pixi-v7/example/slot-objects-scale-rotation.html b/spine-ts/spine-pixi-v7/example/slot-objects-scale-rotation.html new file mode 100644 index 000000000..21c7ed04f --- /dev/null +++ b/spine-ts/spine-pixi-v7/example/slot-objects-scale-rotation.html @@ -0,0 +1,130 @@ + + + + spine-pixi + + + + + + + + + + + + + \ No newline at end of file diff --git a/spine-ts/spine-pixi-v7/package.json b/spine-ts/spine-pixi-v7/package.json index 62ac95a0d..7948d4376 100644 --- a/spine-ts/spine-pixi-v7/package.json +++ b/spine-ts/spine-pixi-v7/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-pixi-v7", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web PixiJS v7.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "peerDependencies": { "@pixi/core": "^7.2.4", diff --git a/spine-ts/spine-pixi-v7/src/Spine.ts b/spine-ts/spine-pixi-v7/src/Spine.ts index 78d6d72d6..4b2b4538f 100644 --- a/spine-ts/spine-pixi-v7/src/Spine.ts +++ b/spine-ts/spine-pixi-v7/src/Spine.ts @@ -34,7 +34,6 @@ import { AtlasAttachmentLoader, ClippingAttachment, Color, - MathUtils, MeshAttachment, Physics, RegionAttachment, @@ -52,7 +51,7 @@ import { SlotMesh } from "./SlotMesh.js"; import { DarkSlotMesh } from "./DarkSlotMesh.js"; import type { ISpineDebugRenderer, SpineDebugRenderer } from "./SpineDebugRenderer.js"; import { Assets } from "@pixi/assets"; -import { IPointData, Point, Rectangle } from "@pixi/core"; +import { IPointData, Point } from "@pixi/core"; import { Ticker } from "@pixi/core"; import type { IDestroyOptions, DisplayObject } from "@pixi/display"; import { Bounds, Container } from "@pixi/display"; @@ -593,8 +592,24 @@ export class Spine extends Container { if (slotObject.visible) { slotObject.position.set(slot.bone.worldX, slot.bone.worldY); - slotObject.scale.set(slot.bone.getWorldScaleX(), slot.bone.getWorldScaleY()); - slotObject.rotation = slot.bone.getWorldRotationX() * MathUtils.degRad; + slotObject.angle = slot.bone.getWorldRotationX(); + + let bone: Bone | null = slot.bone; + let cumulativeScaleX = 1; + let cumulativeScaleY = 1; + while (bone) { + cumulativeScaleX *= bone.scaleX; + cumulativeScaleY *= bone.scaleY; + bone = bone.parent; + }; + + if (cumulativeScaleX < 0) slotObject.angle -= 180; + + slotObject.scale.set( + slot.bone.getWorldScaleX() * Math.sign(cumulativeScaleX), + slot.bone.getWorldScaleY() * Math.sign(cumulativeScaleY), + ); + slotObject.zIndex = zIndex + 1; slotObject.alpha = this.skeleton.color.a * slot.color.a; } diff --git a/spine-ts/spine-pixi-v8/example/slot-objects-scale-rotation.html b/spine-ts/spine-pixi-v8/example/slot-objects-scale-rotation.html new file mode 100644 index 000000000..ab0df26d1 --- /dev/null +++ b/spine-ts/spine-pixi-v8/example/slot-objects-scale-rotation.html @@ -0,0 +1,126 @@ + + + + spine-pixi + + + + + + + + + + + + + \ No newline at end of file diff --git a/spine-ts/spine-pixi-v8/package.json b/spine-ts/spine-pixi-v8/package.json index c7a726386..5f271534f 100644 --- a/spine-ts/spine-pixi-v8/package.json +++ b/spine-ts/spine-pixi-v8/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-pixi-v8", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for PixiJS v8.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "peerDependencies": { "pixi.js": "^8.4.0" diff --git a/spine-ts/spine-pixi-v8/src/Spine.ts b/spine-ts/spine-pixi-v8/src/Spine.ts index 814650c6c..f1abba454 100644 --- a/spine-ts/spine-pixi-v8/src/Spine.ts +++ b/spine-ts/spine-pixi-v8/src/Spine.ts @@ -33,7 +33,6 @@ import { Cache, Container, ContainerOptions, - DEG_TO_RAD, DestroyOptions, fastCopy, Graphics, @@ -785,14 +784,25 @@ export class Spine extends ViewContainer { container.visible = this.skeleton.drawOrder.includes(slot) && followAttachmentValue; if (container.visible) { - const bone = slot.bone; + let bone: Bone | null = slot.bone; container.position.set(bone.worldX, bone.worldY); + container.angle = bone.getWorldRotationX(); - container.scale.x = bone.getWorldScaleX(); - container.scale.y = bone.getWorldScaleY(); + let cumulativeScaleX = 1; + let cumulativeScaleY = 1; + while (bone) { + cumulativeScaleX *= bone.scaleX; + cumulativeScaleY *= bone.scaleY; + bone = bone.parent; + }; - container.rotation = bone.getWorldRotationX() * DEG_TO_RAD; + if (cumulativeScaleX < 0) container.angle -= 180; + + container.scale.set( + slot.bone.getWorldScaleX() * Math.sign(cumulativeScaleX), + slot.bone.getWorldScaleY() * Math.sign(cumulativeScaleY), + ); container.alpha = this.skeleton.color.a * slot.color.a; } diff --git a/spine-ts/spine-player/package.json b/spine-ts/spine-player/package.json index 95b0aaa7c..24633d07f 100644 --- a/spine-ts/spine-player/package.json +++ b/spine-ts/spine-player/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-player", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,6 +31,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-webgl": "4.2.79" + "@esotericsoftware/spine-webgl": "4.2.80" } } \ No newline at end of file diff --git a/spine-ts/spine-threejs/package.json b/spine-ts/spine-threejs/package.json index 752d73ae4..51e466546 100644 --- a/spine-ts/spine-threejs/package.json +++ b/spine-ts/spine-threejs/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-threejs", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,7 +31,7 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" }, "devDependencies": { "@types/three": "0.162.0" diff --git a/spine-ts/spine-webgl/package.json b/spine-ts/spine-webgl/package.json index e027af6f8..e4b9aacd5 100644 --- a/spine-ts/spine-webgl/package.json +++ b/spine-ts/spine-webgl/package.json @@ -1,6 +1,6 @@ { "name": "@esotericsoftware/spine-webgl", - "version": "4.2.79", + "version": "4.2.80", "description": "The official Spine Runtimes for the web.", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -31,6 +31,6 @@ }, "homepage": "https://github.com/esotericsoftware/spine-runtimes#readme", "dependencies": { - "@esotericsoftware/spine-core": "4.2.79" + "@esotericsoftware/spine-core": "4.2.80" } } \ No newline at end of file diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs index fc2ce2513..e851daaac 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonUtilityBoneInspector.cs @@ -310,7 +310,6 @@ namespace Spine.Unity.Editor { UnityEditor.EditorUtility.DisplayDialog("No parent SkeletonUtilityBone found!", "Please select the first physically moving chain node, having a parent GameObject with a SkeletonUtilityBone component attached.", "OK"); return; } - float mass = 10; const float rotationLimit = 20.0f; @@ -334,40 +333,55 @@ namespace Spine.Unity.Editor { //followRotationComponent.reference = skeletonUtility.boneRoot; // Follower Kinematic Rigidbody - GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower"); - followerKinematicObject.transform.parent = normalChainParentObject.transform; - Rigidbody2D followerRigidbody = followerKinematicObject.AddComponent(); + GameObject rootFollowerKinematic = new GameObject(kinematicParentUtilityBone.name + " Follower"); + rootFollowerKinematic.transform.parent = normalChainParentObject.transform; + Rigidbody2D followerRigidbody = rootFollowerKinematic.AddComponent(); followerRigidbody.mass = mass; followerRigidbody.isKinematic = true; - followerKinematicObject.AddComponent().reference = kinematicParentUtilityBone.transform; - followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position; - followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation; + rootFollowerKinematic.AddComponent().reference = kinematicParentUtilityBone.transform; + rootFollowerKinematic.transform.position = kinematicParentUtilityBone.transform.position; + rootFollowerKinematic.transform.rotation = kinematicParentUtilityBone.transform.rotation; - // Child Bones - SkeletonUtilityBone[] utilityBones = utilityBone.GetComponentsInChildren(); - Transform childBoneParentReference = followerKinematicObject.transform; - for (int i = 0; i < utilityBones.Length; ++i) { - SkeletonUtilityBone childBone = utilityBones[i]; - mass *= 0.75f; - childBone.parentReference = (i == 0) ? kinematicParentUtilityBone.transform : childBoneParentReference; - childBone.transform.SetParent(normalChainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity. - AttachRigidbodyAndCollider2D(childBone); - childBone.mode = SkeletonUtilityBone.Mode.Override; - childBone.scale = childBone.position = childBone.zPosition = false; - - HingeJoint2D joint = childBone.gameObject.AddComponent(); - joint.connectedBody = childBoneParentReference.GetComponent(); - joint.useLimits = true; - ApplyJoint2DAngleLimits(joint, rotationLimit, childBoneParentReference, childBone.transform); - - childBone.GetComponent().mass = mass; - childBoneParentReference = childBone.transform; - } + CreateHingeChain2D(utilityBone, mass, rotationLimit, normalChainParentObject.transform, + rootFollowerKinematic.transform, kinematicParentUtilityBone.transform); Duplicate2DHierarchyForFlippedChains(normalChainParentObject, commonParentActivateOnFlip, skeletonUtility.transform, rotationLimit); UnityEditor.Selection.activeGameObject = commonParentObject; } + void CreateHingeChain2D (SkeletonUtilityBone bone, float mass, float rotationLimit, Transform groupObject, + Transform jointParent, Transform utilityParent) { + + mass *= 0.75f; + bone.parentReference = utilityParent; + bone.transform.SetParent(groupObject, true); // we need a flat hierarchy of all Joint objects in Unity. + AttachRigidbodyAndCollider2D(bone); + bone.mode = SkeletonUtilityBone.Mode.Override; + bone.scale = bone.position = bone.zPosition = false; + + HingeJoint2D joint = bone.gameObject.AddComponent(); + joint.connectedBody = jointParent.GetComponent(); + joint.useLimits = true; + ApplyJoint2DAngleLimits(joint, rotationLimit, jointParent, bone.transform); + bone.GetComponent().mass = mass; + + Transform parent = bone.transform; + List children = new List(); + int utilityChildCount = 0; + for (int i = 0; i < parent.childCount; ++i) { + var childUtilityBone = parent.GetChild(i).GetComponent(); + if (childUtilityBone != null) + children.Add(childUtilityBone); + } + mass /= Mathf.Max(1.0f, utilityChildCount); + + for (int i = 0; i < children.Count; ++i) { + SkeletonUtilityBone childBone = children[i]; + if (childBone == null) continue; + CreateHingeChain2D(childBone, mass, rotationLimit, groupObject, parent, parent); + } + } + void ApplyJoint2DAngleLimits (HingeJoint2D joint, float rotationLimit, Transform parentBone, Transform bone) { #if HINGE_JOINT_NEW_BEHAVIOUR float referenceAngle = (parentBone.eulerAngles.z - bone.eulerAngles.z + 360f) % 360f; @@ -452,6 +466,8 @@ namespace Spine.Unity.Editor { UnityEditor.EditorUtility.DisplayDialog("No parent SkeletonUtilityBone found!", "Please select the first physically moving chain node, having a parent GameObject with a SkeletonUtilityBone component attached.", "OK"); return; } + float mass = 10; + const float rotationLimit = 20.0f; SetSkeletonUtilityToFlipByRotation(); @@ -465,39 +481,57 @@ namespace Spine.Unity.Editor { followRotationComponent.reference = skeletonUtility.boneRoot; // Follower Kinematic Rigidbody - GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower"); - followerKinematicObject.transform.parent = chainParentObject.transform; - Rigidbody followerRigidbody = followerKinematicObject.AddComponent(); - followerRigidbody.mass = 10; + GameObject rootFollowerKinematic = new GameObject(kinematicParentUtilityBone.name + " Follower"); + rootFollowerKinematic.transform.parent = chainParentObject.transform; + Rigidbody followerRigidbody = rootFollowerKinematic.AddComponent(); + followerRigidbody.mass = mass; followerRigidbody.isKinematic = true; - followerKinematicObject.AddComponent().reference = kinematicParentUtilityBone.transform; - followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position; - followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation; + rootFollowerKinematic.AddComponent().reference = kinematicParentUtilityBone.transform; + rootFollowerKinematic.transform.position = kinematicParentUtilityBone.transform.position; + rootFollowerKinematic.transform.rotation = kinematicParentUtilityBone.transform.rotation; - // Child Bones - SkeletonUtilityBone[] utilityBones = utilityBone.GetComponentsInChildren(); - Transform childBoneParentReference = followerKinematicObject.transform; - foreach (SkeletonUtilityBone childBone in utilityBones) { - childBone.parentReference = childBoneParentReference; - childBone.transform.SetParent(chainParentObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity. - AttachRigidbodyAndCollider(childBone); - childBone.mode = SkeletonUtilityBone.Mode.Override; + CreateHingeChain(utilityBone, mass, rotationLimit, chainParentObject.transform, rootFollowerKinematic.transform); - HingeJoint joint = childBone.gameObject.AddComponent(); - joint.axis = Vector3.forward; - joint.connectedBody = childBoneParentReference.GetComponent(); - joint.useLimits = true; - joint.limits = new JointLimits { - min = -20, - max = 20 - }; - childBone.GetComponent().mass = childBoneParentReference.transform.GetComponent().mass * 0.75f; - - childBoneParentReference = childBone.transform; - } UnityEditor.Selection.activeGameObject = chainParentObject; } + void CreateHingeChain (SkeletonUtilityBone bone, float mass, float rotationLimit, Transform groupObject, + Transform jointParent) { + + mass *= 0.75f; + + bone.parentReference = jointParent; + bone.transform.SetParent(groupObject.transform, true); // we need a flat hierarchy of all Joint objects in Unity. + AttachRigidbodyAndCollider(bone); + bone.mode = SkeletonUtilityBone.Mode.Override; + + HingeJoint joint = bone.gameObject.AddComponent(); + joint.axis = Vector3.forward; + joint.connectedBody = jointParent.GetComponent(); + joint.useLimits = true; + joint.limits = new JointLimits { + min = -rotationLimit, + max = rotationLimit + }; + bone.GetComponent().mass = mass; + + Transform parent = bone.transform; + List children = new List(); + int utilityChildCount = 0; + for (int i = 0; i < parent.childCount; ++i) { + var childUtilityBone = parent.GetChild(i).GetComponent(); + if (childUtilityBone != null) + children.Add(childUtilityBone); + } + mass /= Mathf.Max(1.0f, utilityChildCount); + + for (int i = 0; i < children.Count; ++i) { + SkeletonUtilityBone childBone = children[i]; + if (childBone == null) continue; + CreateHingeChain(childBone, mass, rotationLimit, groupObject, parent); + } + } + void SetSkeletonUtilityToFlipByRotation () { if (!skeletonUtility.flipBy180DegreeRotation) { skeletonUtility.flipBy180DegreeRotation = true;