diff --git a/spine-unity/Assets/spine-unity/BoneFollower.cs b/spine-unity/Assets/spine-unity/BoneFollower.cs
index ed3b60441..2b88a12c2 100644
--- a/spine-unity/Assets/spine-unity/BoneFollower.cs
+++ b/spine-unity/Assets/spine-unity/BoneFollower.cs
@@ -125,10 +125,7 @@ namespace Spine.Unity {
if (skeletonTransformIsParent) {
// Recommended setup: Use local transform properties if Spine GameObject is the immediate parent
thisTransform.localPosition = new Vector3(bone.worldX, bone.worldY, followZPosition ? 0f : thisTransform.localPosition.z);
- if (followBoneRotation) {
- var halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f;
- thisTransform.localRotation = new Quaternion(0, 0, Mathf.Sin(halfRotation), Mathf.Cos(halfRotation)); //thisTransform.localRotation = Quaternion.Euler(0f, 0f, bone.WorldRotationX);
- }
+ if (followBoneRotation) thisTransform.localRotation = bone.GetQuaternion();
} else {
// For special cases: Use transform world properties if transform relationship is complicated
Vector3 targetWorldPosition = skeletonTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY, 0f));
diff --git a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs
index 0e6e43987..cfba986e4 100644
--- a/spine-unity/Assets/spine-unity/SkeletonExtensions.cs
+++ b/spine-unity/Assets/spine-unity/SkeletonExtensions.cs
@@ -134,6 +134,28 @@ namespace Spine.Unity {
return spineGameObjectTransform.TransformPoint(new Vector3(bone.worldX, bone.worldY));
}
+ /// Gets a skeleton space UnityEngine.Quaternion representation of bone.WorldRotationX.
+ public static Quaternion GetQuaternion (this Bone bone) {
+ var halfRotation = Mathf.Atan2(bone.c, bone.a) * 0.5f;
+ return new Quaternion(0, 0, Mathf.Sin(halfRotation), Mathf.Cos(halfRotation));
+ }
+
+ /// Gets the PointAttachment's Unity World position using its Spine GameObject Transform.
+ public static Vector3 GetWorldPosition (this PointAttachment attachment, Slot slot, Transform spineGameObjectTransform) {
+ Vector3 skeletonSpacePosition;
+ skeletonSpacePosition.z = 0;
+ attachment.ComputeWorldPosition(slot.bone, out skeletonSpacePosition.x, out skeletonSpacePosition.y);
+ return spineGameObjectTransform.TransformPoint(skeletonSpacePosition);
+ }
+
+ /// Gets the PointAttachment's Unity World position using its Spine GameObject Transform.
+ public static Vector3 GetWorldPosition (this PointAttachment attachment, Bone bone, Transform spineGameObjectTransform) {
+ Vector3 skeletonSpacePosition;
+ skeletonSpacePosition.z = 0;
+ attachment.ComputeWorldPosition(bone, out skeletonSpacePosition.x, out skeletonSpacePosition.y);
+ return spineGameObjectTransform.TransformPoint(skeletonSpacePosition);
+ }
+
/// Gets the internal bone matrix as a Unity bonespace-to-skeletonspace transformation matrix.
public static Matrix4x4 GetMatrix4x4 (this Bone bone) {
return new Matrix4x4 {
diff --git a/spine-unity/Assets/spine-unity/SpineAttributes.cs b/spine-unity/Assets/spine-unity/SpineAttributes.cs
index 1876c55df..8836c0a43 100644
--- a/spine-unity/Assets/spine-unity/SpineAttributes.cs
+++ b/spine-unity/Assets/spine-unity/SpineAttributes.cs
@@ -50,11 +50,12 @@ namespace Spine.Unity {
/// Smart popup menu for Spine Slots
///
/// Filters popup results to elements that begin with supplied string.
+ /// Disables popup results that don't contain bounding box attachments when true.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives).
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
///
- /// Disables popup results that don't contain bounding box attachments when true.
public SpineSlot(string startsWith = "", string dataField = "", bool containsBoundingBoxes = false, bool includeNone = true) {
this.startsWith = startsWith;
this.dataField = dataField;
@@ -68,6 +69,7 @@ namespace Spine.Unity {
/// Smart popup menu for Spine Events (Spine.EventData)
///
/// Filters popup results to elements that begin with supplied string.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives).
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
@@ -79,11 +81,63 @@ namespace Spine.Unity {
}
}
+ public class SpineIkConstraint : SpineAttributeBase {
+ ///
+ /// Smart popup menu for Spine IK Constraints (Spine.IkConstraint)
+ ///
+ /// Filters popup results to elements that begin with supplied string.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
+ /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
+ /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives).
+ /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
+ ///
+ public SpineIkConstraint(string startsWith = "", string dataField = "", bool includeNone = true) {
+ this.startsWith = startsWith;
+ this.dataField = dataField;
+ this.includeNone = includeNone;
+ }
+ }
+
+ public class SpinePathConstraint : SpineAttributeBase {
+ ///
+ /// Smart popup menu for Spine Events (Spine.PathConstraint)
+ ///
+ /// Filters popup results to elements that begin with supplied string.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
+ /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
+ /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives).
+ /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
+ ///
+ public SpinePathConstraint(string startsWith = "", string dataField = "", bool includeNone = true) {
+ this.startsWith = startsWith;
+ this.dataField = dataField;
+ this.includeNone = includeNone;
+ }
+ }
+
+ public class SpineTransformConstraint : SpineAttributeBase {
+ ///
+ /// Smart popup menu for Spine Transform Constraints (Spine.TransformConstraint)
+ ///
+ /// Filters popup results to elements that begin with supplied string.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
+ /// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
+ /// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives).
+ /// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
+ ///
+ public SpineTransformConstraint(string startsWith = "", string dataField = "", bool includeNone = true) {
+ this.startsWith = startsWith;
+ this.dataField = dataField;
+ this.includeNone = includeNone;
+ }
+ }
+
public class SpineSkin : SpineAttributeBase {
///
/// Smart popup menu for Spine Skins
///
/// Filters popup results to elements that begin with supplied string.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives)
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
@@ -100,6 +154,7 @@ namespace Spine.Unity {
///
/// Filters popup results to elements that begin with supplied string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives)
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
///
@@ -124,6 +179,8 @@ namespace Spine.Unity {
/// Returns a fully qualified path for an Attachment in the format "Skin/Slot/AttachmentName". This path format is only used by the SpineAttachment helper methods like SpineAttachment.GetAttachment and .GetHierarchy. Do not use full path anywhere else in Spine's system.
/// Filters popup results to exclude attachments that are not children of Skin Placeholders
/// If specified, a locally scoped field with the name supplied by in slotField will be used to limit the popup results to children of a named slot
+ /// If specified, a locally scoped field with the name supplied by in skinField will be used to limit the popup results to entries of the named skin
+ /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives)
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.
@@ -184,6 +241,7 @@ namespace Spine.Unity {
/// Smart popup menu for Spine Bones
///
/// Filters popup results to elements that begin with supplied string.
+ /// /// If true, the dropdown list will include a "none" option which stored as an empty string.
/// If specified, a locally scoped field with the name supplied by in dataField will be used to fill the popup results.
/// Valid types are SkeletonDataAsset and SkeletonRenderer (and derivatives)
/// If left empty and the script the attribute is applied to is derived from Component, GetComponent() will be called as a fallback.