Merge pull request #8 from EsotericSoftware/master

Merging with official runtime.
This commit is contained in:
John 2015-12-19 15:24:36 +08:00
commit 55136345ae
11 changed files with 207 additions and 107 deletions

View File

@ -86,7 +86,13 @@ namespace Spine {
using (var input = new BufferedStream(Microsoft.Xna.Framework.TitleContainer.OpenStream(path)))
{
#else
using (var input = new BufferedStream(new FileStream(path, FileMode.Open))) {
#if UNITY_WP8 || UNITY_WP8_1
using (var input = new FileStream(path, FileMode.Open))
{
#else
using (var input = new BufferedStream(new FileStream(path, FileMode.Open)))
{
#endif
#endif
SkeletonData skeletonData = ReadSkeletonData(input);
skeletonData.name = Path.GetFileNameWithoutExtension(path);

View File

@ -18,7 +18,11 @@ public class RaggedySpineboy : MonoBehaviour {
void AddRigidbody () {
var rb = gameObject.AddComponent<Rigidbody2D>();
#if UNITY_5_1
rb.freezeRotation = true;
#else
rb.fixedAngle = true;
#endif
naturalCollider.enabled = true;
}

View File

@ -0,0 +1,21 @@
using UnityEngine;
namespace Spine {
public static class AssetDatabaseAvailabilityDetector {
const string MARKER_RESOURCE_NAME = "SpineAssetDatabaseMarker";
private static bool _isMarkerLoaded;
public static bool IsAssetDatabaseAvailable (bool forceCheck = false) {
if (!forceCheck && _isMarkerLoaded)
return true;
TextAsset markerTextAsset = Resources.Load<TextAsset>(MARKER_RESOURCE_NAME);
_isMarkerLoaded = markerTextAsset != null;
if (markerTextAsset != null) {
Resources.UnloadAsset(markerTextAsset);
}
return _isMarkerLoaded;
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 25086cd81e3158b439761b73d7366c47
timeCreated: 1444587791
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 24903fdac57ee784b9597fcb751ec22f
folderAsset: yes
timeCreated: 1444565388
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1 @@
DO NOT MOVE OR DELETE THIS FILE

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 57281c00bdd90ad4392f811f2b9f0da1
timeCreated: 1444565392
licenseType: Pro
TextScriptImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -149,6 +149,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
public static string editorPath = "";
public static string editorGUIPath = "";
static HashSet<string> assetsImportedInWrongState;
static Dictionary<int, GameObject> skeletonRendererTable;
static Dictionary<int, SkeletonUtilityBone> skeletonUtilityBoneTable;
static Dictionary<int, BoundingBoxFollower> boundingBoxFollowerTable;
@ -173,6 +174,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
Icons.Initialize();
assetsImportedInWrongState = new HashSet<string>();
skeletonRendererTable = new Dictionary<int, GameObject>();
skeletonUtilityBoneTable = new Dictionary<int, SkeletonUtilityBone>();
boundingBoxFollowerTable = new Dictionary<int, BoundingBoxFollower>();
@ -254,8 +256,34 @@ public class SpineEditorUtilities : AssetPostprocessor {
}
static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) {
ImportSpineContent(imported, false);
if (imported.Length == 0)
return;
// In case user used "Assets -> Reimport All", during the import process,
// asset database is not initialized until some point. During that period,
// all attempts to load any assets using API (i.e. AssetDatabase.LoadAssetAtPath)
// will return null, and as result, assets won't be loaded even if they actually exists,
// which may lead to numerous importing errors.
// This situation also happens if Library folder is deleted from the project, which is a pretty
// common case, since when using version control systems, the Library folder must be excluded.
//
// So to avoid this, in case asset database is not available, we delay loading the assets
// until next time.
//
// Unity *always* reimports some internal assets after the process is done, so this method
// is always called once again in a state when asset database is available.
//
// Checking whether AssetDatabase is initialized is done by attempting to load
// a known "marker" asset that should always be available. Failing to load this asset
// means that AssetDatabase is not initialized.
assetsImportedInWrongState.UnionWith(imported);
if (AssetDatabaseAvailabilityDetector.IsAssetDatabaseAvailable()) {
string[] combinedAssets = assetsImportedInWrongState.ToArray();
assetsImportedInWrongState.Clear();
ImportSpineContent(combinedAssets);
}
}
public static void ImportSpineContent (string[] imported, bool reimport = false) {
List<string> atlasPaths = new List<string>();
List<string> imagePaths = new List<string>();
@ -408,14 +436,34 @@ public class SpineEditorUtilities : AssetPostprocessor {
skeletonDataAsset.Reset();
string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset));
string lastHash = EditorPrefs.GetString(guid + "_hash");
if (lastHash != skeletonDataAsset.GetSkeletonData(true).Hash) {
string lastHash = EditorPrefs.GetString(guid + "_hash");
// For some weird reason sometimes Unity loses the internal Object pointer,
// and as a result, all comparisons with null returns true.
// But the C# wrapper is still alive, so we can "restore" the object
// by reloading it from its Instance ID.
AtlasAsset[] skeletonDataAtlasAssets = skeletonDataAsset.atlasAssets;
if (skeletonDataAtlasAssets != null) {
for (int i = 0; i < skeletonDataAtlasAssets.Length; i++) {
if (!ReferenceEquals(null, skeletonDataAtlasAssets[i]) &&
skeletonDataAtlasAssets[i].Equals(null) &&
skeletonDataAtlasAssets[i].GetInstanceID() != 0
) {
skeletonDataAtlasAssets[i] = EditorUtility.InstanceIDToObject(skeletonDataAtlasAssets[i].GetInstanceID()) as AtlasAsset;
}
}
}
SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true);
string currentHash = skeletonData != null ? skeletonData.Hash : null;
if (currentHash == null || lastHash != currentHash) {
//do any upkeep on synchronized assets
UpdateMecanimClips(skeletonDataAsset);
}
EditorPrefs.SetString(guid + "_hash", skeletonDataAsset.GetSkeletonData(true).Hash);
if (currentHash != null) {
EditorPrefs.SetString(guid + "_hash", currentHash);
}
}
}
}

View File

@ -102,7 +102,8 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
if (mode == MixMode.AlwaysMix) {
//always use Mix instead of Applying the first non-zero weighted clip
foreach (var info in clipInfo) {
for (int c = 0; c < clipInfo.Length; c++) {
var info = clipInfo[c];
float weight = info.weight * layerWeight;
if (weight == 0)
continue;
@ -111,13 +112,16 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight);
}
foreach (var info in nextClipInfo) {
float weight = info.weight * layerWeight;
if (weight == 0)
continue;
if (nextStateInfo.fullPathHash != 0) {
for (int c = 0; c < nextClipInfo.Length; c++) {
var info = nextClipInfo[c];
float weight = info.weight * layerWeight;
if (weight == 0)
continue;
float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
}
}
} else if (mode >= MixMode.MixNext) {
//apply first non-zero weighted clip
@ -147,8 +151,22 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
c = 0;
//apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
if (mode == MixMode.SpineStyle) {
if (nextStateInfo.fullPathHash != 0) {
//apply next clip directly instead of mixing (ie: no crossfade, ignores mecanim transition weights)
if (mode == MixMode.SpineStyle) {
for (; c < nextClipInfo.Length; c++) {
var info = nextClipInfo[c];
float weight = info.weight * layerWeight;
if (weight == 0)
continue;
float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[GetAnimationClipNameHashCode(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null);
break;
}
}
//mix the rest
for (; c < nextClipInfo.Length; c++) {
var info = nextClipInfo[c];
float weight = info.weight * layerWeight;
@ -156,21 +174,9 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[GetAnimationClipNameHashCode(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null);
break;
animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
}
}
//mix the rest
for (; c < nextClipInfo.Length; c++) {
var info = nextClipInfo[c];
float weight = info.weight * layerWeight;
if (weight == 0)
continue;
float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
}
}
}

View File

@ -71,7 +71,7 @@ public class SkeletonRenderer : MonoBehaviour {
private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
private LastState lastState = new LastState();
private MeshState meshState = new MeshState();
public virtual void Reset () {
if (meshFilter != null)
@ -94,7 +94,7 @@ public class SkeletonRenderer : MonoBehaviour {
DestroyImmediate(mesh2);
}
lastState = new LastState();
meshState = new MeshState();
mesh1 = null;
mesh2 = null;
vertices = null;
@ -193,15 +193,11 @@ public class SkeletonRenderer : MonoBehaviour {
bool renderMeshes = this.renderMeshes;
// Clear last state of attachments and submeshes
ExposedList<int> attachmentsTriangleCountTemp = lastState.attachmentsTriangleCountTemp;
attachmentsTriangleCountTemp.GrowIfNeeded(drawOrderCount);
attachmentsTriangleCountTemp.Count = drawOrderCount;
ExposedList<bool> attachmentsFlipStateTemp = lastState.attachmentsFlipStateTemp;
attachmentsFlipStateTemp.GrowIfNeeded(drawOrderCount);
attachmentsFlipStateTemp.Count = drawOrderCount;
MeshState.SingleMeshState stateTemp = meshState.stateTemp;
stateTemp.attachments.Clear(true);
stateTemp.UpdateDrawOrderCount(drawOrderCount);
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsTemp = lastState.addSubmeshArgumentsTemp;
addSubmeshArgumentsTemp.Clear(false);
stateTemp.addSubmeshArguments.Clear(false);
for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder.Items[i];
Bone bone = slot.bone;
@ -214,9 +210,9 @@ public class SkeletonRenderer : MonoBehaviour {
bool worldScaleIsSameSigns = (worldScaleXIsPositive && worldScaleYIsPositive) ||
(!worldScaleXIsPositive && !worldScaleYIsPositive);
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns);
attachmentsFlipStateTemp.Items[i] = flip;
stateTemp.attachmentsFlipState.Items[i] = flip;
attachmentsTriangleCountTemp.Items[i] = -1;
stateTemp.attachments.Items[i] = attachment;
RegionAttachment regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) {
rendererObject = regionAttachment.RendererObject;
@ -249,8 +245,8 @@ public class SkeletonRenderer : MonoBehaviour {
#endif
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
addSubmeshArgumentsTemp.Add(
new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false)
stateTemp.addSubmeshArguments.Add(
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false)
);
submeshTriangleCount = 0;
submeshFirstVertex = vertexCount;
@ -260,18 +256,16 @@ public class SkeletonRenderer : MonoBehaviour {
submeshTriangleCount += attachmentTriangleCount;
vertexCount += attachmentVertexCount;
attachmentsTriangleCountTemp.Items[i] = attachmentTriangleCount;
}
addSubmeshArgumentsTemp.Add(
new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
stateTemp.addSubmeshArguments.Add(
new MeshState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
);
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(attachmentsTriangleCountTemp, attachmentsFlipStateTemp, addSubmeshArgumentsTemp);
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(stateTemp.attachments, stateTemp.attachmentsFlipState, stateTemp.addSubmeshArguments);
if (mustUpdateMeshStructure) {
submeshMaterials.Clear();
for (int i = 0, n = addSubmeshArgumentsTemp.Count; i < n; i++) {
LastState.AddSubmeshArguments arguments = addSubmeshArgumentsTemp.Items[i];
for (int i = 0, n = stateTemp.addSubmeshArguments.Count; i < n; i++) {
MeshState.AddSubmeshArguments arguments = stateTemp.addSubmeshArguments.Items[i];
AddSubmesh(
arguments.material,
arguments.startSlot,
@ -279,7 +273,7 @@ public class SkeletonRenderer : MonoBehaviour {
arguments.triangleCount,
arguments.firstVertex,
arguments.lastSubmesh,
attachmentsFlipStateTemp
stateTemp.attachmentsFlipState
);
}
@ -305,10 +299,10 @@ public class SkeletonRenderer : MonoBehaviour {
} else {
// Too many vertices, zero the extra.
Vector3 zero = Vector3.zero;
for (int i = vertexCount, n = lastState.vertexCount; i < n; i++)
for (int i = vertexCount, n = meshState.vertexCount; i < n; i++)
vertices[i] = zero;
}
lastState.vertexCount = vertexCount;
meshState.vertexCount = vertexCount;
// Setup mesh.
float zSpacing = this.zSpacing;
@ -534,32 +528,21 @@ public class SkeletonRenderer : MonoBehaviour {
}
// Update previous state
ExposedList<int> attachmentsTriangleCountCurrentMesh;
ExposedList<bool> attachmentsFlipStateCurrentMesh;
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh;
if (useMesh1) {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1;
lastState.immutableTrianglesMesh1 = immutableTriangles;
} else {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2;
lastState.immutableTrianglesMesh2 = immutableTriangles;
}
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
currentMeshState.immutableTriangles = immutableTriangles;
attachmentsTriangleCountCurrentMesh.GrowIfNeeded(attachmentsTriangleCountTemp.Capacity);
attachmentsTriangleCountCurrentMesh.Count = attachmentsTriangleCountTemp.Count;
attachmentsTriangleCountTemp.CopyTo(attachmentsTriangleCountCurrentMesh.Items, 0);
currentMeshState.attachments.Clear(true);
currentMeshState.attachments.GrowIfNeeded(stateTemp.attachments.Capacity);
currentMeshState.attachments.Count = stateTemp.attachments.Count;
stateTemp.attachments.CopyTo(currentMeshState.attachments.Items);
attachmentsFlipStateCurrentMesh.GrowIfNeeded(attachmentsFlipStateTemp.Capacity);
attachmentsFlipStateCurrentMesh.Count = attachmentsFlipStateTemp.Count;
attachmentsFlipStateTemp.CopyTo(attachmentsFlipStateCurrentMesh.Items, 0);
currentMeshState.attachmentsFlipState.GrowIfNeeded(stateTemp.attachmentsFlipState.Capacity);
currentMeshState.attachmentsFlipState.Count = stateTemp.attachmentsFlipState.Count;
stateTemp.attachmentsFlipState.CopyTo(currentMeshState.attachmentsFlipState.Items);
addSubmeshArgumentsCurrentMesh.GrowIfNeeded(addSubmeshArgumentsTemp.Count);
addSubmeshArgumentsCurrentMesh.Count = addSubmeshArgumentsTemp.Count;
addSubmeshArgumentsTemp.CopyTo(addSubmeshArgumentsCurrentMesh.Items);
currentMeshState.addSubmeshArguments.GrowIfNeeded(stateTemp.addSubmeshArguments.Capacity);
currentMeshState.addSubmeshArguments.Count = stateTemp.addSubmeshArguments.Count;
stateTemp.addSubmeshArguments.CopyTo(currentMeshState.addSubmeshArguments.Items);
if (submeshRenderers.Length > 0) {
for (int i = 0; i < submeshRenderers.Length; i++) {
@ -575,39 +558,33 @@ public class SkeletonRenderer : MonoBehaviour {
useMesh1 = !useMesh1;
}
private bool CheckIfMustUpdateMeshStructure (ExposedList<int> attachmentsTriangleCountTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
private bool CheckIfMustUpdateMeshStructure (ExposedList<Attachment> attachmentsTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
#if UNITY_EDITOR
if (!Application.isPlaying)
return true;
#endif
// Check if any mesh settings were changed
bool mustUpdateMeshStructure =
immutableTriangles != (useMesh1 ? lastState.immutableTrianglesMesh1 : lastState.immutableTrianglesMesh2);
#if UNITY_EDITOR
mustUpdateMeshStructure |= !Application.isPlaying;
#endif
immutableTriangles != (useMesh1 ? meshState.stateMesh1.immutableTriangles : meshState.stateMesh2.immutableTriangles);
if (mustUpdateMeshStructure)
return true;
// Check if any attachments were enabled/disabled
// or submesh structures has changed
ExposedList<int> attachmentsTriangleCountCurrentMesh;
ExposedList<bool> attachmentsFlipStateCurrentMesh;
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh;
if (useMesh1) {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1;
} else {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2;
}
MeshState.SingleMeshState currentMeshState = useMesh1 ? meshState.stateMesh1 : meshState.stateMesh2;
ExposedList<Attachment> attachmentsCurrentMesh = currentMeshState.attachments;
ExposedList<MeshState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh = currentMeshState.addSubmeshArguments;
ExposedList<bool> attachmentsFlipStateCurrentMesh = currentMeshState.attachmentsFlipState;
// Check attachments
int attachmentCount = attachmentsTriangleCountTemp.Count;
if (attachmentsTriangleCountCurrentMesh.Count != attachmentCount)
int attachmentCount = attachmentsTemp.Count;
if (attachmentsCurrentMesh.Count != attachmentCount)
return true;
for (int i = 0; i < attachmentCount; i++) {
if (attachmentsTriangleCountCurrentMesh.Items[i] != attachmentsTriangleCountTemp.Items[i])
if (attachmentsCurrentMesh.Items[i] != attachmentsTemp.Items[i])
return true;
}
@ -749,19 +726,26 @@ public class SkeletonRenderer : MonoBehaviour {
}
#endif
private class LastState {
public bool immutableTrianglesMesh1;
public bool immutableTrianglesMesh2;
private class MeshState {
public int vertexCount;
public readonly ExposedList<bool> attachmentsFlipStateTemp = new ExposedList<bool>();
public readonly ExposedList<bool> attachmentsFlipStateMesh1 = new ExposedList<bool>();
public readonly ExposedList<bool> attachmentsFlipStateMesh2 = new ExposedList<bool>();
public readonly ExposedList<int> attachmentsTriangleCountTemp = new ExposedList<int>();
public readonly ExposedList<int> attachmentsTriangleCountMesh1 = new ExposedList<int>();
public readonly ExposedList<int> attachmentsTriangleCountMesh2 = new ExposedList<int>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsTemp = new ExposedList<AddSubmeshArguments>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsMesh1 = new ExposedList<AddSubmeshArguments>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsMesh2 = new ExposedList<AddSubmeshArguments>();
public readonly SingleMeshState stateTemp = new SingleMeshState();
public readonly SingleMeshState stateMesh1 = new SingleMeshState();
public readonly SingleMeshState stateMesh2 = new SingleMeshState();
public class SingleMeshState {
public bool immutableTriangles;
public readonly ExposedList<Attachment> attachments = new ExposedList<Attachment>();
public readonly ExposedList<bool> attachmentsFlipState = new ExposedList<bool>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArguments = new ExposedList<AddSubmeshArguments>();
public void UpdateDrawOrderCount(int drawOrderCount) {
attachmentsFlipState.GrowIfNeeded(drawOrderCount);
attachmentsFlipState.Count = drawOrderCount;
attachments.GrowIfNeeded(drawOrderCount);
attachments.Count = drawOrderCount;
}
}
public struct AddSubmeshArguments {
public Material material;

View File

@ -71,6 +71,7 @@ public class SkeletonUtilityGroundConstraint : SkeletonUtilityConstraint {
protected override void OnEnable () {
base.OnEnable();
lastHitY = transform.position.y;
}
protected override void OnDisable () {