更新,spine和很多优化
This commit is contained in:
+247
@@ -0,0 +1,247 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes License Agreement
|
||||
* Last updated April 5, 2025. Replaces all prior versions.
|
||||
*
|
||||
* Copyright (c) 2013-2025, Esoteric Software LLC
|
||||
*
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
* "Products"), provided that each user of the Products must obtain their own
|
||||
* Spine Editor license and redistribution of the Products in any form must
|
||||
* include this license and copyright notice.
|
||||
*
|
||||
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
using Spine;
|
||||
using Spine.Unity;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Spine.Unity.Examples {
|
||||
|
||||
//[CreateAssetMenu(menuName = "Spine/SkeletonData Modifiers/Animation Match", order = 200)]
|
||||
public class AnimationMatchModifierAsset : SkeletonDataModifierAsset {
|
||||
|
||||
public bool matchAllAnimations = true;
|
||||
|
||||
public override void Apply (SkeletonData skeletonData) {
|
||||
if (matchAllAnimations)
|
||||
AnimationTools.MatchAnimationTimelines(skeletonData.Animations, skeletonData);
|
||||
}
|
||||
|
||||
public static class AnimationTools {
|
||||
|
||||
#region Filler Timelines
|
||||
/// <summary>
|
||||
/// Matches the animation timelines across the given set of animations.
|
||||
/// This allows unkeyed properties to assume setup pose when animations are naively mixed using Animation.Apply.
|
||||
/// </summary>
|
||||
/// <param name="animations">An enumerable collection animations whose timelines will be matched.</param>
|
||||
/// <param name="skeletonData">The SkeletonData where the animations belong.</param>
|
||||
public static void MatchAnimationTimelines (IEnumerable<Spine.Animation> animations, SkeletonData skeletonData) {
|
||||
if (animations == null) return;
|
||||
if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "Timelines can't be matched without a SkeletonData source.");
|
||||
|
||||
// Build a reference collection of timelines to match
|
||||
// and a collection of dummy timelines that can be used to fill-in missing items.
|
||||
Dictionary<string, Timeline> timelineDictionary = new Dictionary<string, Spine.Timeline>();
|
||||
foreach (Animation animation in animations) {
|
||||
foreach (Timeline timeline in animation.Timelines) {
|
||||
if (timeline is EventTimeline) continue;
|
||||
|
||||
foreach (string propertyId in timeline.PropertyIds) {
|
||||
if (!timelineDictionary.ContainsKey(propertyId)) {
|
||||
timelineDictionary.Add(propertyId, GetFillerTimeline(timeline, skeletonData));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<string> idsToMatch = new List<string>(timelineDictionary.Keys);
|
||||
|
||||
// For each animation in the list, check for and add missing timelines.
|
||||
HashSet<string> currentAnimationIDs = new HashSet<string>();
|
||||
foreach (Animation animation in animations) {
|
||||
currentAnimationIDs.Clear();
|
||||
foreach (Timeline timeline in animation.Timelines) {
|
||||
if (timeline is EventTimeline) continue;
|
||||
foreach (string propertyId in timeline.PropertyIds) {
|
||||
currentAnimationIDs.Add(propertyId);
|
||||
}
|
||||
}
|
||||
|
||||
ExposedList<Timeline> animationTimelines = animation.Timelines;
|
||||
foreach (string propertyId in idsToMatch) {
|
||||
if (!currentAnimationIDs.Contains(propertyId))
|
||||
animationTimelines.Add(timelineDictionary[propertyId]);
|
||||
}
|
||||
}
|
||||
|
||||
// These are locals, but sometimes Unity's GC does weird stuff. So let's clean up.
|
||||
timelineDictionary.Clear();
|
||||
timelineDictionary = null;
|
||||
idsToMatch.Clear();
|
||||
idsToMatch = null;
|
||||
currentAnimationIDs.Clear();
|
||||
currentAnimationIDs = null;
|
||||
}
|
||||
|
||||
static Timeline GetFillerTimeline (Timeline timeline, SkeletonData skeletonData) {
|
||||
if (timeline is RotateTimeline)
|
||||
return GetFillerTimeline((RotateTimeline)timeline, skeletonData);
|
||||
if (timeline is TranslateTimeline)
|
||||
return GetFillerTimeline((TranslateTimeline)timeline, skeletonData);
|
||||
if (timeline is ScaleTimeline)
|
||||
return GetFillerTimeline((ScaleTimeline)timeline, skeletonData);
|
||||
if (timeline is ShearTimeline)
|
||||
return GetFillerTimeline((ShearTimeline)timeline, skeletonData);
|
||||
if (timeline is AttachmentTimeline)
|
||||
return GetFillerTimeline((AttachmentTimeline)timeline, skeletonData);
|
||||
if (timeline is RGBATimeline)
|
||||
return GetFillerTimeline((RGBATimeline)timeline, skeletonData);
|
||||
if (timeline is RGBA2Timeline)
|
||||
return GetFillerTimeline((RGBA2Timeline)timeline, skeletonData);
|
||||
if (timeline is DeformTimeline)
|
||||
return GetFillerTimeline((DeformTimeline)timeline, skeletonData);
|
||||
if (timeline is DrawOrderTimeline)
|
||||
return GetFillerTimeline((DrawOrderTimeline)timeline, skeletonData);
|
||||
if (timeline is IkConstraintTimeline)
|
||||
return GetFillerTimeline((IkConstraintTimeline)timeline, skeletonData);
|
||||
if (timeline is TransformConstraintTimeline)
|
||||
return GetFillerTimeline((TransformConstraintTimeline)timeline, skeletonData);
|
||||
if (timeline is PathConstraintPositionTimeline)
|
||||
return GetFillerTimeline((PathConstraintPositionTimeline)timeline, skeletonData);
|
||||
if (timeline is PathConstraintSpacingTimeline)
|
||||
return GetFillerTimeline((PathConstraintSpacingTimeline)timeline, skeletonData);
|
||||
if (timeline is PathConstraintMixTimeline)
|
||||
return GetFillerTimeline((PathConstraintMixTimeline)timeline, skeletonData);
|
||||
return null;
|
||||
}
|
||||
|
||||
static RotateTimeline GetFillerTimeline (RotateTimeline timeline, SkeletonData skeletonData) {
|
||||
RotateTimeline t = new RotateTimeline(1, 0, timeline.BoneIndex);
|
||||
t.SetFrame(0, 0, 0);
|
||||
return t;
|
||||
}
|
||||
|
||||
static TranslateTimeline GetFillerTimeline (TranslateTimeline timeline, SkeletonData skeletonData) {
|
||||
TranslateTimeline t = new TranslateTimeline(1, 0, timeline.BoneIndex);
|
||||
t.SetFrame(0, 0, 0, 0);
|
||||
return t;
|
||||
}
|
||||
|
||||
static ScaleTimeline GetFillerTimeline (ScaleTimeline timeline, SkeletonData skeletonData) {
|
||||
ScaleTimeline t = new ScaleTimeline(1, 0, timeline.BoneIndex);
|
||||
t.SetFrame(0, 0, 0, 0);
|
||||
return t;
|
||||
}
|
||||
|
||||
static ShearTimeline GetFillerTimeline (ShearTimeline timeline, SkeletonData skeletonData) {
|
||||
ShearTimeline t = new ShearTimeline(1, 0, timeline.BoneIndex);
|
||||
t.SetFrame(0, 0, 0, 0);
|
||||
return t;
|
||||
}
|
||||
|
||||
static AttachmentTimeline GetFillerTimeline (AttachmentTimeline timeline, SkeletonData skeletonData) {
|
||||
AttachmentTimeline t = new AttachmentTimeline(1, timeline.SlotIndex);
|
||||
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
|
||||
t.SetFrame(0, 0, slotData.AttachmentName);
|
||||
return t;
|
||||
}
|
||||
|
||||
static RGBATimeline GetFillerTimeline (RGBATimeline timeline, SkeletonData skeletonData) {
|
||||
RGBATimeline t = new RGBATimeline(1, 0, timeline.SlotIndex);
|
||||
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
|
||||
Color color = slotData.GetSetupPose().GetColor();
|
||||
t.SetFrame(0, 0, color.r, color.g, color.b, color.a);
|
||||
return t;
|
||||
}
|
||||
|
||||
static RGBA2Timeline GetFillerTimeline (RGBA2Timeline timeline, SkeletonData skeletonData) {
|
||||
RGBA2Timeline t = new RGBA2Timeline(1, 0, timeline.SlotIndex);
|
||||
SlotData slotData = skeletonData.Slots.Items[t.SlotIndex];
|
||||
var setup = slotData.GetSetupPose();
|
||||
Color color = setup.GetColor();
|
||||
Color? darkColorOptional = setup.GetDarkColor();
|
||||
Color darkColor = darkColorOptional.HasValue ? darkColorOptional.Value : Color.black;
|
||||
t.SetFrame(0, 0, color.r, color.g, color.b, color.a, darkColor.r, darkColor.g, darkColor.b);
|
||||
return t;
|
||||
}
|
||||
|
||||
static DeformTimeline GetFillerTimeline (DeformTimeline timeline, SkeletonData skeletonData) {
|
||||
DeformTimeline t = new DeformTimeline(1, 0, timeline.SlotIndex, timeline.Attachment);
|
||||
if (t.Attachment.IsWeighted()) {
|
||||
t.SetFrame(0, 0, new float[t.Attachment.Vertices.Length]);
|
||||
} else {
|
||||
t.SetFrame(0, 0, t.Attachment.Vertices.Clone() as float[]);
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
static DrawOrderTimeline GetFillerTimeline (DrawOrderTimeline timeline, SkeletonData skeletonData) {
|
||||
DrawOrderTimeline t = new DrawOrderTimeline(1);
|
||||
t.SetFrame(0, 0, null); // null means use setup pose in DrawOrderTimeline.Apply.
|
||||
return t;
|
||||
}
|
||||
|
||||
static IkConstraintTimeline GetFillerTimeline (IkConstraintTimeline timeline, SkeletonData skeletonData) {
|
||||
IkConstraintTimeline t = new IkConstraintTimeline(1, 0, timeline.ConstraintIndex);
|
||||
var ikConstraintData = (IkConstraintData)skeletonData.Constraints.Items[timeline.ConstraintIndex];
|
||||
var setup = ikConstraintData.GetSetupPose();
|
||||
t.SetFrame(0, 0, setup.Mix, setup.Softness, setup.BendDirection, setup.Compress, setup.Stretch);
|
||||
return t;
|
||||
}
|
||||
|
||||
static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) {
|
||||
TransformConstraintTimeline t = new TransformConstraintTimeline(1, 0, timeline.ConstraintIndex);
|
||||
var data = (TransformConstraintData)skeletonData.Constraints.Items[timeline.ConstraintIndex];
|
||||
var setup = data.GetSetupPose();
|
||||
t.SetFrame(0, 0, setup.MixRotate, setup.MixX, setup.MixY, setup.MixScaleX, setup.MixScaleY, setup.MixShearY);
|
||||
return t;
|
||||
}
|
||||
|
||||
static PathConstraintPositionTimeline GetFillerTimeline (PathConstraintPositionTimeline timeline, SkeletonData skeletonData) {
|
||||
PathConstraintPositionTimeline t = new PathConstraintPositionTimeline(1, 0, timeline.ConstraintIndex);
|
||||
var data = (PathConstraintData)skeletonData.Constraints.Items[timeline.ConstraintIndex];
|
||||
var setup = data.GetSetupPose();
|
||||
t.SetFrame(0, 0, setup.Position);
|
||||
return t;
|
||||
}
|
||||
|
||||
static PathConstraintSpacingTimeline GetFillerTimeline (PathConstraintSpacingTimeline timeline, SkeletonData skeletonData) {
|
||||
PathConstraintSpacingTimeline t = new PathConstraintSpacingTimeline(1, 0, timeline.ConstraintIndex);
|
||||
var data = (PathConstraintData)skeletonData.Constraints.Items[timeline.ConstraintIndex];
|
||||
var setup = data.GetSetupPose();
|
||||
t.SetFrame(0, 0, setup.Spacing);
|
||||
return t;
|
||||
}
|
||||
|
||||
static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) {
|
||||
PathConstraintMixTimeline t = new PathConstraintMixTimeline(1, 0, timeline.ConstraintIndex);
|
||||
PathConstraintData data = (PathConstraintData)skeletonData.Constraints.Items[timeline.ConstraintIndex];
|
||||
var setup = data.GetSetupPose();
|
||||
t.SetFrame(0, 0, setup.MixRotate, setup.MixX, setup.MixY);
|
||||
return t;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df7d457928e0f4041a439f9847f72290
|
||||
timeCreated: 1537527074
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
AnimationMatchModifierAsset
|
||||
===========================
|
||||
|
||||
This is a SkeletonDataModifierAsset. Add it to a SkeletonDataAsset to apply its effects when its SkeletonData is loaded.
|
||||
|
||||
AnimationMatchModifierAsset processes animations so that their timelines match. This allows them to function with naive Animation Apply systems such as SkeletonMecanim without the need for autoreset functionality.
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4436c0c78cc5ee469089ed864f4e1ea
|
||||
timeCreated: 1537528259
|
||||
licenseType: Pro
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_PrefabParentObject: {fileID: 0}
|
||||
m_PrefabInternal: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: df7d457928e0f4041a439f9847f72290, type: 3}
|
||||
m_Name: Default Match All Animations
|
||||
m_EditorClassIdentifier:
|
||||
matchAllAnimations: 1
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8623082208cae724e88314ec951691e1
|
||||
timeCreated: 1537527914
|
||||
licenseType: Pro
|
||||
NativeFormatImporter:
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user