diff --git a/CHANGELOG.md b/CHANGELOG.md index d311f2ce1..33ccaf835 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,14 +53,15 @@ * Added `Animation Update` mode (called `UpdateTiming` in code) `In Late Update` for `SkeletonAnimation`, `SkeletonMecanim` and `SkeletonGraphic`. This allows you to update the `SkeletonMecanim` skeleton in the same frame that the Mecanim Animator updated its state, which happens between `Update` and `LateUpdate`. * URP Shaders: Added URP "Blend Mode" shader variants for both URP 3D and URP 2D renderers. They are listed under shader name "Universal Render Pipeline/Spine/Blend Modes/" and "Universal Render Pipeline/2D/Spine/Blend Modes/" respectively. * URP Shaders: Added support for [Tint Black](http://en.esotericsoftware.com/spine-slots#Tint-black) functionality at "Blend Modes" Spine URP shaders (2D and 3D shaders). - * PhysicsConstraints: Skeleton GameObjects now automatically apply Transform translation and rotation to the skeleton's `PhysicsConstraints`. You can disable applying translation or rotation at the Skeleton component Inspector under `Advanced - Physics Constraints` `Transform Translation` and `Transform Rotation`, or by setting the properties `applyTranslationToPhysics` and `applyRotationToPhysics` at the skeleton component via code. + * PhysicsConstraints: Skeleton GameObjects now automatically apply Transform translation and rotation to the skeleton's `PhysicsConstraints`. You can disable applying translation or rotation at the Skeleton component Inspector under `Advanced - Physics Inheritance` by setting `Position` to (0,0)and `Rotation` to 0, or by setting the properties `physicsPositionInheritanceFactor` to `Vector2.zero` and `physicsRotationInheritanceFactor` to `0` at the skeleton component via code. * Added `Physics Constraints` example scene (located in `Spine Examples/Other Examples`) together with `celestial-circus` example skeleton assets. This scene demonstrates Transform movement automatically affecting physics constraints of a skeleton. - * PhysicsConstraints: Skeleton components now allow you to use relative instead of world-space Transform movement (with `applyTranslationToPhysics` and `applyRotationToPhysics`) by assigning a Transform (typically the parent) to the new `Movement relative to` property. Leave this property at `null` (the default) to use world-space Transform movement for physics. - + * PhysicsConstraints: Skeleton components now allow you to use relative instead of world-space Transform movement by assigning a Transform (typically the parent) to the new `Movement relative to` property. Leave this property at `null` (the default) to use world-space Transform movement for physics. + * **Breaking changes** * Changed `SpineShaderWithOutlineGUI` outline related methods from `private` to `protected virtual` to allow for custom shader GUI subclasses to switch to different outline shaders. * Changed `BoneFollower` and `BoneFollowerGraphic` methods `LateUpdate` and `Initialize` to `virtual` to allow easier overriding for e.g. positional offset in custom subclasses. * `MeshGenerator` received a new optimization option to avoid rendering fully transparent attachments at slot alpha 0 by default. Comment out `#define SLOT_ALPHA_DISABLES_ATTACHMENT` in `MeshGenerator.cs` to revert to previous behaviour. You may only need this option disabled when utilizing a custom shader which uses vertex color alpha for purposes other than transparency. + * PhysicsConstraints: bool properties `ApplyTranslationToPhysics` and `ApplyRotationToPhysics` were changed to `Vector2 PhysicsPositionInheritanceFactor` and `float PhysicsRotationInheritanceFactor` to allow the Transform movement the be scaled by a factor before being applied to the skeleton. You can set the properties to `Vector2.zero` and `0` respectively to disable applying any Transform movement at all. The `Advanced` Inspector section `Physics Constraints` was renamed to `Physics Inheritance`, the properties in the section are now called `Position` and `Rotation`. * **Changes of default values** diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs index 137cb1b47..86feac1ff 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonGraphicInspector.cs @@ -62,7 +62,7 @@ namespace Spine.Unity.Editor { SerializedProperty skeletonDataAsset, initialSkinName; SerializedProperty startingAnimation, startingLoop, timeScale, freeze, updateTiming, updateWhenInvisible, unscaledTime, tintBlack, layoutScaleMode, editReferenceRect; - SerializedProperty applyTranslationToPhysics, applyRotationToPhysics, physicsMovementRelativeTo; + SerializedProperty physicsPositionInheritanceFactor, physicsRotationInheritanceFactor, physicsMovementRelativeTo; SerializedProperty initialFlipX, initialFlipY; SerializedProperty meshGeneratorSettings; SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots, @@ -73,10 +73,20 @@ namespace Spine.Unity.Editor { "If enabled, AnimationState uses unscaled game time (Time.unscaledDeltaTime), " + "running animations independent of e.g. game pause (Time.timeScale). " + "Instance SkeletonAnimation.timeScale will still be applied."); - readonly GUIContent ApplyTranslationToPhysicsLabel = new GUIContent("Transform Translation", - "When enabled, the GameObject Transform translation movement is applied to PhysicsConstraints of the skeleton."); - readonly GUIContent ApplyRotationToPhysicsLabel = new GUIContent("Transform Rotation", - "When enabled, the GameObject Transform rotation movement is applied to PhysicsConstraints of the skeleton."); + readonly GUIContent PhysicsPositionInheritanceFactorLabel = new GUIContent("Position", + "When set to non-zero, Transform position movement in X and Y direction is applied to skeleton " + + "PhysicsConstraints, multiplied by these " + + "\nX and Y scale factors to the right. Typical values are " + + "\n(1,1) to apply XY movement normally, " + + "\n(2,2) to apply movement with double intensity, " + + "\n(1,0) to apply only horizontal movement, or" + + "\n(0,0) to not apply any Transform position movement at all."); + readonly GUIContent PhysicsRotationInheritanceFactorLabel = new GUIContent("Rotation", + "When set to non-zero, Transform rotation movement is applied to skeleton PhysicsConstraints, " + + "multiplied by this scale factor to the right. Typical values are " + + "\n1 to apply movement normally, " + + "\n2 to apply movement with double intensity, or " + + "\n0 to not apply any Transform rotation movement at all."); readonly GUIContent PhysicsMovementRelativeToLabel = new GUIContent("Movement relative to", "Reference transform relative to which physics movement will be calculated, or null to use world location."); @@ -143,8 +153,8 @@ namespace Spine.Unity.Editor { updateWhenInvisible = so.FindProperty("updateWhenInvisible"); layoutScaleMode = so.FindProperty("layoutScaleMode"); editReferenceRect = so.FindProperty("editReferenceRect"); - applyTranslationToPhysics = so.FindProperty("applyTranslationToPhysics"); - applyRotationToPhysics = so.FindProperty("applyRotationToPhysics"); + physicsPositionInheritanceFactor = so.FindProperty("physicsPositionInheritanceFactor"); + physicsRotationInheritanceFactor = so.FindProperty("physicsRotationInheritanceFactor"); physicsMovementRelativeTo = so.FindProperty("physicsMovementRelativeTo"); meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings"); @@ -320,9 +330,16 @@ namespace Spine.Unity.Editor { EditorGUILayout.Space(); using (new SpineInspectorUtility.LabelWidthScope()) { - EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Physics Constraints", SpineEditorUtilities.Icons.constraintPhysics), EditorStyles.boldLabel); - EditorGUILayout.PropertyField(applyTranslationToPhysics, ApplyTranslationToPhysicsLabel); - EditorGUILayout.PropertyField(applyRotationToPhysics, ApplyRotationToPhysicsLabel); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Physics Inheritance", SpineEditorUtilities.Icons.constraintPhysics), EditorStyles.boldLabel); + + using (new GUILayout.HorizontalScope()) { + EditorGUILayout.LabelField(PhysicsPositionInheritanceFactorLabel, GUILayout.Width(EditorGUIUtility.labelWidth)); + int savedIndentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUILayout.PropertyField(physicsPositionInheritanceFactor, GUIContent.none, GUILayout.MinWidth(60)); + EditorGUI.indentLevel = savedIndentLevel; + } + EditorGUILayout.PropertyField(physicsRotationInheritanceFactor, PhysicsRotationInheritanceFactorLabel); EditorGUILayout.PropertyField(physicsMovementRelativeTo, PhysicsMovementRelativeToLabel); } } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs index 91026d36b..e69c4bf16 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs @@ -68,7 +68,7 @@ namespace Spine.Unity.Editor { protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings protected SerializedProperty maskInteraction; protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside; - protected SerializedProperty applyTranslationToPhysics, applyRotationToPhysics, physicsMovementRelativeTo; + protected SerializedProperty physicsPositionInheritanceFactor, physicsRotationInheritanceFactor, physicsMovementRelativeTo; protected SpineInspectorUtility.SerializedSortingProperties sortingProperties; protected bool wasInitParameterChanged = false; protected bool requireRepaint = false; @@ -88,10 +88,20 @@ namespace Spine.Unity.Editor { protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel; protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel; - readonly GUIContent ApplyTranslationToPhysicsLabel = new GUIContent("Transform Translation", - "When enabled, the GameObject Transform translation movement is applied to PhysicsConstraints of the skeleton."); - readonly GUIContent ApplyRotationToPhysicsLabel = new GUIContent("Transform Rotation", - "When enabled, the GameObject Transform rotation movement is applied to PhysicsConstraints of the skeleton."); + readonly GUIContent PhysicsPositionInheritanceFactorLabel = new GUIContent("Position", + "When set to non-zero, Transform position movement in X and Y direction is applied to skeleton " + + "PhysicsConstraints, multiplied by these " + + "\nX and Y scale factors to the right. Typical values are " + + "\n(1,1) to apply XY movement normally, " + + "\n(2,2) to apply movement with double intensity, " + + "\n(1,0) to apply only horizontal movement, or" + + "\n(0,0) to not apply any Transform position movement at all."); + readonly GUIContent PhysicsRotationInheritanceFactorLabel = new GUIContent("Rotation", + "When set to non-zero, Transform rotation movement is applied to skeleton PhysicsConstraints, " + + "multiplied by this scale factor to the right. Typical values are " + + "\n1 to apply movement normally, " + + "\n2 to apply movement with double intensity, or " + + "\n0 to not apply any Transform rotation movement at all."); readonly GUIContent PhysicsMovementRelativeToLabel = new GUIContent("Movement relative to", "Reference transform relative to which physics movement will be calculated, or null to use world location."); @@ -169,8 +179,8 @@ namespace Spine.Unity.Editor { maskMaterialsNone = so.FindProperty("maskMaterials.materialsMaskDisabled"); maskMaterialsInside = so.FindProperty("maskMaterials.materialsInsideMask"); maskMaterialsOutside = so.FindProperty("maskMaterials.materialsOutsideMask"); - applyTranslationToPhysics = so.FindProperty("applyTranslationToPhysics"); - applyRotationToPhysics = so.FindProperty("applyRotationToPhysics"); + physicsPositionInheritanceFactor = so.FindProperty("physicsPositionInheritanceFactor"); + physicsRotationInheritanceFactor = so.FindProperty("physicsRotationInheritanceFactor"); physicsMovementRelativeTo = so.FindProperty("physicsMovementRelativeTo"); separatorSlotNames = so.FindProperty("separatorSlotNames"); @@ -418,9 +428,16 @@ namespace Spine.Unity.Editor { } #endif using (new SpineInspectorUtility.LabelWidthScope()) { - EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Physics Constraints", SpineEditorUtilities.Icons.constraintPhysics), EditorStyles.boldLabel); - EditorGUILayout.PropertyField(applyTranslationToPhysics, ApplyTranslationToPhysicsLabel); - EditorGUILayout.PropertyField(applyRotationToPhysics, ApplyRotationToPhysicsLabel); + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Physics Inheritance", SpineEditorUtilities.Icons.constraintPhysics), EditorStyles.boldLabel); + + using (new GUILayout.HorizontalScope()) { + EditorGUILayout.LabelField(PhysicsPositionInheritanceFactorLabel, GUILayout.Width(EditorGUIUtility.labelWidth)); + int savedIndentLevel = EditorGUI.indentLevel; + EditorGUI.indentLevel = 0; + EditorGUILayout.PropertyField(physicsPositionInheritanceFactor, GUIContent.none, GUILayout.MinWidth(60)); + EditorGUI.indentLevel = savedIndentLevel; + } + EditorGUILayout.PropertyField(physicsRotationInheritanceFactor, PhysicsRotationInheritanceFactorLabel); EditorGUILayout.PropertyField(physicsMovementRelativeTo, PhysicsMovementRelativeToLabel); } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs index 60e5edbc5..9faaddafb 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs @@ -391,21 +391,22 @@ namespace Spine.Unity { public virtual void ApplyTransformMovementToPhysics () { if (Application.isPlaying) { - if (applyTranslationToPhysics) { + if (physicsPositionInheritanceFactor != Vector2.zero) { Vector2 position = GetPhysicsTransformPosition(); Vector2 positionDelta = (position - lastPosition) / meshScale; if (physicsMovementRelativeTo != null) { positionDelta.x *= physicsMovementRelativeTo.lossyScale.x; positionDelta.y *= physicsMovementRelativeTo.lossyScale.y; } - positionDelta.x /= transform.lossyScale.x; - positionDelta.y /= transform.lossyScale.y; + positionDelta.x *= physicsPositionInheritanceFactor.x / transform.lossyScale.x; + positionDelta.y *= physicsPositionInheritanceFactor.y / transform.lossyScale.y; + skeleton.PhysicsTranslate(positionDelta.x, positionDelta.y); lastPosition = position; } - if (applyRotationToPhysics) { + if (physicsRotationInheritanceFactor != 0f) { float rotation = GetPhysicsTransformRotation(); - skeleton.PhysicsRotate(0, 0, rotation - lastRotation); + skeleton.PhysicsRotate(0, 0, physicsRotationInheritanceFactor * (rotation - lastRotation)); lastRotation = rotation; } } @@ -567,10 +568,10 @@ namespace Spine.Unity { } } - /// When enabled, Transform translation is applied to skeleton PhysicsConstraints. - [SerializeField] protected bool applyTranslationToPhysics = true; - /// When enabled, Transform rotation is applied to skeleton PhysicsConstraints. - [SerializeField] protected bool applyRotationToPhysics = true; + /// + [SerializeField] protected Vector2 physicsPositionInheritanceFactor = Vector2.one; + /// + [SerializeField] protected float physicsRotationInheritanceFactor = 1.0f; /// Reference transform relative to which physics movement will be calculated, or null to use world location. [SerializeField] protected Transform physicsMovementRelativeTo = null; @@ -579,25 +580,33 @@ namespace Spine.Unity { /// Used for applying Transform rotation to skeleton PhysicsConstraints. protected float lastRotation; - /// When enabled, Transform translation is applied to skeleton PhysicsConstraints. - public bool ApplyTranslationToPhysics { + /// When set to non-zero, Transform position movement in X and Y direction + /// is applied to skeleton PhysicsConstraints, multiplied by this scale factor. + /// Typical values are Vector2.one to apply XY movement 1:1, + /// Vector2(2f, 2f) to apply movement with double intensity, + /// Vector2(1f, 0f) to apply only horizontal movement, or + /// Vector2.zero to not apply any Transform position movement at all. + public Vector2 PhysicsPositionInheritanceFactor { get { - return applyTranslationToPhysics; + return physicsPositionInheritanceFactor; } set { - if (value && !applyTranslationToPhysics) ResetLastPosition(); - applyTranslationToPhysics = value; + if (physicsPositionInheritanceFactor == Vector2.zero && value != Vector2.zero) ResetLastPosition(); + physicsPositionInheritanceFactor = value; } } - /// When enabled, Transform rotation is applied to skeleton PhysicsConstraints. - public bool ApplyRotationToPhysics { + /// When set to non-zero, Transform rotation movement is applied to skeleton PhysicsConstraints, + /// multiplied by this scale factor. Typical values are 1 to apply movement 1:1, + /// 2 to apply movement with double intensity, or + /// 0 to not apply any Transform rotation movement at all. + public float PhysicsRotationInheritanceFactor { get { - return applyRotationToPhysics; + return physicsRotationInheritanceFactor; } set { - if (value && !applyRotationToPhysics) ResetLastRotation(); - applyRotationToPhysics = value; + if (physicsRotationInheritanceFactor == 0f && value != 0f) ResetLastRotation(); + physicsRotationInheritanceFactor = value; } } @@ -608,8 +617,8 @@ namespace Spine.Unity { } set { physicsMovementRelativeTo = value; - if (applyTranslationToPhysics) ResetLastPosition(); - if (applyRotationToPhysics) ResetLastRotation(); + if (physicsPositionInheritanceFactor != Vector2.zero) ResetLastPosition(); + if (physicsRotationInheritanceFactor != 0f) ResetLastRotation(); } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 41ee7ecd3..0fe7adae3 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -289,10 +289,10 @@ namespace Spine.Unity { #endregion #region Physics - /// When enabled, Transform translation is applied to skeleton PhysicsConstraints. - [SerializeField] protected bool applyTranslationToPhysics = true; - /// When enabled, Transform rotation is applied to skeleton PhysicsConstraints. - [SerializeField] protected bool applyRotationToPhysics = true; + /// + [SerializeField] protected Vector2 physicsPositionInheritanceFactor = Vector2.one; + /// + [SerializeField] protected float physicsRotationInheritanceFactor = 1.0f; /// Reference transform relative to which physics movement will be calculated, or null to use world location. [SerializeField] protected Transform physicsMovementRelativeTo = null; @@ -301,25 +301,33 @@ namespace Spine.Unity { /// Used for applying Transform rotation to skeleton PhysicsConstraints. protected float lastRotation; - /// When enabled, Transform translation is applied to skeleton PhysicsConstraints. - public bool ApplyTranslationToPhysics { + /// When set to non-zero, Transform position movement in X and Y direction + /// is applied to skeleton PhysicsConstraints, multiplied by this scale factor. + /// Typical values are Vector2.one to apply XY movement 1:1, + /// Vector2(2f, 2f) to apply movement with double intensity, + /// Vector2(1f, 0f) to apply only horizontal movement, or + /// Vector2.zero to not apply any Transform position movement at all. + public Vector2 PhysicsPositionInheritanceFactor { get { - return applyTranslationToPhysics; + return physicsPositionInheritanceFactor; } set { - if (value && !applyTranslationToPhysics) ResetLastPosition(); - applyTranslationToPhysics = value; + if (physicsPositionInheritanceFactor == Vector2.zero && value != Vector2.zero) ResetLastPosition(); + physicsPositionInheritanceFactor = value; } } - /// When enabled, Transform rotation is applied to skeleton PhysicsConstraints. - public bool ApplyRotationToPhysics { + /// When set to non-zero, Transform rotation movement is applied to skeleton PhysicsConstraints, + /// multiplied by this scale factor. Typical values are 1 to apply movement 1:1, + /// 2 to apply movement with double intensity, or + /// 0 to not apply any Transform rotation movement at all. + public float PhysicsRotationInheritanceFactor { get { - return applyRotationToPhysics; + return physicsRotationInheritanceFactor; } set { - if (value && !applyRotationToPhysics) ResetLastRotation(); - applyRotationToPhysics = value; + if (physicsRotationInheritanceFactor == 0f && value != 0f) ResetLastRotation(); + physicsRotationInheritanceFactor = value; } } @@ -330,8 +338,8 @@ namespace Spine.Unity { } set { physicsMovementRelativeTo = value; - if (applyTranslationToPhysics) ResetLastPosition(); - if (applyRotationToPhysics) ResetLastRotation(); + if (physicsPositionInheritanceFactor != Vector2.zero) ResetLastPosition(); + if (physicsRotationInheritanceFactor != 0f) ResetLastRotation(); } } @@ -504,21 +512,21 @@ namespace Spine.Unity { public virtual void ApplyTransformMovementToPhysics () { if (Application.isPlaying) { - if (applyTranslationToPhysics) { + if (physicsPositionInheritanceFactor != Vector2.zero) { Vector2 position = GetPhysicsTransformPosition(); Vector2 positionDelta = position - lastPosition; if (physicsMovementRelativeTo != null) { positionDelta.x *= physicsMovementRelativeTo.lossyScale.x; positionDelta.y *= physicsMovementRelativeTo.lossyScale.y; } - positionDelta.x /= transform.lossyScale.x; - positionDelta.y /= transform.lossyScale.y; + positionDelta.x *= physicsPositionInheritanceFactor.x / transform.lossyScale.x; + positionDelta.y *= physicsPositionInheritanceFactor.y / transform.lossyScale.y; skeleton.PhysicsTranslate(positionDelta.x, positionDelta.y); lastPosition = position; } - if (applyRotationToPhysics) { + if (physicsRotationInheritanceFactor != 0f) { float rotation = GetPhysicsTransformRotation(); - skeleton.PhysicsRotate(0, 0, rotation - lastRotation); + skeleton.PhysicsRotate(0, 0, physicsRotationInheritanceFactor * (rotation - lastRotation)); lastRotation = rotation; } }