Compare commits

...

2 Commits

Author SHA1 Message Date
GL
966acd38e1 Merge branch 'main' of http://sheziwanglo.cn:3000/hyskai/_TheStrongestSnail 2024-11-12 14:07:09 +08:00
GL
eee242d0a7 add 2024-11-12 14:06:34 +08:00
711 changed files with 69981 additions and 26 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bda3fb9806abb464482e9cb8e77949cd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b29e98153ec2fbd44b8f7da1b41194e8, type: 3}
m_Name: SpineSettings
m_EditorClassIdentifier:
defaultScale: 0.01
defaultMix: 0.2
defaultShader: Spine/Skeleton
defaultZSpacing: 0
defaultInstantiateLoop: 1
defaultPhysicsPositionInheritance: {x: 1, y: 1}
defaultPhysicsRotationInheritance: 1
showHierarchyIcons: 1
reloadAfterPlayMode: 1
setTextureImporterSettings: 1
textureSettingsReference:
fixPrefabOverrideViaMeshFilter: 0
removePrefabPreviewMeshes: 0
blendModeMaterialMultiply: {fileID: 0}
blendModeMaterialScreen: {fileID: 0}
blendModeMaterialAdditive: {fileID: 0}
atlasTxtImportWarning: 1
textureImporterWarning: 1
componentMaterialWarning: 1
skeletonDataAssetNoFileError: 1
autoReloadSceneSkeletons: 1
handleScale: 1
mecanimEventIncludeFolderName: 1
timelineDefaultMixDuration: 0
timelineUseBlendDuration: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bd90f0f8a3e9d0544bbd18c6257570fc
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -547,11 +547,7 @@ RectTransform:
- {fileID: 2135586306}
- {fileID: 1584193622}
- {fileID: 1995711213}
- {fileID: 332149378}
- {fileID: 580834436}
- {fileID: 2029421261}
- {fileID: 252325264}
- {fileID: 935748551}
m_Father: {fileID: 1225833476}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -839,7 +835,7 @@ GameObject:
- component: {fileID: 214046554}
- component: {fileID: 214046553}
m_Layer: 5
m_Name: Text (Legacy)
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -1150,6 +1146,7 @@ GameObject:
serializedVersion: 6
m_Component:
- component: {fileID: 252325264}
- component: {fileID: 252325265}
m_Layer: 5
m_Name: HegemonPanel
m_TagString: Untagged
@ -1164,21 +1161,35 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252325263}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 43098355}
- {fileID: 394223518}
m_Father: {fileID: 142654719}
m_RootOrder: 11
m_Father: {fileID: 1225833476}
m_RootOrder: 6
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5398135, y: 0.882}
m_AnchorMax: {x: 1, y: 0.966}
m_AnchoredPosition: {x: -2.580017, y: -9.944824}
m_SizeDelta: {x: 8.150024, y: 21.1904}
m_SizeDelta: {x: 8.150024, y: 21.190414}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &252325265
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252325263}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: bccc9804fcaee0b4dbf55f78a599bc2c, type: 3}
m_Name:
m_EditorClassIdentifier:
timeText: {fileID: 1632850612}
timeNum: 0
--- !u!1 &271727214
GameObject:
m_ObjectHideFlags: 0
@ -1231,7 +1242,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
@ -1268,7 +1279,7 @@ GameObject:
- component: {fileID: 284545412}
- component: {fileID: 284545411}
m_Layer: 5
m_Name: Text (Legacy)
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -1415,13 +1426,13 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 332149377}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 142654719}
m_RootOrder: 8
m_Father: {fileID: 1225833476}
m_RootOrder: 7
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0.93435806}
m_AnchorMax: {x: 0.2895423, y: 0.98676854}
@ -1964,20 +1975,20 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 580834435}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1406968644}
- {fileID: 1804033313}
m_Father: {fileID: 142654719}
m_RootOrder: 9
m_Father: {fileID: 1225833476}
m_RootOrder: 5
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.04054228, y: 0.901642}
m_AnchorMax: {x: 0.2895423, y: 0.93435806}
m_AnchoredPosition: {x: 2.9500732, y: -1.7998047}
m_SizeDelta: {x: -0.83999634, y: 5.9396973}
m_SizeDelta: {x: -0.83999634, y: 5.9396896}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1 &586134487
GameObject:
@ -2029,7 +2040,7 @@ GameObject:
- component: {fileID: 632503726}
- component: {fileID: 632503725}
m_Layer: 5
m_Name: Text (Legacy)
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -2896,6 +2907,7 @@ GameObject:
- component: {fileID: 935748551}
- component: {fileID: 935748553}
- component: {fileID: 935748552}
- component: {fileID: 935748554}
m_Layer: 5
m_Name: BettingBtns
m_TagString: Untagged
@ -2910,7 +2922,7 @@ RectTransform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 935748550}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@ -2918,8 +2930,8 @@ RectTransform:
- {fileID: 1227559356}
- {fileID: 1954526985}
- {fileID: 1737087530}
m_Father: {fileID: 142654719}
m_RootOrder: 12
m_Father: {fileID: 1225833476}
m_RootOrder: 4
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.15748437}
m_AnchorMax: {x: 0.5, y: 0.15748437}
@ -2964,6 +2976,22 @@ CanvasRenderer:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 935748550}
m_CullTransparentMesh: 1
--- !u!114 &935748554
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 935748550}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4fb563e68ba8d9747a0dc8bd431d8495, type: 3}
m_Name:
m_EditorClassIdentifier:
BetList: {fileID: 1737087529}
NumBtn: {fileID: 1954526986}
BetText: {fileID: 251123273}
BetValue: 0
--- !u!1 &1049673026
GameObject:
m_ObjectHideFlags: 0
@ -3568,6 +3596,10 @@ RectTransform:
- {fileID: 142654719}
- {fileID: 760515341}
- {fileID: 86707888}
- {fileID: 935748551}
- {fileID: 580834436}
- {fileID: 252325264}
- {fileID: 332149378}
m_Father: {fileID: 0}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
@ -3711,7 +3743,7 @@ GameObject:
- component: {fileID: 1227980072}
- component: {fileID: 1227980071}
m_Layer: 5
m_Name: Text (Legacy)
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -4859,7 +4891,7 @@ GameObject:
- component: {fileID: 1565478605}
- component: {fileID: 1565478604}
m_Layer: 5
m_Name: Text (Legacy)
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -6540,11 +6572,11 @@ RectTransform:
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 142654719}
m_RootOrder: 10
m_RootOrder: 8
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 0.12415764}
m_AnchoredPosition: {x: 0, y: -0.49951172}
m_AnchoredPosition: {x: 0, y: -0.49902344}
m_SizeDelta: {x: -3, y: -1}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2029421262

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a04ee1d11f4fbf14cbabb39c94909c0a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,44 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class BettingBtn : MonoBehaviour
{
public GameObject BetList;
public Button NumBtn;
public Text BetText;
public float BetValue;//投注的值
// Start is called before the first frame update
void Start()
{
BetList.SetActive(false);
NumBtn.onClick.AddListener(OnClickNumBtn);
BetValue = 50;//默认50
SetBet();
}
void OnClickNumBtn()
{
BetList.SetActive(true);
}
void SetBet()
{
// 获取所有的Button组件
Button[] buttons = BetList.GetComponentsInChildren<Button>();
// 遍历每一个Button添加点击事件
foreach (Button button in buttons)
{
button.onClick.AddListener(() => {
BetText.text = button.transform.GetComponentInChildren<Text>().text;
BetValue = float.Parse(BetText.text);
BetList.SetActive(false);
});
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4fb563e68ba8d9747a0dc8bd431d8495
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HegemonTime : MonoBehaviour
{
public Text timeText;
public int timeNum;
// Start is called before the first frame update
void Start()
{
timeNum = 60;
StartCoroutine(StartGame());
}
private void Update()
{
}
private IEnumerator StartGame()
{
while (timeNum >=0)
{
timeText.text = timeNum.ToString(); // ÏÔʾÕûÊýÃëÊý
yield return new WaitForSeconds(1f); // µÈ´ý1Ãë
timeNum -= 1;
}
timeNum = 60;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bccc9804fcaee0b4dbf55f78a599bc2c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 30918bcaadaaecc42bc215ff52f75b21
folderAsset: yes
timeCreated: 1488288531
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f09c19426de438b408307e7ff432e4b5
timeCreated: 1727118056
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: ad14d5a4cd7a0444286d315541ee0495
folderAsset: yes
timeCreated: 1527569319
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
{
"name": "spine-unity-editor",
"references": [
"spine-csharp",
"spine-unity"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 173464ddf4cdb6640a4dfa8a9281ad69
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 83fbec88df35fe34bab43a5dde6788af
folderAsset: yes
timeCreated: 1527569675
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: f0e95036e72b08544a9d295dd4366f40
folderAsset: yes
DefaultImporter:
userData:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: eb646ac6e394e534b80d5cac61478488
folderAsset: yes
timeCreated: 1563305058
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,182 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 System;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
[CustomEditor(typeof(AnimationReferenceAsset))]
public class AnimationReferenceAssetEditor : Editor {
const string InspectorHelpText = "This is a Spine-Unity Animation Reference Asset. It serializes a reference to a SkeletonData asset and an animationName. It does not contain actual animation data. At runtime, it stores a reference to a Spine.Animation.\n\n" +
"You can use this in your AnimationState calls instead of a string animation name or a Spine.Animation reference. Use its implicit conversion into Spine.Animation or its .Animation property.\n\n" +
"Use AnimationReferenceAssets as an alternative to storing strings or finding animations and caching per component. This only does the lookup by string once, and allows you to store and manage animations via asset references.";
readonly SkeletonInspectorPreview preview = new SkeletonInspectorPreview();
FieldInfo skeletonDataAssetField = typeof(AnimationReferenceAsset).GetField("skeletonDataAsset", BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo nameField = typeof(AnimationReferenceAsset).GetField("animationName", BindingFlags.NonPublic | BindingFlags.Instance);
AnimationReferenceAsset ThisAnimationReferenceAsset { get { return target as AnimationReferenceAsset; } }
SkeletonDataAsset ThisSkeletonDataAsset { get { return skeletonDataAssetField.GetValue(ThisAnimationReferenceAsset) as SkeletonDataAsset; } }
string ThisAnimationName { get { return nameField.GetValue(ThisAnimationReferenceAsset) as string; } }
bool changeNextFrame = false;
SerializedProperty animationNameProperty;
SkeletonDataAsset lastSkeletonDataAsset;
SkeletonData lastSkeletonData;
void OnEnable () { HandleOnEnablePreview(); }
void OnDestroy () {
HandleOnDestroyPreview();
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
EditorApplication.update -= preview.HandleEditorUpdate;
}
public override void OnInspectorGUI () {
animationNameProperty = animationNameProperty ?? serializedObject.FindProperty("animationName");
string animationName = animationNameProperty.stringValue;
Animation animation = null;
if (ThisSkeletonDataAsset != null) {
SkeletonData skeletonData = ThisSkeletonDataAsset.GetSkeletonData(true);
if (skeletonData != null) {
animation = skeletonData.FindAnimation(animationName);
}
}
bool animationNotFound = (animation == null);
if (changeNextFrame) {
changeNextFrame = false;
if (ThisSkeletonDataAsset != lastSkeletonDataAsset || ThisSkeletonDataAsset.GetSkeletonData(true) != lastSkeletonData) {
preview.Clear();
preview.Initialize(Repaint, ThisSkeletonDataAsset, LastSkinName);
if (animationNotFound) {
animationNameProperty.stringValue = "";
preview.ClearAnimationSetupPose();
}
}
preview.ClearAnimationSetupPose();
if (!string.IsNullOrEmpty(animationNameProperty.stringValue))
preview.PlayPauseAnimation(animationNameProperty.stringValue, true);
}
//EditorGUILayout.HelpBox(AnimationReferenceAssetEditor.InspectorHelpText, MessageType.Info, true);
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
DrawDefaultInspector();
if (EditorGUI.EndChangeCheck()) {
changeNextFrame = true;
}
// Draw extra info below default inspector.
EditorGUILayout.Space();
if (ThisSkeletonDataAsset == null) {
EditorGUILayout.HelpBox("SkeletonDataAsset is missing.", MessageType.Error);
} else if (string.IsNullOrEmpty(animationName)) {
EditorGUILayout.HelpBox("No animation selected.", MessageType.Warning);
} else if (animationNotFound) {
EditorGUILayout.HelpBox(string.Format("Animation named {0} was not found for this Skeleton.", animationNameProperty.stringValue), MessageType.Warning);
} else {
using (new SpineInspectorUtility.BoxScope()) {
if (!string.Equals(AssetUtility.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase))
EditorGUILayout.HelpBox("Animation name value does not match this asset's name. Inspectors using this asset may be misleading.", MessageType.None);
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(animationName, SpineEditorUtilities.Icons.animation));
if (animation != null) {
EditorGUILayout.LabelField(string.Format("Timelines: {0}", animation.Timelines.Count));
EditorGUILayout.LabelField(string.Format("Duration: {0} sec", animation.Duration));
}
}
}
lastSkeletonDataAsset = ThisSkeletonDataAsset;
lastSkeletonData = ThisSkeletonDataAsset.GetSkeletonData(true);
}
#region Preview Handlers
string TargetAssetGUID { get { return AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(ThisSkeletonDataAsset)); } }
string LastSkinKey { get { return TargetAssetGUID + "_lastSkin"; } }
string LastSkinName { get { return EditorPrefs.GetString(LastSkinKey, ""); } }
void HandleOnEnablePreview () {
if (ThisSkeletonDataAsset != null && ThisSkeletonDataAsset.skeletonJSON == null)
return;
SpineEditorUtilities.ConfirmInitialization();
// This handles the case where the managed editor assembly is unloaded before recompilation when code changes.
AppDomain.CurrentDomain.DomainUnload -= OnDomainUnload;
AppDomain.CurrentDomain.DomainUnload += OnDomainUnload;
preview.Initialize(this.Repaint, ThisSkeletonDataAsset, LastSkinName);
preview.PlayPauseAnimation(ThisAnimationName, true);
preview.OnSkinChanged -= HandleOnSkinChanged;
preview.OnSkinChanged += HandleOnSkinChanged;
EditorApplication.update -= preview.HandleEditorUpdate;
EditorApplication.update += preview.HandleEditorUpdate;
}
private void OnDomainUnload (object sender, EventArgs e) {
OnDestroy();
}
private void HandleOnSkinChanged (string skinName) {
EditorPrefs.SetString(LastSkinKey, skinName);
preview.PlayPauseAnimation(ThisAnimationName, true);
}
void HandleOnDestroyPreview () {
EditorApplication.update -= preview.HandleEditorUpdate;
preview.OnDestroy();
}
override public bool HasPreviewGUI () {
if (serializedObject.isEditingMultipleObjects) return false;
return ThisSkeletonDataAsset != null && ThisSkeletonDataAsset.GetSkeletonData(true) != null;
}
override public void OnInteractivePreviewGUI (Rect r, GUIStyle background) {
preview.Initialize(this.Repaint, ThisSkeletonDataAsset);
preview.HandleInteractivePreviewGUI(r, background);
}
public override GUIContent GetPreviewTitle () { return SpineInspectorUtility.TempContent("Preview"); }
public override void OnPreviewSettings () { preview.HandleDrawSettings(); }
public override Texture2D RenderStaticPreview (string assetPath, UnityEngine.Object[] subAssets, int width, int height) { return preview.GetStaticPreview(width, height); }
#endregion
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 9511532e80feed24881a5863f5485446
timeCreated: 1523316585
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 01cbef8f24d105f4bafa9668d669e040
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,390 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
//#define BAKE_ALL_BUTTON
//#define REGION_BAKING_MESH
using Spine;
using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
[CustomEditor(typeof(SpineAtlasAsset)), CanEditMultipleObjects]
public class SpineAtlasAssetInspector : UnityEditor.Editor {
SerializedProperty atlasFile, materials, textureLoadingMode, onDemandTextureLoader;
SpineAtlasAsset atlasAsset;
GUIContent spriteSlicesLabel;
GUIContent SpriteSlicesLabel {
get {
if (spriteSlicesLabel == null) {
spriteSlicesLabel = new GUIContent(
"Apply Regions as Texture Sprite Slices",
SpineEditorUtilities.Icons.unity,
"Adds Sprite slices to atlas texture(s). " +
"Updates existing slices if ones with matching names exist. \n\n" +
"If your atlas was exported with Premultiply Alpha, " +
"your SpriteRenderer should use the generated Spine _Material asset (or any Material with a PMA shader) instead of Sprites-Default.");
}
return spriteSlicesLabel;
}
}
static List<AtlasRegion> GetRegions (Atlas atlas) {
FieldInfo regionsField = SpineInspectorUtility.GetNonPublicField(typeof(Atlas), "regions");
return (List<AtlasRegion>)regionsField.GetValue(atlas);
}
void OnEnable () {
SpineEditorUtilities.ConfirmInitialization();
atlasFile = serializedObject.FindProperty("atlasFile");
materials = serializedObject.FindProperty("materials");
textureLoadingMode = serializedObject.FindProperty("textureLoadingMode");
onDemandTextureLoader = serializedObject.FindProperty("onDemandTextureLoader");
materials.isExpanded = true;
atlasAsset = (SpineAtlasAsset)target;
#if REGION_BAKING_MESH
UpdateBakedList();
#endif
}
#if REGION_BAKING_MESH
private List<bool> baked;
private List<GameObject> bakedObjects;
void UpdateBakedList () {
AtlasAsset asset = (AtlasAsset)target;
baked = new List<bool>();
bakedObjects = new List<GameObject>();
if (atlasFile.objectReferenceValue != null) {
List<AtlasRegion> regions = this.Regions;
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
for (int i = 0; i < regions.Count; i++) {
AtlasRegion region = regions[i];
string bakedPrefabPath = Path.Combine(bakedDirPath, AssetUtility.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/");
GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject));
baked.Add(prefab != null);
bakedObjects.Add(prefab);
}
}
}
#endif
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
DrawDefaultInspector();
return;
}
serializedObject.Update();
atlasAsset = (atlasAsset == null) ? (SpineAtlasAsset)target : atlasAsset;
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
atlasAsset.Clear();
atlasAsset.GetAtlas();
}
if (materials.arraySize == 0) {
EditorGUILayout.HelpBox("No materials", MessageType.Error);
return;
}
for (int i = 0; i < materials.arraySize; i++) {
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
Material material = (Material)prop.objectReferenceValue;
if (material == null) {
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
return;
}
}
if (textureLoadingMode != null) {
EditorGUILayout.Space();
EditorGUILayout.PropertyField(textureLoadingMode);
EditorGUILayout.PropertyField(onDemandTextureLoader);
}
EditorGUILayout.Space();
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpinePreferences.DEFAULT_MIPMAPBIAS, tooltip: "This may help textures with mipmaps be less blurry when used for 2D sprites."))) {
foreach (Material m in atlasAsset.materials) {
Texture texture = m.mainTexture;
string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID());
TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(texturePath);
importer.mipMapBias = SpinePreferences.DEFAULT_MIPMAPBIAS;
EditorUtility.SetDirty(texture);
}
Debug.Log("Texture mipmap bias set to " + SpinePreferences.DEFAULT_MIPMAPBIAS);
}
EditorGUILayout.Space();
if (atlasFile.objectReferenceValue != null) {
if (SpineInspectorUtility.LargeCenteredButton(SpriteSlicesLabel)) {
Atlas atlas = atlasAsset.GetAtlas();
foreach (Material m in atlasAsset.materials)
UpdateSpriteSlices(m.mainTexture, atlas);
}
}
EditorGUILayout.Space();
#if REGION_BAKING_MESH
if (atlasFile.objectReferenceValue != null) {
Atlas atlas = asset.GetAtlas();
FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic);
List<AtlasRegion> regions = (List<AtlasRegion>)field.GetValue(atlas);
EditorGUILayout.LabelField(new GUIContent("Region Baking", SpineEditorUtilities.Icons.unityIcon));
EditorGUI.indentLevel++;
AtlasPage lastPage = null;
for (int i = 0; i < regions.Count; i++) {
if (lastPage != regions[i].page) {
if (lastPage != null) {
EditorGUILayout.Separator();
EditorGUILayout.Separator();
}
lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject);
if (mat != null) {
GUILayout.BeginHorizontal();
{
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.EndDisabledGroup();
}
GUILayout.EndHorizontal();
} else {
EditorGUILayout.LabelField(new GUIContent("Page missing material!", SpineEditorUtilities.Icons.warning));
}
}
GUILayout.BeginHorizontal();
{
//EditorGUILayout.ToggleLeft(baked[i] ? "" : regions[i].name, baked[i]);
bool result = baked[i] ? EditorGUILayout.ToggleLeft("", baked[i], GUILayout.Width(24)) : EditorGUILayout.ToggleLeft(" " + regions[i].name, baked[i]);
if(baked[i]){
EditorGUILayout.ObjectField(bakedObjects[i], typeof(GameObject), false, GUILayout.Width(250));
}
if (result && !baked[i]) {
//bake
baked[i] = true;
bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]);
EditorGUIUtility.PingObject(bakedObjects[i]);
} else if (!result && baked[i]) {
//unbake
bool unbakeResult = EditorUtility.DisplayDialog("Delete Baked Region", "Do you want to delete the prefab for " + regions[i].name, "Yes", "Cancel");
switch (unbakeResult) {
case true:
//delete
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/");
AssetDatabase.DeleteAsset(bakedPrefabPath);
baked[i] = false;
break;
case false:
//do nothing
break;
}
}
}
GUILayout.EndHorizontal();
}
EditorGUI.indentLevel--;
#if BAKE_ALL_BUTTON
// Check state
bool allBaked = true;
bool allUnbaked = true;
for (int i = 0; i < regions.Count; i++) {
allBaked &= baked[i];
allUnbaked &= !baked[i];
}
if (!allBaked && GUILayout.Button("Bake All")) {
for (int i = 0; i < regions.Count; i++) {
if (!baked[i]) {
baked[i] = true;
bakedObjects[i] = SpineEditorUtilities.BakeRegion(atlasAsset, regions[i]);
}
}
} else if (!allUnbaked && GUILayout.Button("Unbake All")) {
bool unbakeResult = EditorUtility.DisplayDialog("Delete All Baked Regions", "Are you sure you want to unbake all region prefabs? This cannot be undone.", "Yes", "Cancel");
switch (unbakeResult) {
case true:
//delete
for (int i = 0; i < regions.Count; i++) {
if (baked[i]) {
string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset);
string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath);
string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name);
string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(regions[i]) + ".prefab").Replace("\\", "/");
AssetDatabase.DeleteAsset(bakedPrefabPath);
baked[i] = false;
}
}
break;
case false:
//do nothing
break;
}
}
#endif
}
#else
if (atlasFile.objectReferenceValue != null) {
int baseIndent = EditorGUI.indentLevel;
List<AtlasRegion> regions = SpineAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas());
int regionsCount = regions.Count;
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel);
EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount));
}
AtlasPage lastPage = null;
for (int i = 0; i < regionsCount; i++) {
if (lastPage != regions[i].page) {
if (lastPage != null) {
EditorGUILayout.Separator();
EditorGUILayout.Separator();
}
lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject);
if (mat != null) {
EditorGUI.indentLevel = baseIndent;
using (new GUILayout.HorizontalScope())
using (new EditorGUI.DisabledGroupScope(true))
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.indentLevel = baseIndent + 1;
} else {
EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning);
}
}
string regionName = regions[i].name;
Texture2D icon = SpineEditorUtilities.Icons.image;
if (regionName.EndsWith(" ")) {
regionName = string.Format("'{0}'", regions[i].name);
icon = SpineEditorUtilities.Icons.warning;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames."));
} else {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon));
}
}
EditorGUI.indentLevel = baseIndent;
}
#endif
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current))
atlasAsset.Clear();
}
static public void UpdateSpriteSlices (Texture texture, Atlas atlas) {
string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID());
TextureImporter t = (TextureImporter)TextureImporter.GetAtPath(texturePath);
t.spriteImportMode = SpriteImportMode.Multiple;
SpriteMetaData[] spriteSheet = t.spritesheet;
List<SpriteMetaData> sprites = new List<SpriteMetaData>(spriteSheet);
List<AtlasRegion> regions = SpineAtlasAssetInspector.GetRegions(atlas);
int updatedCount = 0;
int addedCount = 0;
foreach (AtlasRegion r in regions) {
string pageName = System.IO.Path.GetFileNameWithoutExtension(r.page.name);
string textureName = texture.name;
bool pageMatch = string.Equals(pageName, textureName, StringComparison.Ordinal);
// if (pageMatch) {
// int pw = r.page.width;
// int ph = r.page.height;
// bool mismatchSize = pw != texture.width || pw > t.maxTextureSize || ph != texture.height || ph > t.maxTextureSize;
// if (mismatchSize)
// Debug.LogWarningFormat("Size mismatch found.\nExpected atlas size is {0}x{1}. Texture Import Max Size of texture '{2}'({4}x{5}) is currently set to {3}.", pw, ph, texture.name, t.maxTextureSize, texture.width, texture.height);
// }
int spriteIndex = pageMatch ? sprites.FindIndex(
(s) => string.Equals(s.name, r.name, StringComparison.Ordinal)
) : -1;
bool spriteNameMatchExists = spriteIndex >= 0;
if (pageMatch) {
Rect spriteRect = new Rect();
if (r.degrees == 90) {
spriteRect.width = r.height;
spriteRect.height = r.width;
} else {
spriteRect.width = r.width;
spriteRect.height = r.height;
}
spriteRect.x = r.x;
spriteRect.y = r.page.height - spriteRect.height - r.y;
if (spriteNameMatchExists) {
SpriteMetaData s = sprites[spriteIndex];
s.rect = spriteRect;
sprites[spriteIndex] = s;
updatedCount++;
} else {
sprites.Add(new SpriteMetaData {
name = r.name,
pivot = new Vector2(0.5f, 0.5f),
rect = spriteRect
});
addedCount++;
}
}
}
t.spritesheet = sprites.ToArray();
EditorUtility.SetDirty(t);
AssetDatabase.ImportAsset(texturePath, ImportAssetOptions.ForceUpdate);
EditorGUIUtility.PingObject(texture);
Debug.Log(string.Format("Applied sprite slices to {2}. {0} added. {1} updated.", addedCount, updatedCount, texture.name));
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ca9b3ce36d70a05408e3bdd5e92c7f64
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,153 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 System;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
[CustomEditor(typeof(SpineSpriteAtlasAsset)), CanEditMultipleObjects]
public class SpineSpriteAtlasAssetInspector : UnityEditor.Editor {
SerializedProperty atlasFile, materials;
SpineSpriteAtlasAsset atlasAsset;
static List<AtlasRegion> GetRegions (Atlas atlas) {
FieldInfo regionsField = SpineInspectorUtility.GetNonPublicField(typeof(Atlas), "regions");
return (List<AtlasRegion>)regionsField.GetValue(atlas);
}
void OnEnable () {
SpineEditorUtilities.ConfirmInitialization();
atlasFile = serializedObject.FindProperty("spriteAtlasFile");
materials = serializedObject.FindProperty("materials");
materials.isExpanded = true;
atlasAsset = (SpineSpriteAtlasAsset)target;
if (!SpineSpriteAtlasAsset.AnySpriteAtlasNeedsRegionsLoaded())
return;
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
EditorApplication.update += SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
void OnDisable () {
EditorApplication.update -= SpineSpriteAtlasAsset.UpdateWhenEditorPlayModeStarted;
}
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
DrawDefaultInspector();
return;
}
serializedObject.Update();
atlasAsset = (atlasAsset == null) ? (SpineSpriteAtlasAsset)target : atlasAsset;
if (atlasAsset.RegionsNeedLoading) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Load regions by entering Play mode"), GUILayout.Height(20))) {
EditorApplication.isPlaying = true;
}
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(atlasFile);
EditorGUILayout.PropertyField(materials, true);
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
atlasAsset.Clear();
atlasAsset.GetAtlas();
atlasAsset.updateRegionsInPlayMode = true;
}
if (materials.arraySize == 0) {
EditorGUILayout.HelpBox("No materials", MessageType.Error);
return;
}
for (int i = 0; i < materials.arraySize; i++) {
SerializedProperty prop = materials.GetArrayElementAtIndex(i);
Material material = (Material)prop.objectReferenceValue;
if (material == null) {
EditorGUILayout.HelpBox("Materials cannot be null.", MessageType.Error);
return;
}
}
if (atlasFile.objectReferenceValue != null) {
int baseIndent = EditorGUI.indentLevel;
List<AtlasRegion> regions = SpineSpriteAtlasAssetInspector.GetRegions(atlasAsset.GetAtlas());
int regionsCount = regions.Count;
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.LabelField("Atlas Regions", EditorStyles.boldLabel);
EditorGUILayout.LabelField(string.Format("{0} regions total", regionsCount));
}
AtlasPage lastPage = null;
for (int i = 0; i < regionsCount; i++) {
if (lastPage != regions[i].page) {
if (lastPage != null) {
EditorGUILayout.Separator();
EditorGUILayout.Separator();
}
lastPage = regions[i].page;
Material mat = ((Material)lastPage.rendererObject);
if (mat != null) {
EditorGUI.indentLevel = baseIndent;
using (new GUILayout.HorizontalScope())
using (new EditorGUI.DisabledGroupScope(true))
EditorGUILayout.ObjectField(mat, typeof(Material), false, GUILayout.Width(250));
EditorGUI.indentLevel = baseIndent + 1;
} else {
EditorGUILayout.HelpBox("Page missing material!", MessageType.Warning);
}
}
string regionName = regions[i].name;
Texture2D icon = SpineEditorUtilities.Icons.image;
if (regionName.EndsWith(" ")) {
regionName = string.Format("'{0}'", regions[i].name);
icon = SpineEditorUtilities.Icons.warning;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames."));
} else {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon));
}
}
EditorGUI.indentLevel = baseIndent;
}
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current))
atlasAsset.Clear();
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f063dc5ff6881db4a9ee2e059812cba2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 0134640f881c8d24d812a6f9af9d0761
folderAsset: yes
timeCreated: 1563304704
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,209 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
using Event = UnityEngine.Event;
[CustomEditor(typeof(BoneFollowerGraphic)), CanEditMultipleObjects]
public class BoneFollowerGraphicInspector : Editor {
SerializedProperty boneName, skeletonGraphic, followXYPosition, followZPosition, followBoneRotation,
followLocalScale, followParentWorldScale, followSkeletonFlip, maintainedAxisOrientation;
BoneFollowerGraphic targetBoneFollower;
bool needsReset;
#region Context Menu Item
[MenuItem("CONTEXT/SkeletonGraphic/Add BoneFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonGraphic skeletonGraphic = cmd.context as SkeletonGraphic;
GameObject go = EditorInstantiation.NewGameObject("BoneFollower", true, typeof(RectTransform));
Transform t = go.transform;
t.SetParent(skeletonGraphic.transform);
t.localPosition = Vector3.zero;
BoneFollowerGraphic f = go.AddComponent<BoneFollowerGraphic>();
f.skeletonGraphic = skeletonGraphic;
f.SetBone(skeletonGraphic.Skeleton.RootBone.Data.Name);
EditorGUIUtility.PingObject(t);
Undo.RegisterCreatedObjectUndo(go, "Add BoneFollowerGraphic");
}
// Validate
[MenuItem("CONTEXT/SkeletonGraphic/Add BoneFollower GameObject", true)]
static bool ValidateAddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonGraphic skeletonGraphic = cmd.context as SkeletonGraphic;
return skeletonGraphic.IsValid;
}
#endregion
void OnEnable () {
skeletonGraphic = serializedObject.FindProperty("skeletonGraphic");
boneName = serializedObject.FindProperty("boneName");
followBoneRotation = serializedObject.FindProperty("followBoneRotation");
followXYPosition = serializedObject.FindProperty("followXYPosition");
followZPosition = serializedObject.FindProperty("followZPosition");
followLocalScale = serializedObject.FindProperty("followLocalScale");
followParentWorldScale = serializedObject.FindProperty("followParentWorldScale");
followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip");
maintainedAxisOrientation = serializedObject.FindProperty("maintainedAxisOrientation");
targetBoneFollower = (BoneFollowerGraphic)target;
if (targetBoneFollower.SkeletonGraphic != null)
targetBoneFollower.SkeletonGraphic.Initialize(false);
if (!targetBoneFollower.valid || needsReset) {
targetBoneFollower.Initialize();
targetBoneFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
}
public void OnSceneGUI () {
BoneFollowerGraphic tbf = target as BoneFollowerGraphic;
SkeletonGraphic skeletonGraphicComponent = tbf.SkeletonGraphic;
if (skeletonGraphicComponent == null) return;
Transform transform = skeletonGraphicComponent.transform;
Skeleton skeleton = skeletonGraphicComponent.Skeleton;
float positionScale = skeletonGraphicComponent.MeshScale;
Vector2 positionOffset = skeletonGraphicComponent.GetScaledPivotOffset();
if (string.IsNullOrEmpty(boneName.stringValue)) {
SpineHandles.DrawBones(transform, skeleton, positionScale, positionOffset);
SpineHandles.DrawBoneNames(transform, skeleton, positionScale, positionOffset);
Handles.Label(tbf.transform.position, "No bone selected", EditorStyles.helpBox);
} else {
Bone targetBone = tbf.bone;
if (targetBone == null) return;
SpineHandles.DrawBoneWireframe(transform, targetBone, SpineHandles.TransformContraintColor, positionScale, positionOffset);
Handles.Label(targetBone.GetWorldPosition(transform, positionScale, positionOffset),
targetBone.Data.Name, SpineHandles.BoneNameStyle);
}
}
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
if (needsReset) {
needsReset = false;
foreach (Object o in targets) {
BoneFollower bf = (BoneFollower)o;
bf.Initialize();
bf.LateUpdate();
}
SceneView.RepaintAll();
}
EditorGUI.BeginChangeCheck();
DrawDefaultInspector();
needsReset |= EditorGUI.EndChangeCheck();
return;
}
if (needsReset && Event.current.type == EventType.Layout) {
targetBoneFollower.Initialize();
targetBoneFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
serializedObject.Update();
// Find Renderer
if (skeletonGraphic.objectReferenceValue == null) {
SkeletonGraphic parentRenderer = targetBoneFollower.GetComponentInParent<SkeletonGraphic>();
if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject) {
skeletonGraphic.objectReferenceValue = parentRenderer;
Debug.Log("Inspector automatically assigned BoneFollowerGraphic.SkeletonGraphic");
}
}
EditorGUILayout.PropertyField(skeletonGraphic);
SkeletonGraphic skeletonGraphicComponent = skeletonGraphic.objectReferenceValue as SkeletonGraphic;
if (skeletonGraphicComponent != null) {
if (skeletonGraphicComponent.gameObject == targetBoneFollower.gameObject) {
skeletonGraphic.objectReferenceValue = null;
EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollowerGraphic can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonGraphic from a different GameObject.", "Ok");
}
}
if (!targetBoneFollower.valid) {
needsReset = true;
}
if (targetBoneFollower.valid) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(boneName);
needsReset |= EditorGUI.EndChangeCheck();
EditorGUILayout.PropertyField(followBoneRotation);
EditorGUILayout.PropertyField(followXYPosition);
EditorGUILayout.PropertyField(followZPosition);
EditorGUILayout.PropertyField(followLocalScale);
EditorGUILayout.PropertyField(followParentWorldScale);
EditorGUILayout.PropertyField(followSkeletonFlip);
if ((followSkeletonFlip.hasMultipleDifferentValues || followSkeletonFlip.boolValue == false) &&
(followBoneRotation.hasMultipleDifferentValues || followBoneRotation.boolValue == true)) {
using (new SpineInspectorUtility.IndentScope())
EditorGUILayout.PropertyField(maintainedAxisOrientation);
}
//BoneFollowerInspector.RecommendRigidbodyButton(targetBoneFollower);
} else {
SkeletonGraphic boneFollowerSkeletonGraphic = targetBoneFollower.skeletonGraphic;
if (boneFollowerSkeletonGraphic == null) {
EditorGUILayout.HelpBox("SkeletonGraphic is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonMecanim).", MessageType.Warning);
} else {
boneFollowerSkeletonGraphic.Initialize(false);
if (boneFollowerSkeletonGraphic.skeletonDataAsset == null)
EditorGUILayout.HelpBox("Assigned SkeletonGraphic does not have SkeletonData assigned to it.", MessageType.Warning);
if (!boneFollowerSkeletonGraphic.IsValid)
EditorGUILayout.HelpBox("Assigned SkeletonGraphic is invalid. Check target SkeletonGraphic, its SkeletonData asset or the console for other errors.", MessageType.Warning);
}
}
Event current = Event.current;
bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
if (wasUndo)
targetBoneFollower.Initialize();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: da44a8561fd243c43a1f77bda36de0eb
timeCreated: 1499279157
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,230 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
using Event = UnityEngine.Event;
[CustomEditor(typeof(BoneFollower)), CanEditMultipleObjects]
public class BoneFollowerInspector : Editor {
SerializedProperty boneName, skeletonRenderer, followXYPosition, followZPosition, followBoneRotation,
followLocalScale, followParentWorldScale, followSkeletonFlip, maintainedAxisOrientation;
BoneFollower targetBoneFollower;
bool needsReset;
#region Context Menu Item
[MenuItem("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonRenderer skeletonRenderer = cmd.context as SkeletonRenderer;
GameObject go = EditorInstantiation.NewGameObject("New BoneFollower", true);
Transform t = go.transform;
t.SetParent(skeletonRenderer.transform);
t.localPosition = Vector3.zero;
BoneFollower f = go.AddComponent<BoneFollower>();
f.skeletonRenderer = skeletonRenderer;
EditorGUIUtility.PingObject(t);
Undo.RegisterCreatedObjectUndo(go, "Add BoneFollower");
}
// Validate
[MenuItem("CONTEXT/SkeletonRenderer/Add BoneFollower GameObject", true)]
static bool ValidateAddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonRenderer skeletonRenderer = cmd.context as SkeletonRenderer;
return skeletonRenderer.valid;
}
[MenuItem("CONTEXT/BoneFollower/Rename BoneFollower GameObject")]
static void RenameGameObject (MenuCommand cmd) {
AutonameGameObject(cmd.context as BoneFollower);
}
#endregion
static void AutonameGameObject (BoneFollower boneFollower) {
if (boneFollower == null) return;
string boneName = boneFollower.boneName;
boneFollower.gameObject.name = string.IsNullOrEmpty(boneName) ? "BoneFollower" : string.Format("{0} (BoneFollower)", boneName);
}
void OnEnable () {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
boneName = serializedObject.FindProperty("boneName");
followBoneRotation = serializedObject.FindProperty("followBoneRotation");
followXYPosition = serializedObject.FindProperty("followXYPosition");
followZPosition = serializedObject.FindProperty("followZPosition");
followLocalScale = serializedObject.FindProperty("followLocalScale");
followParentWorldScale = serializedObject.FindProperty("followParentWorldScale");
followSkeletonFlip = serializedObject.FindProperty("followSkeletonFlip");
maintainedAxisOrientation = serializedObject.FindProperty("maintainedAxisOrientation");
targetBoneFollower = (BoneFollower)target;
if (targetBoneFollower.SkeletonRenderer != null)
targetBoneFollower.SkeletonRenderer.Initialize(false);
if (!targetBoneFollower.valid || needsReset) {
targetBoneFollower.Initialize();
targetBoneFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
}
public void OnSceneGUI () {
BoneFollower tbf = target as BoneFollower;
SkeletonRenderer skeletonRendererComponent = tbf.skeletonRenderer;
if (skeletonRendererComponent == null) return;
Transform transform = skeletonRendererComponent.transform;
Skeleton skeleton = skeletonRendererComponent.skeleton;
if (string.IsNullOrEmpty(boneName.stringValue)) {
SpineHandles.DrawBones(transform, skeleton);
SpineHandles.DrawBoneNames(transform, skeleton);
Handles.Label(tbf.transform.position, "No bone selected", EditorStyles.helpBox);
} else {
Bone targetBone = tbf.bone;
if (targetBone == null) return;
SpineHandles.DrawBoneWireframe(transform, targetBone, SpineHandles.TransformContraintColor);
Handles.Label(targetBone.GetWorldPosition(transform), targetBone.Data.Name, SpineHandles.BoneNameStyle);
}
}
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
if (needsReset) {
needsReset = false;
foreach (UnityEngine.Object o in targets) {
BoneFollower bf = (BoneFollower)o;
bf.Initialize();
bf.LateUpdate();
}
SceneView.RepaintAll();
}
EditorGUI.BeginChangeCheck();
DrawDefaultInspector();
needsReset |= EditorGUI.EndChangeCheck();
return;
}
if (needsReset && Event.current.type == EventType.Layout) {
targetBoneFollower.Initialize();
targetBoneFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
serializedObject.Update();
// Find Renderer
if (skeletonRenderer.objectReferenceValue == null) {
SkeletonRenderer parentRenderer = targetBoneFollower.GetComponentInParent<SkeletonRenderer>();
if (parentRenderer != null && parentRenderer.gameObject != targetBoneFollower.gameObject) {
skeletonRenderer.objectReferenceValue = parentRenderer;
Debug.Log("Inspector automatically assigned BoneFollower.SkeletonRenderer");
}
}
EditorGUILayout.PropertyField(skeletonRenderer);
SkeletonRenderer skeletonRendererReference = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
if (skeletonRendererReference != null) {
if (skeletonRendererReference.gameObject == targetBoneFollower.gameObject) {
skeletonRenderer.objectReferenceValue = null;
EditorUtility.DisplayDialog("Invalid assignment.", "BoneFollower can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your BoneFollower, or choose a SkeletonRenderer from a different GameObject.", "Ok");
}
}
if (!targetBoneFollower.valid) {
needsReset = true;
}
if (targetBoneFollower.valid) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(boneName);
needsReset |= EditorGUI.EndChangeCheck();
EditorGUILayout.PropertyField(followBoneRotation);
EditorGUILayout.PropertyField(followXYPosition);
EditorGUILayout.PropertyField(followZPosition);
EditorGUILayout.PropertyField(followLocalScale);
EditorGUILayout.PropertyField(followParentWorldScale);
EditorGUILayout.PropertyField(followSkeletonFlip);
if ((followSkeletonFlip.hasMultipleDifferentValues || followSkeletonFlip.boolValue == false) &&
(followBoneRotation.hasMultipleDifferentValues || followBoneRotation.boolValue == true)) {
using (new SpineInspectorUtility.IndentScope())
EditorGUILayout.PropertyField(maintainedAxisOrientation);
}
BoneFollowerInspector.RecommendRigidbodyButton(targetBoneFollower);
} else {
SkeletonRenderer boneFollowerSkeletonRenderer = targetBoneFollower.skeletonRenderer;
if (boneFollowerSkeletonRenderer == null) {
EditorGUILayout.HelpBox("SkeletonRenderer is unassigned. Please assign a SkeletonRenderer (SkeletonAnimation or SkeletonMecanim).", MessageType.Warning);
} else {
boneFollowerSkeletonRenderer.Initialize(false);
if (boneFollowerSkeletonRenderer.skeletonDataAsset == null)
EditorGUILayout.HelpBox("Assigned SkeletonRenderer does not have SkeletonData assigned to it.", MessageType.Warning);
if (!boneFollowerSkeletonRenderer.valid)
EditorGUILayout.HelpBox("Assigned SkeletonRenderer is invalid. Check target SkeletonRenderer, its SkeletonData asset or the console for other errors.", MessageType.Warning);
}
}
Event current = Event.current;
bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
if (wasUndo)
targetBoneFollower.Initialize();
serializedObject.ApplyModifiedProperties();
}
internal static void RecommendRigidbodyButton (Component component) {
bool hasCollider2D = component.GetComponent<Collider2D>() != null || component.GetComponent<BoundingBoxFollower>() != null;
bool hasCollider3D = !hasCollider2D && component.GetComponent<Collider>();
bool missingRigidBody = (hasCollider2D && component.GetComponent<Rigidbody2D>() == null) || (hasCollider3D && component.GetComponent<Rigidbody>() == null);
if (missingRigidBody) {
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.HelpBox("Collider detected. Unity recommends adding a Rigidbody to the Transforms of any colliders that are intended to be dynamically repositioned and rotated.", MessageType.Warning);
System.Type rbType = hasCollider2D ? typeof(Rigidbody2D) : typeof(Rigidbody);
string rbLabel = string.Format("Add {0}", rbType.Name);
GUIContent rbContent = SpineInspectorUtility.TempContent(rbLabel, SpineInspectorUtility.UnityIcon(rbType), "Add a rigidbody to this GameObject to be the Physics body parent of the attached collider.");
if (SpineInspectorUtility.CenteredButton(rbContent)) component.gameObject.AddComponent(rbType);
}
}
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: c71ca35fd6241cb49a0b0756a664fcf7
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,271 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(BoundingBoxFollowerGraphic))]
public class BoundingBoxFollowerGraphicInspector : UnityEditor.Editor {
SerializedProperty skeletonGraphic, slotName,
isTrigger, usedByEffector, usedByComposite, clearStateOnDisable;
BoundingBoxFollowerGraphic follower;
bool rebuildRequired = false;
bool addBoneFollower = false;
bool sceneRepaintRequired = false;
bool debugIsExpanded;
GUIContent addBoneFollowerLabel;
GUIContent AddBoneFollowerLabel {
get {
if (addBoneFollowerLabel == null) addBoneFollowerLabel = new GUIContent("Add Bone Follower", Icons.bone);
return addBoneFollowerLabel;
}
}
void InitializeEditor () {
skeletonGraphic = serializedObject.FindProperty("skeletonGraphic");
slotName = serializedObject.FindProperty("slotName");
isTrigger = serializedObject.FindProperty("isTrigger");
usedByEffector = serializedObject.FindProperty("usedByEffector");
usedByComposite = serializedObject.FindProperty("usedByComposite");
clearStateOnDisable = serializedObject.FindProperty("clearStateOnDisable");
follower = (BoundingBoxFollowerGraphic)target;
}
public override void OnInspectorGUI () {
#if !NEW_PREFAB_SYSTEM
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#else
bool isInspectingPrefab = false;
#endif
// Note: when calling InitializeEditor() in OnEnable, it throws exception
// "SerializedObjectNotCreatableException: Object at index 0 is null".
InitializeEditor();
// Try to auto-assign SkeletonGraphic field.
if (skeletonGraphic.objectReferenceValue == null) {
SkeletonGraphic foundSkeletonGraphic = follower.GetComponentInParent<SkeletonGraphic>();
if (foundSkeletonGraphic != null)
Debug.Log("BoundingBoxFollowerGraphic automatically assigned: " + foundSkeletonGraphic.gameObject.name);
else if (Event.current.type == EventType.Repaint)
Debug.Log("No Spine GameObject detected. Make sure to set this GameObject as a child of the Spine GameObject; or set BoundingBoxFollowerGraphic's 'Skeleton Graphic' field in the inspector.");
skeletonGraphic.objectReferenceValue = foundSkeletonGraphic;
serializedObject.ApplyModifiedProperties();
InitializeEditor();
}
SkeletonGraphic skeletonGraphicValue = skeletonGraphic.objectReferenceValue as SkeletonGraphic;
if (skeletonGraphicValue != null && skeletonGraphicValue.gameObject == follower.gameObject) {
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollowerGraphic to a separate child GameObject of the Spine GameObject.", MessageType.Warning);
if (GUILayout.Button(new GUIContent("Move BoundingBoxFollowerGraphic to new GameObject", Icons.boundingBox), GUILayout.Height(30f))) {
AddBoundingBoxFollowerGraphicChild(skeletonGraphicValue, follower);
DestroyImmediate(follower);
return;
}
}
EditorGUILayout.Space();
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(skeletonGraphic);
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
#if !NEW_PREFAB_SYSTEM
if (!isInspectingPrefab)
rebuildRequired = true;
#endif
}
using (new SpineInspectorUtility.LabelWidthScope(150f)) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(isTrigger);
EditorGUILayout.PropertyField(usedByEffector);
EditorGUILayout.PropertyField(usedByComposite);
bool colliderParamChanged = EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(clearStateOnDisable, new GUIContent(clearStateOnDisable.displayName, "Enable this if you are pooling your Spine GameObject"));
bool clearStateChanged = EditorGUI.EndChangeCheck();
if (clearStateChanged || colliderParamChanged) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
if (colliderParamChanged)
foreach (PolygonCollider2D col in follower.colliderTable.Values) {
col.isTrigger = isTrigger.boolValue;
col.usedByEffector = usedByEffector.boolValue;
col.usedByComposite = usedByComposite.boolValue;
}
}
}
if (isInspectingPrefab) {
follower.colliderTable.Clear();
follower.nameTable.Clear();
EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info);
// How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work.
PolygonCollider2D collider = follower.GetComponent<PolygonCollider2D>();
if (collider != null) Debug.LogWarning("Found BoundingBoxFollowerGraphic collider components in prefab. These are disposed and regenerated at runtime.");
} else {
using (new SpineInspectorUtility.BoxScope()) {
if (debugIsExpanded = EditorGUILayout.Foldout(debugIsExpanded, "Debug Colliders")) {
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count));
EditorGUI.BeginChangeCheck();
foreach (KeyValuePair<BoundingBoxAttachment, string> kp in follower.nameTable) {
string attachmentName = kp.Value;
PolygonCollider2D collider = follower.colliderTable[kp.Key];
bool isPlaceholder = attachmentName != kp.Key.Name;
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : string.Format("{0} [{1}]", attachmentName, kp.Key.Name), isPlaceholder ? Icons.skinPlaceholder : Icons.boundingBox), collider.enabled);
}
sceneRepaintRequired |= EditorGUI.EndChangeCheck();
EditorGUI.indentLevel--;
}
}
}
if (follower.Slot == null)
follower.Initialize(false);
bool hasBoneFollower = follower.GetComponent<BoneFollowerGraphic>() != null;
if (!hasBoneFollower) {
bool buttonDisabled = follower.Slot == null;
using (new EditorGUI.DisabledGroupScope(buttonDisabled)) {
addBoneFollower |= SpineInspectorUtility.LargeCenteredButton(AddBoneFollowerLabel, true);
EditorGUILayout.Space();
}
}
if (Event.current.type == EventType.Repaint) {
if (addBoneFollower) {
BoneFollowerGraphic boneFollower = follower.gameObject.AddComponent<BoneFollowerGraphic>();
boneFollower.skeletonGraphic = skeletonGraphicValue;
boneFollower.SetBone(follower.Slot.Data.BoneData.Name);
addBoneFollower = false;
}
if (sceneRepaintRequired) {
SceneView.RepaintAll();
sceneRepaintRequired = false;
}
if (rebuildRequired) {
follower.Initialize();
rebuildRequired = false;
}
}
}
#region Menus
[MenuItem("CONTEXT/SkeletonGraphic/Add BoundingBoxFollowerGraphic GameObject")]
static void AddBoundingBoxFollowerGraphicChild (MenuCommand command) {
GameObject go = AddBoundingBoxFollowerGraphicChild((SkeletonGraphic)command.context);
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollowerGraphic");
}
[MenuItem("CONTEXT/SkeletonGraphic/Add all BoundingBoxFollowerGraphic GameObjects")]
static void AddAllBoundingBoxFollowerGraphicChildren (MenuCommand command) {
List<GameObject> objects = AddAllBoundingBoxFollowerGraphicChildren((SkeletonGraphic)command.context);
foreach (GameObject go in objects)
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollowerGraphic");
}
#endregion
public static GameObject AddBoundingBoxFollowerGraphicChild (SkeletonGraphic skeletonGraphic,
BoundingBoxFollowerGraphic original = null, string name = "BoundingBoxFollowerGraphic",
string slotName = null) {
GameObject go = EditorInstantiation.NewGameObject(name, true);
go.transform.SetParent(skeletonGraphic.transform, false);
go.AddComponent<RectTransform>();
BoundingBoxFollowerGraphic newFollower = go.AddComponent<BoundingBoxFollowerGraphic>();
if (original != null) {
newFollower.slotName = original.slotName;
newFollower.isTrigger = original.isTrigger;
newFollower.usedByEffector = original.usedByEffector;
newFollower.usedByComposite = original.usedByComposite;
newFollower.clearStateOnDisable = original.clearStateOnDisable;
}
if (slotName != null)
newFollower.slotName = slotName;
newFollower.skeletonGraphic = skeletonGraphic;
newFollower.Initialize();
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
return go;
}
public static List<GameObject> AddAllBoundingBoxFollowerGraphicChildren (
SkeletonGraphic skeletonGraphic, BoundingBoxFollowerGraphic original = null) {
List<GameObject> createdGameObjects = new List<GameObject>();
foreach (Skin skin in skeletonGraphic.Skeleton.Data.Skins) {
ICollection<Skin.SkinEntry> attachments = skin.Attachments;
foreach (Skin.SkinEntry entry in attachments) {
BoundingBoxAttachment boundingBoxAttachment = entry.Attachment as BoundingBoxAttachment;
if (boundingBoxAttachment == null)
continue;
int slotIndex = entry.SlotIndex;
Slot slot = skeletonGraphic.Skeleton.Slots.Items[slotIndex];
string slotName = slot.Data.Name;
GameObject go = AddBoundingBoxFollowerGraphicChild(skeletonGraphic,
original, boundingBoxAttachment.Name, slotName);
BoneFollowerGraphic boneFollower = go.AddComponent<BoneFollowerGraphic>();
boneFollower.skeletonGraphic = skeletonGraphic;
boneFollower.SetBone(slot.Data.BoneData.Name);
createdGameObjects.Add(go);
}
}
return createdGameObjects;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c4f5b276299bc048ad00f3cd2d1ea09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,270 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(BoundingBoxFollower))]
public class BoundingBoxFollowerInspector : UnityEditor.Editor {
SerializedProperty skeletonRenderer, slotName,
isTrigger, usedByEffector, usedByComposite, clearStateOnDisable;
BoundingBoxFollower follower;
bool rebuildRequired = false;
bool addBoneFollower = false;
bool sceneRepaintRequired = false;
bool debugIsExpanded;
GUIContent addBoneFollowerLabel;
GUIContent AddBoneFollowerLabel {
get {
if (addBoneFollowerLabel == null) addBoneFollowerLabel = new GUIContent("Add Bone Follower", Icons.bone);
return addBoneFollowerLabel;
}
}
void InitializeEditor () {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
slotName = serializedObject.FindProperty("slotName");
isTrigger = serializedObject.FindProperty("isTrigger");
usedByEffector = serializedObject.FindProperty("usedByEffector");
usedByComposite = serializedObject.FindProperty("usedByComposite");
clearStateOnDisable = serializedObject.FindProperty("clearStateOnDisable");
follower = (BoundingBoxFollower)target;
}
public override void OnInspectorGUI () {
#if !NEW_PREFAB_SYSTEM
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#else
bool isInspectingPrefab = false;
#endif
// Note: when calling InitializeEditor() in OnEnable, it throws exception
// "SerializedObjectNotCreatableException: Object at index 0 is null".
InitializeEditor();
// Try to auto-assign SkeletonRenderer field.
if (skeletonRenderer.objectReferenceValue == null) {
SkeletonRenderer foundSkeletonRenderer = follower.GetComponentInParent<SkeletonRenderer>();
if (foundSkeletonRenderer != null)
Debug.Log("BoundingBoxFollower automatically assigned: " + foundSkeletonRenderer.gameObject.name);
else if (Event.current.type == EventType.Repaint)
Debug.Log("No Spine GameObject detected. Make sure to set this GameObject as a child of the Spine GameObject; or set BoundingBoxFollower's 'Skeleton Renderer' field in the inspector.");
skeletonRenderer.objectReferenceValue = foundSkeletonRenderer;
serializedObject.ApplyModifiedProperties();
InitializeEditor();
}
SkeletonRenderer skeletonRendererValue = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
if (skeletonRendererValue != null && skeletonRendererValue.gameObject == follower.gameObject) {
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
EditorGUILayout.HelpBox("It's ideal to add BoundingBoxFollower to a separate child GameObject of the Spine GameObject.", MessageType.Warning);
if (GUILayout.Button(new GUIContent("Move BoundingBoxFollower to new GameObject", Icons.boundingBox), GUILayout.Height(30f))) {
AddBoundingBoxFollowerChild(skeletonRendererValue, follower);
DestroyImmediate(follower);
return;
}
}
EditorGUILayout.Space();
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(skeletonRenderer);
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
if (EditorGUI.EndChangeCheck()) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
#if !NEW_PREFAB_SYSTEM
if (!isInspectingPrefab)
rebuildRequired = true;
#endif
}
using (new SpineInspectorUtility.LabelWidthScope(150f)) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(isTrigger);
EditorGUILayout.PropertyField(usedByEffector);
EditorGUILayout.PropertyField(usedByComposite);
bool colliderParamChanged = EditorGUI.EndChangeCheck();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(clearStateOnDisable, new GUIContent(clearStateOnDisable.displayName, "Enable this if you are pooling your Spine GameObject"));
bool clearStateChanged = EditorGUI.EndChangeCheck();
if (clearStateChanged || colliderParamChanged) {
serializedObject.ApplyModifiedProperties();
InitializeEditor();
if (colliderParamChanged)
foreach (PolygonCollider2D col in follower.colliderTable.Values) {
col.isTrigger = isTrigger.boolValue;
col.usedByEffector = usedByEffector.boolValue;
col.usedByComposite = usedByComposite.boolValue;
}
}
}
if (isInspectingPrefab) {
follower.colliderTable.Clear();
follower.nameTable.Clear();
EditorGUILayout.HelpBox("BoundingBoxAttachments cannot be previewed in prefabs.", MessageType.Info);
// How do you prevent components from being saved into the prefab? No such HideFlag. DontSaveInEditor | DontSaveInBuild does not work. DestroyImmediate does not work.
PolygonCollider2D collider = follower.GetComponent<PolygonCollider2D>();
if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime.");
} else {
using (new SpineInspectorUtility.BoxScope()) {
if (debugIsExpanded = EditorGUILayout.Foldout(debugIsExpanded, "Debug Colliders")) {
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count));
EditorGUI.BeginChangeCheck();
foreach (KeyValuePair<BoundingBoxAttachment, string> pair in follower.nameTable) {
string attachmentName = pair.Value;
PolygonCollider2D collider = follower.colliderTable[pair.Key];
bool isPlaceholder = attachmentName != pair.Key.Name;
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : string.Format("{0} [{1}]", attachmentName, pair.Key.Name), isPlaceholder ? Icons.skinPlaceholder : Icons.boundingBox), collider.enabled);
}
sceneRepaintRequired |= EditorGUI.EndChangeCheck();
EditorGUI.indentLevel--;
}
}
}
if (follower.Slot == null)
follower.Initialize(false);
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
if (!hasBoneFollower) {
bool buttonDisabled = follower.Slot == null;
using (new EditorGUI.DisabledGroupScope(buttonDisabled)) {
addBoneFollower |= SpineInspectorUtility.LargeCenteredButton(AddBoneFollowerLabel, true);
EditorGUILayout.Space();
}
}
if (Event.current.type == EventType.Repaint) {
if (addBoneFollower) {
BoneFollower boneFollower = follower.gameObject.AddComponent<BoneFollower>();
boneFollower.skeletonRenderer = skeletonRendererValue;
boneFollower.SetBone(follower.Slot.Data.BoneData.Name);
addBoneFollower = false;
}
if (sceneRepaintRequired) {
SceneView.RepaintAll();
sceneRepaintRequired = false;
}
if (rebuildRequired) {
follower.Initialize();
rebuildRequired = false;
}
}
}
#region Menus
[MenuItem("CONTEXT/SkeletonRenderer/Add BoundingBoxFollower GameObject")]
static void AddBoundingBoxFollowerChild (MenuCommand command) {
GameObject go = AddBoundingBoxFollowerChild((SkeletonRenderer)command.context);
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollower");
}
[MenuItem("CONTEXT/SkeletonRenderer/Add all BoundingBoxFollower GameObjects")]
static void AddAllBoundingBoxFollowerChildren (MenuCommand command) {
List<GameObject> objects = AddAllBoundingBoxFollowerChildren((SkeletonRenderer)command.context);
foreach (GameObject go in objects)
Undo.RegisterCreatedObjectUndo(go, "Add BoundingBoxFollower");
}
#endregion
public static GameObject AddBoundingBoxFollowerChild (SkeletonRenderer skeletonRenderer,
BoundingBoxFollower original = null, string name = "BoundingBoxFollower",
string slotName = null) {
GameObject go = EditorInstantiation.NewGameObject(name, true);
go.transform.SetParent(skeletonRenderer.transform, false);
BoundingBoxFollower newFollower = go.AddComponent<BoundingBoxFollower>();
if (original != null) {
newFollower.slotName = original.slotName;
newFollower.isTrigger = original.isTrigger;
newFollower.usedByEffector = original.usedByEffector;
newFollower.usedByComposite = original.usedByComposite;
newFollower.clearStateOnDisable = original.clearStateOnDisable;
}
if (slotName != null)
newFollower.slotName = slotName;
newFollower.skeletonRenderer = skeletonRenderer;
newFollower.Initialize();
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
return go;
}
public static List<GameObject> AddAllBoundingBoxFollowerChildren (
SkeletonRenderer skeletonRenderer, BoundingBoxFollower original = null) {
List<GameObject> createdGameObjects = new List<GameObject>();
foreach (Skin skin in skeletonRenderer.Skeleton.Data.Skins) {
ICollection<Skin.SkinEntry> attachments = skin.Attachments;
foreach (Skin.SkinEntry entry in attachments) {
BoundingBoxAttachment boundingBoxAttachment = entry.Attachment as BoundingBoxAttachment;
if (boundingBoxAttachment == null)
continue;
int slotIndex = entry.SlotIndex;
Slot slot = skeletonRenderer.Skeleton.Slots.Items[slotIndex];
string slotName = slot.Data.Name;
GameObject go = AddBoundingBoxFollowerChild(skeletonRenderer,
original, boundingBoxAttachment.Name, slotName);
BoneFollower boneFollower = go.AddComponent<BoneFollower>();
boneFollower.skeletonRenderer = skeletonRenderer;
boneFollower.SetBone(slot.Data.BoneData.Name);
createdGameObjects.Add(go);
}
}
return createdGameObjects;
}
}
}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 670a3cefa3853bd48b5da53a424fd542
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@ -0,0 +1,187 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 System.Collections;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
using Event = UnityEngine.Event;
[CustomEditor(typeof(PointFollower)), CanEditMultipleObjects]
public class PointFollowerInspector : Editor {
SerializedProperty slotName, pointAttachmentName, skeletonRenderer, followZPosition, followBoneRotation, followSkeletonFlip;
PointFollower targetPointFollower;
bool needsReset;
#region Context Menu Item
[MenuItem("CONTEXT/SkeletonRenderer/Add PointFollower GameObject")]
static void AddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonRenderer skeletonRenderer = cmd.context as SkeletonRenderer;
GameObject go = EditorInstantiation.NewGameObject("PointFollower", true);
Transform t = go.transform;
t.SetParent(skeletonRenderer.transform);
t.localPosition = Vector3.zero;
PointFollower f = go.AddComponent<PointFollower>();
f.skeletonRenderer = skeletonRenderer;
EditorGUIUtility.PingObject(t);
Undo.RegisterCreatedObjectUndo(go, "Add PointFollower");
}
// Validate
[MenuItem("CONTEXT/SkeletonRenderer/Add PointFollower GameObject", true)]
static bool ValidateAddBoneFollowerGameObject (MenuCommand cmd) {
SkeletonRenderer skeletonRenderer = cmd.context as SkeletonRenderer;
return skeletonRenderer.valid;
}
#endregion
void OnEnable () {
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
slotName = serializedObject.FindProperty("slotName");
pointAttachmentName = serializedObject.FindProperty("pointAttachmentName");
targetPointFollower = (PointFollower)target;
if (targetPointFollower.skeletonRenderer != null)
targetPointFollower.skeletonRenderer.Initialize(false);
if (!targetPointFollower.IsValid || needsReset) {
targetPointFollower.Initialize();
targetPointFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
}
public void OnSceneGUI () {
PointFollower tbf = target as PointFollower;
SkeletonRenderer skeletonRendererComponent = tbf.skeletonRenderer;
if (skeletonRendererComponent == null)
return;
Skeleton skeleton = skeletonRendererComponent.skeleton;
Transform skeletonTransform = skeletonRendererComponent.transform;
if (string.IsNullOrEmpty(pointAttachmentName.stringValue)) {
// Draw all active PointAttachments in the current skin
Skin currentSkin = skeleton.Skin;
if (currentSkin != skeleton.Data.DefaultSkin) DrawPointsInSkin(skeleton.Data.DefaultSkin, skeleton, skeletonTransform);
if (currentSkin != null) DrawPointsInSkin(currentSkin, skeleton, skeletonTransform);
} else {
Slot slot = skeleton.FindSlot(slotName.stringValue);
if (slot != null) {
int slotIndex = slot.Data.Index;
PointAttachment point = skeleton.GetAttachment(slotIndex, pointAttachmentName.stringValue) as PointAttachment;
if (point != null) {
DrawPointAttachmentWithLabel(point, slot.Bone, skeletonTransform);
}
}
}
}
static void DrawPointsInSkin (Skin skin, Skeleton skeleton, Transform transform) {
foreach (Skin.SkinEntry skinEntry in skin.Attachments) {
PointAttachment attachment = skinEntry.Attachment as PointAttachment;
if (attachment != null) {
Slot slot = skeleton.Slots.Items[skinEntry.SlotIndex];
DrawPointAttachmentWithLabel(attachment, slot.Bone, transform);
}
}
}
static void DrawPointAttachmentWithLabel (PointAttachment point, Bone bone, Transform transform) {
Vector3 labelOffset = new Vector3(0f, -0.2f, 0f);
SpineHandles.DrawPointAttachment(bone, point, transform);
Handles.Label(labelOffset + point.GetWorldPosition(bone, transform), point.Name, SpineHandles.PointNameStyle);
}
override public void OnInspectorGUI () {
if (serializedObject.isEditingMultipleObjects) {
if (needsReset) {
needsReset = false;
foreach (Object o in targets) {
BoneFollower bf = (BoneFollower)o;
bf.Initialize();
bf.LateUpdate();
}
SceneView.RepaintAll();
}
EditorGUI.BeginChangeCheck();
DrawDefaultInspector();
needsReset |= EditorGUI.EndChangeCheck();
return;
}
if (needsReset && Event.current.type == EventType.Layout) {
targetPointFollower.Initialize();
targetPointFollower.LateUpdate();
needsReset = false;
SceneView.RepaintAll();
}
serializedObject.Update();
DrawDefaultInspector();
// Find Renderer
if (skeletonRenderer.objectReferenceValue == null) {
SkeletonRenderer parentRenderer = targetPointFollower.GetComponentInParent<SkeletonRenderer>();
if (parentRenderer != null && parentRenderer.gameObject != targetPointFollower.gameObject) {
skeletonRenderer.objectReferenceValue = parentRenderer;
Debug.Log("Inspector automatically assigned PointFollower.SkeletonRenderer");
}
}
SkeletonRenderer skeletonRendererReference = skeletonRenderer.objectReferenceValue as SkeletonRenderer;
if (skeletonRendererReference != null) {
if (skeletonRendererReference.gameObject == targetPointFollower.gameObject) {
skeletonRenderer.objectReferenceValue = null;
EditorUtility.DisplayDialog("Invalid assignment.", "PointFollower can only follow a skeleton on a separate GameObject.\n\nCreate a new GameObject for your PointFollower, or choose a SkeletonRenderer from a different GameObject.", "Ok");
}
}
if (!targetPointFollower.IsValid) {
needsReset = true;
}
Event current = Event.current;
bool wasUndo = (current.type == EventType.ValidateCommand && current.commandName == "UndoRedoPerformed");
if (wasUndo)
targetPointFollower.Initialize();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7c7e838a8ec295a4e9c53602f690f42f
timeCreated: 1518163038
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,137 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonAnimation))]
[CanEditMultipleObjects]
public class SkeletonAnimationInspector : SkeletonRendererInspector {
protected SerializedProperty animationName, loop, timeScale, unscaledTime, autoReset;
protected bool wasAnimationParameterChanged = false;
readonly GUIContent LoopLabel = new GUIContent("Loop", "Whether or not .AnimationName should loop. This only applies to the initial animation specified in the inspector, or any subsequent Animations played through .AnimationName. Animations set through state.SetAnimation are unaffected.");
readonly GUIContent TimeScaleLabel = new GUIContent("Time Scale", "The rate at which animations progress over time. 1 means normal speed. 0.5 means 50% speed.");
readonly GUIContent UnscaledTimeLabel = new GUIContent("Unscaled Time",
"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.");
protected override void OnEnable () {
base.OnEnable();
animationName = serializedObject.FindProperty("_animationName");
loop = serializedObject.FindProperty("loop");
timeScale = serializedObject.FindProperty("timeScale");
unscaledTime = serializedObject.FindProperty("unscaledTime");
}
protected override void DrawInspectorGUI (bool multi) {
base.DrawInspectorGUI(multi);
if (!TargetIsValid) return;
bool sameData = SpineInspectorUtility.TargetsUseSameData(serializedObject);
foreach (UnityEngine.Object o in targets)
TrySetAnimation(o as SkeletonAnimation);
EditorGUILayout.Space();
if (!sameData) {
EditorGUILayout.DelayedTextField(animationName);
} else {
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(animationName);
wasAnimationParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
}
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(loop, LoopLabel);
wasAnimationParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
EditorGUILayout.PropertyField(timeScale, TimeScaleLabel);
foreach (UnityEngine.Object o in targets) {
SkeletonAnimation component = o as SkeletonAnimation;
component.timeScale = Mathf.Max(component.timeScale, 0);
}
EditorGUILayout.PropertyField(unscaledTime, UnscaledTimeLabel);
EditorGUILayout.Space();
SkeletonRootMotionParameter();
serializedObject.ApplyModifiedProperties();
}
protected void TrySetAnimation (SkeletonAnimation skeletonAnimation) {
if (skeletonAnimation == null) return;
if (!skeletonAnimation.valid || skeletonAnimation.AnimationState == null)
return;
TrackEntry current = skeletonAnimation.AnimationState.GetCurrent(0);
if (!isInspectingPrefab) {
string activeAnimation = (current != null) ? current.Animation.Name : "";
bool activeLoop = (current != null) ? current.Loop : false;
bool animationParameterChanged = this.wasAnimationParameterChanged &&
((activeAnimation != animationName.stringValue) || (activeLoop != loop.boolValue));
if (animationParameterChanged) {
this.wasAnimationParameterChanged = false;
Skeleton skeleton = skeletonAnimation.Skeleton;
AnimationState state = skeletonAnimation.AnimationState;
if (!Application.isPlaying) {
if (state != null) state.ClearTrack(0);
skeleton.SetToSetupPose();
}
Spine.Animation animationToUse = skeleton.Data.FindAnimation(animationName.stringValue);
if (!Application.isPlaying) {
if (animationToUse != null) {
skeletonAnimation.AnimationState.SetAnimation(0, animationToUse, loop.boolValue);
}
skeletonAnimation.Update(0);
skeletonAnimation.LateUpdate();
requireRepaint = true;
} else {
if (animationToUse != null)
state.SetAnimation(0, animationToUse, loop.boolValue);
else
state.ClearTrack(0);
}
}
// Reflect animationName serialized property in the inspector even if SetAnimation API was used.
if (Application.isPlaying) {
if (current != null && current.Animation != null) {
if (skeletonAnimation.AnimationName != animationName.stringValue)
animationName.stringValue = current.Animation.Name;
}
}
}
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 39fbfef61034ca045b5aa80088e1e8a4
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,159 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.Unity.Examples;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
// This script is not intended for use with code. See spine-unity documentation page for additional information.
[CustomEditor(typeof(SkeletonGraphicCustomMaterials))]
public class SkeletonGraphicCustomMaterialsInspector : UnityEditor.Editor {
List<SkeletonGraphicCustomMaterials.AtlasMaterialOverride> componentCustomMaterialOverrides, _customMaterialOverridesPrev;
List<SkeletonGraphicCustomMaterials.AtlasTextureOverride> componentCustomTextureOverrides, _customTextureOverridesPrev;
SkeletonGraphicCustomMaterials component;
const BindingFlags PrivateInstance = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo RemoveCustomMaterialOverrides, RemoveCustomTextureOverrides, SetCustomMaterialOverrides, SetCustomTextureOverrides;
#region SkeletonGraphic context menu
[MenuItem("CONTEXT/SkeletonGraphic/Add Basic Serialized Custom Materials")]
static void AddSkeletonGraphicCustomMaterials (MenuCommand menuCommand) {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)menuCommand.context;
SkeletonGraphicCustomMaterials newComponent = skeletonGraphic.gameObject.AddComponent<SkeletonGraphicCustomMaterials>();
Undo.RegisterCreatedObjectUndo(newComponent, "Add Basic Serialized Custom Materials");
}
[MenuItem("CONTEXT/SkeletonGraphic/Add Basic Serialized Custom Materials", true)]
static bool AddSkeletonGraphicCustomMaterials_Validate (MenuCommand menuCommand) {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)menuCommand.context;
return (skeletonGraphic.GetComponent<SkeletonGraphicCustomMaterials>() == null);
}
#endregion
void OnEnable () {
Type cm = typeof(SkeletonGraphicCustomMaterials);
RemoveCustomMaterialOverrides = cm.GetMethod("RemoveCustomMaterialOverrides", PrivateInstance);
RemoveCustomTextureOverrides = cm.GetMethod("RemoveCustomTextureOverrides", PrivateInstance);
SetCustomMaterialOverrides = cm.GetMethod("SetCustomMaterialOverrides", PrivateInstance);
SetCustomTextureOverrides = cm.GetMethod("SetCustomTextureOverrides", PrivateInstance);
}
public override void OnInspectorGUI () {
component = (SkeletonGraphicCustomMaterials)target;
SkeletonGraphic skeletonGraphic = component.skeletonGraphic;
// Draw the default inspector
DrawDefaultInspector();
if (serializedObject.isEditingMultipleObjects)
return;
if (componentCustomMaterialOverrides == null) {
Type cm = typeof(SkeletonGraphicCustomMaterials);
componentCustomMaterialOverrides = cm.GetField("customMaterialOverrides", PrivateInstance).GetValue(component) as List<SkeletonGraphicCustomMaterials.AtlasMaterialOverride>;
componentCustomTextureOverrides = cm.GetField("customTextureOverrides", PrivateInstance).GetValue(component) as List<SkeletonGraphicCustomMaterials.AtlasTextureOverride>;
if (componentCustomMaterialOverrides == null) {
Debug.Log("Reflection failed.");
return;
}
}
// Fill with current values at start
if (_customMaterialOverridesPrev == null || _customTextureOverridesPrev == null) {
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customTextureOverridesPrev = CopyList(componentCustomTextureOverrides);
}
// Compare new values with saved. If change is detected:
// store new values, restore old values, remove overrides, restore new values, restore overrides.
// 1. Store new values
var customMaterialOverridesNew = CopyList(componentCustomMaterialOverrides);
var customTextureOverridesNew = CopyList(componentCustomTextureOverrides);
// Detect changes
if (!_customMaterialOverridesPrev.SequenceEqual(customMaterialOverridesNew) ||
!_customTextureOverridesPrev.SequenceEqual(customTextureOverridesNew)) {
// 2. Restore old values
componentCustomMaterialOverrides.Clear();
componentCustomTextureOverrides.Clear();
componentCustomMaterialOverrides.AddRange(_customMaterialOverridesPrev);
componentCustomTextureOverrides.AddRange(_customTextureOverridesPrev);
// 3. Remove overrides
RemoveCustomMaterials();
// 4. Restore new values
componentCustomMaterialOverrides.Clear();
componentCustomTextureOverrides.Clear();
componentCustomMaterialOverrides.AddRange(customMaterialOverridesNew);
componentCustomTextureOverrides.AddRange(customTextureOverridesNew);
// 5. Restore overrides
SetCustomMaterials();
if (skeletonGraphic != null)
skeletonGraphic.LateUpdate();
}
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customTextureOverridesPrev = CopyList(componentCustomTextureOverrides);
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Clear and Reapply Changes", tooltip: "Removes all non-serialized overrides in the SkeletonGraphic and reapplies the overrides on this component."))) {
if (skeletonGraphic != null) {
skeletonGraphic.CustomMaterialOverride.Clear();
skeletonGraphic.CustomTextureOverride.Clear();
RemoveCustomMaterials();
SetCustomMaterials();
skeletonGraphic.LateUpdate();
}
}
}
void RemoveCustomMaterials () {
RemoveCustomMaterialOverrides.Invoke(component, null);
RemoveCustomTextureOverrides.Invoke(component, null);
}
void SetCustomMaterials () {
SetCustomMaterialOverrides.Invoke(component, null);
SetCustomTextureOverrides.Invoke(component, null);
}
static List<T> CopyList<T> (List<T> list) {
return list.GetRange(0, list.Count);
}
}
}

View File

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

View File

@ -0,0 +1,897 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2018_2_OR_NEWER
#define HAS_CULL_TRANSPARENT_MESH
#endif
#if UNITY_2017_2_OR_NEWER
#define NEWPLAYMODECALLBACKS
#endif
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonGraphic))]
[CanEditMultipleObjects]
public class SkeletonGraphicInspector : UnityEditor.Editor {
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
const string ReloadButtonString = "Reload";
protected GUIContent SkeletonDataAssetLabel, UpdateTimingLabel;
static GUILayoutOption reloadButtonWidth;
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
SerializedProperty material, color;
SerializedProperty additiveMaterial, multiplyMaterial, screenMaterial;
SerializedProperty skeletonDataAsset, initialSkinName;
SerializedProperty startingAnimation, startingLoop, timeScale, freeze,
updateTiming, updateWhenInvisible, unscaledTime, layoutScaleMode, editReferenceRect;
SerializedProperty physicsPositionInheritanceFactor, physicsRotationInheritanceFactor, physicsMovementRelativeTo;
SerializedProperty initialFlipX, initialFlipY;
SerializedProperty meshGeneratorSettings;
SerializedProperty useClipping, zSpacing, tintBlack, canvasGroupCompatible, pmaVertexColors, addNormals, calculateTangents, immutableTriangles;
SerializedProperty allowMultipleCanvasRenderers, separatorSlotNames, enableSeparatorSlots,
updateSeparatorPartLocation, updateSeparatorPartScale;
SerializedProperty raycastTarget, maskable;
readonly GUIContent UseClippingLabel = new GUIContent("Use Clipping",
"When disabled, clipping attachments are ignored. This may be used to save performance.");
readonly GUIContent ZSpacingLabel = new GUIContent("Z Spacing",
"A value other than 0 adds a space between each rendered attachment to prevent Z Fighting when using shaders" +
" that read or write to the depth buffer. Large values may cause unwanted parallax and spaces depending on " +
"camera setup.");
readonly GUIContent TintBlackLabel = new GUIContent("Tint Black (!)",
"Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret " +
"UV2 and UV3 as black tint colors for this effect to work. You may then want to use the " +
"[Spine/SkeletonGraphic Tint Black] shader.");
readonly GUIContent CanvasGroupCompatibleLabel = new GUIContent("CanvasGroup Compatible",
"Enable when using SkeletonGraphic under a CanvasGroup. " +
"When enabled, PMA Vertex Color alpha value is stored at uv2.g instead of color.a to capture " +
"CanvasGroup modifying color.a. Also helps to detect correct parameter setting combinations.");
readonly GUIContent PMAVertexColorsLabel = new GUIContent("PMA Vertex Colors",
"Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader.");
readonly GUIContent AddNormalsLabel = new GUIContent("Add Normals",
"Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the " +
"shader to assume a single normal value for the whole mesh.");
readonly GUIContent CalculateTangentsLabel = new GUIContent("Solve Tangents",
"Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that " +
"require vertex tangents.");
readonly GUIContent ImmutableTrianglesLabel = new GUIContent("Immutable Triangles",
"Enable to optimize rendering for skeletons that never change attachment visbility");
readonly GUIContent UnscaledTimeLabel = new GUIContent("Unscaled Time",
"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 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 (X,Y) 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.");
SkeletonGraphic thisSkeletonGraphic;
protected bool isInspectingPrefab;
protected bool slotsReapplyRequired = false;
protected bool forceReloadQueued = false;
protected bool TargetIsValid {
get {
if (serializedObject.isEditingMultipleObjects) {
foreach (UnityEngine.Object c in targets) {
SkeletonGraphic component = (SkeletonGraphic)c;
if (!component.IsValid)
return false;
}
return true;
} else {
SkeletonGraphic component = (SkeletonGraphic)target;
return component.IsValid;
}
}
}
void OnEnable () {
#if NEW_PREFAB_SYSTEM
isInspectingPrefab = false;
#else
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#endif
SpineEditorUtilities.ConfirmInitialization();
// Labels
SkeletonDataAssetLabel = new GUIContent("SkeletonData Asset", Icons.spine);
UpdateTimingLabel = new GUIContent("Animation Update", "Whether to update the animation in normal Update (the default), physics step FixedUpdate, or manually via a user call.");
SerializedObject so = this.serializedObject;
thisSkeletonGraphic = target as SkeletonGraphic;
// MaskableGraphic
material = so.FindProperty("m_Material");
color = so.FindProperty("m_SkeletonColor");
raycastTarget = so.FindProperty("m_RaycastTarget");
maskable = so.FindProperty("m_Maskable");
// SkeletonRenderer
additiveMaterial = so.FindProperty("additiveMaterial");
multiplyMaterial = so.FindProperty("multiplyMaterial");
screenMaterial = so.FindProperty("screenMaterial");
skeletonDataAsset = so.FindProperty("skeletonDataAsset");
initialSkinName = so.FindProperty("initialSkinName");
initialFlipX = so.FindProperty("initialFlipX");
initialFlipY = so.FindProperty("initialFlipY");
// SkeletonAnimation
startingAnimation = so.FindProperty("startingAnimation");
startingLoop = so.FindProperty("startingLoop");
timeScale = so.FindProperty("timeScale");
unscaledTime = so.FindProperty("unscaledTime");
freeze = so.FindProperty("freeze");
updateTiming = so.FindProperty("updateTiming");
updateWhenInvisible = so.FindProperty("updateWhenInvisible");
layoutScaleMode = so.FindProperty("layoutScaleMode");
editReferenceRect = so.FindProperty("editReferenceRect");
physicsPositionInheritanceFactor = so.FindProperty("physicsPositionInheritanceFactor");
physicsRotationInheritanceFactor = so.FindProperty("physicsRotationInheritanceFactor");
physicsMovementRelativeTo = so.FindProperty("physicsMovementRelativeTo");
meshGeneratorSettings = so.FindProperty("meshGenerator").FindPropertyRelative("settings");
meshGeneratorSettings.isExpanded = SkeletonRendererInspector.advancedFoldout;
useClipping = meshGeneratorSettings.FindPropertyRelative("useClipping");
zSpacing = meshGeneratorSettings.FindPropertyRelative("zSpacing");
tintBlack = meshGeneratorSettings.FindPropertyRelative("tintBlack");
canvasGroupCompatible = meshGeneratorSettings.FindPropertyRelative("canvasGroupCompatible");
pmaVertexColors = meshGeneratorSettings.FindPropertyRelative("pmaVertexColors");
calculateTangents = meshGeneratorSettings.FindPropertyRelative("calculateTangents");
addNormals = meshGeneratorSettings.FindPropertyRelative("addNormals");
immutableTriangles = meshGeneratorSettings.FindPropertyRelative("immutableTriangles");
allowMultipleCanvasRenderers = so.FindProperty("allowMultipleCanvasRenderers");
updateSeparatorPartLocation = so.FindProperty("updateSeparatorPartLocation");
updateSeparatorPartScale = so.FindProperty("updateSeparatorPartScale");
enableSeparatorSlots = so.FindProperty("enableSeparatorSlots");
separatorSlotNames = so.FindProperty("separatorSlotNames");
separatorSlotNames.isExpanded = true;
#if NEWPLAYMODECALLBACKS
EditorApplication.playModeStateChanged += OnPlaymodeChanged;
#else
EditorApplication.playmodeStateChanged += OnPlaymodeChanged;
#endif
}
void OnDisable () {
#if NEWPLAYMODECALLBACKS
EditorApplication.playModeStateChanged -= OnPlaymodeChanged;
#else
EditorApplication.playmodeStateChanged -= OnPlaymodeChanged;
#endif
DisableEditReferenceRectMode();
}
#if NEWPLAYMODECALLBACKS
void OnPlaymodeChanged (PlayModeStateChange mode) {
#else
void OnPlaymodeChanged () {
#endif
DisableEditReferenceRectMode();
}
void DisableEditReferenceRectMode () {
foreach (UnityEngine.Object c in targets) {
SkeletonGraphic component = (SkeletonGraphic)c;
component.EditReferenceRect = false;
}
}
public override void OnInspectorGUI () {
if (UnityEngine.Event.current.type == EventType.Layout) {
if (forceReloadQueued) {
forceReloadQueued = false;
foreach (UnityEngine.Object c in targets) {
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonGraphic);
}
} else {
foreach (UnityEngine.Object c in targets) {
SkeletonGraphic component = c as SkeletonGraphic;
if (!component.IsValid) {
SpineEditorUtilities.ReinitializeComponent(component);
if (!component.IsValid) continue;
}
}
}
}
bool wasChanged = false;
EditorGUI.BeginChangeCheck();
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) {
SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel);
if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth))
forceReloadQueued = true;
}
if (thisSkeletonGraphic.skeletonDataAsset == null) {
EditorGUILayout.HelpBox("You need to assign a SkeletonData asset first.", MessageType.Info);
serializedObject.ApplyModifiedProperties();
serializedObject.Update();
return;
}
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(thisSkeletonGraphic.skeletonDataAsset)) {
EditorGUILayout.HelpBox("SkeletonData asset error. Please check SkeletonData asset.", MessageType.Error);
return;
}
using (new SpineInspectorUtility.LabelWidthScope(100)) {
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.PropertyField(material);
if (GUILayout.Button("Detect", EditorStyles.miniButton, GUILayout.Width(67f))) {
Undo.RecordObjects(targets, "Detect Material");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectMaterial((SkeletonGraphic)skeletonGraphic);
}
}
}
EditorGUILayout.PropertyField(color);
}
string errorMessage = null;
if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic(thisSkeletonGraphic, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
}
bool isSingleRendererOnly = (!allowMultipleCanvasRenderers.hasMultipleDifferentValues && allowMultipleCanvasRenderers.boolValue == false);
bool isSeparationEnabledButNotMultipleRenderers =
isSingleRendererOnly && (!enableSeparatorSlots.hasMultipleDifferentValues && enableSeparatorSlots.boolValue == true);
bool meshRendersIncorrectlyWithSingleRenderer =
isSingleRendererOnly && SkeletonHasMultipleSubmeshes();
if (isSeparationEnabledButNotMultipleRenderers || meshRendersIncorrectlyWithSingleRenderer)
meshGeneratorSettings.isExpanded = true;
using (new SpineInspectorUtility.BoxScope()) {
EditorGUILayout.PropertyField(meshGeneratorSettings, SpineInspectorUtility.TempContent("Advanced..."), includeChildren: false);
SkeletonRendererInspector.advancedFoldout = meshGeneratorSettings.isExpanded;
if (meshGeneratorSettings.isExpanded) {
EditorGUILayout.Space();
using (new SpineInspectorUtility.IndentScope()) {
DrawMeshSettings();
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PropertyField(allowMultipleCanvasRenderers, SpineInspectorUtility.TempContent("Multiple CanvasRenderers"));
if (GUILayout.Button(new GUIContent("Trim Renderers", "Remove currently unused CanvasRenderer GameObjects. These will be regenerated whenever needed."),
EditorStyles.miniButton, GUILayout.Width(100f))) {
Undo.RecordObjects(targets, "Trim Renderers");
foreach (UnityEngine.Object skeletonGraphic in targets) {
((SkeletonGraphic)skeletonGraphic).TrimRenderers();
}
}
EditorGUILayout.EndHorizontal();
BlendModeMaterials blendModeMaterials = thisSkeletonGraphic.skeletonDataAsset.blendModeMaterials;
if (allowMultipleCanvasRenderers.boolValue == true && blendModeMaterials.RequiresBlendModeMaterials) {
using (new SpineInspectorUtility.IndentScope()) {
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Blend Mode Materials", EditorStyles.boldLabel);
if (GUILayout.Button(new GUIContent("Detect", "Auto-Assign Blend Mode Materials according to Vertex Data and Texture settings."),
EditorStyles.miniButton, GUILayout.Width(100f))) {
Undo.RecordObjects(targets, "Detect Blend Mode Materials");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectBlendModeMaterials((SkeletonGraphic)skeletonGraphic);
}
}
EditorGUILayout.EndHorizontal();
bool usesAdditiveMaterial = blendModeMaterials.applyAdditiveMaterial;
bool pmaVertexColors = thisSkeletonGraphic.MeshGenerator.settings.pmaVertexColors;
if (pmaVertexColors)
using (new EditorGUI.DisabledGroupScope(true)) {
EditorGUILayout.LabelField("Additive Material - Unused with PMA Vertex Colors", EditorStyles.label);
}
else if (usesAdditiveMaterial)
EditorGUILayout.PropertyField(additiveMaterial, SpineInspectorUtility.TempContent("Additive Material", null, "SkeletonGraphic Material for 'Additive' blend mode slots. Unused when 'PMA Vertex Colors' is enabled."));
else
using (new EditorGUI.DisabledGroupScope(true)) {
EditorGUILayout.LabelField("No Additive Mat - 'Apply Additive Material' disabled at SkeletonDataAsset", EditorStyles.label);
}
EditorGUILayout.PropertyField(multiplyMaterial, SpineInspectorUtility.TempContent("Multiply Material", null, "SkeletonGraphic Material for 'Multiply' blend mode slots."));
EditorGUILayout.PropertyField(screenMaterial, SpineInspectorUtility.TempContent("Screen Material", null, "SkeletonGraphic Material for 'Screen' blend mode slots."));
}
}
EditorGUILayout.PropertyField(updateTiming, UpdateTimingLabel);
EditorGUILayout.PropertyField(updateWhenInvisible);
}
// warning box
if (isSeparationEnabledButNotMultipleRenderers) {
using (new SpineInspectorUtility.BoxScope()) {
meshGeneratorSettings.isExpanded = true;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("'Multiple Canvas Renderers' must be enabled\nwhen 'Enable Separation' is enabled.", Icons.warning), GUILayout.Height(42), GUILayout.Width(340));
}
} else if (meshRendersIncorrectlyWithSingleRenderer) {
using (new SpineInspectorUtility.BoxScope()) {
meshGeneratorSettings.isExpanded = true;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("This mesh uses multiple atlas pages or blend modes.\n" +
"You need to enable 'Multiple Canvas Renderers'\n" +
"for correct rendering. Consider packing\n" +
"attachments to a single atlas page if possible.", Icons.warning), GUILayout.Height(60), GUILayout.Width(380));
}
}
}
EditorGUILayout.Space();
SeparatorsField(separatorSlotNames, enableSeparatorSlots, updateSeparatorPartLocation, updateSeparatorPartScale);
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
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);
}
}
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(initialSkinName);
{
Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent("Initial Flip"));
rect.x += EditorGUIUtility.labelWidth;
rect.width = 30f;
SpineInspectorUtility.ToggleLeft(rect, initialFlipX, SpineInspectorUtility.TempContent("X", tooltip: "initialFlipX"));
rect.x += 35f;
SpineInspectorUtility.ToggleLeft(rect, initialFlipY, SpineInspectorUtility.TempContent("Y", tooltip: "initialFlipY"));
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Animation", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(startingAnimation);
EditorGUILayout.PropertyField(startingLoop);
EditorGUILayout.PropertyField(timeScale);
EditorGUILayout.PropertyField(unscaledTime, UnscaledTimeLabel);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(freeze);
EditorGUILayout.Space();
SkeletonRendererInspector.SkeletonRootMotionParameter(targets);
EditorGUILayout.Space();
EditorGUILayout.LabelField("UI", EditorStyles.boldLabel);
EditorGUILayout.PropertyField(raycastTarget);
if (maskable != null) EditorGUILayout.PropertyField(maskable);
EditorGUILayout.PropertyField(layoutScaleMode);
using (new EditorGUI.DisabledGroupScope(layoutScaleMode.intValue == 0)) {
EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
EditorGUILayout.PrefixLabel("Edit Layout Bounds");
editReferenceRect.boolValue = GUILayout.Toggle(editReferenceRect.boolValue,
EditorGUIUtility.IconContent("EditCollider"), EditorStyles.miniButton, GUILayout.Width(40f));
EditorGUILayout.EndHorizontal();
}
if (layoutScaleMode.intValue == 0) {
editReferenceRect.boolValue = false;
}
using (new EditorGUI.DisabledGroupScope(editReferenceRect.boolValue == false && layoutScaleMode.intValue != 0)) {
EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
EditorGUILayout.PrefixLabel("Match RectTransform with Mesh");
if (GUILayout.Button("Match", EditorStyles.miniButton, GUILayout.Width(65f))) {
foreach (UnityEngine.Object skeletonGraphic in targets) {
MatchRectTransformWithBounds((SkeletonGraphic)skeletonGraphic);
}
}
EditorGUILayout.EndHorizontal();
}
if (TargetIsValid && !isInspectingPrefab) {
EditorGUILayout.Space();
if (SpineInspectorUtility.CenteredButton(new GUIContent("Add Skeleton Utility", Icons.skeletonUtility), 21, true, 200f))
foreach (UnityEngine.Object t in targets) {
Component component = t as Component;
if (component.GetComponent<SkeletonUtility>() == null) {
component.gameObject.AddComponent<SkeletonUtility>();
}
}
}
wasChanged |= EditorGUI.EndChangeCheck();
if (wasChanged) {
serializedObject.ApplyModifiedProperties();
slotsReapplyRequired = true;
}
if (slotsReapplyRequired && UnityEngine.Event.current.type == EventType.Repaint) {
foreach (UnityEngine.Object target in targets) {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;
skeletonGraphic.ReapplySeparatorSlotNames();
skeletonGraphic.LateUpdate();
SceneView.RepaintAll();
}
slotsReapplyRequired = false;
}
}
protected void DrawMeshSettings () {
EditorGUILayout.PropertyField(useClipping, UseClippingLabel);
const float MinZSpacing = -0.1f;
const float MaxZSpacing = 0f;
EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing, ZSpacingLabel);
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon<MeshFilter>()), EditorStyles.boldLabel);
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
if (GUILayout.Button("Detect", EditorStyles.miniButton, GUILayout.Width(65f))) {
Undo.RecordObjects(targets, "Detect Tint Black");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectTintBlack((SkeletonGraphic)skeletonGraphic);
}
}
}
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.PropertyField(canvasGroupCompatible, CanvasGroupCompatibleLabel);
if (GUILayout.Button("Detect", EditorStyles.miniButton, GUILayout.Width(65f))) {
Undo.RecordObjects(targets, "Detect CanvasGroup Compatible");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectCanvasGroupCompatible((SkeletonGraphic)skeletonGraphic);
}
}
}
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel);
if (GUILayout.Button("Detect", EditorStyles.miniButton, GUILayout.Width(65f))) {
Undo.RecordObjects(targets, "Detect PMA Vertex Colors");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectPMAVertexColors((SkeletonGraphic)skeletonGraphic);
}
}
}
using (new EditorGUILayout.HorizontalScope()) {
GUILayout.FlexibleSpace();
if (GUILayout.Button("Detect Settings", EditorStyles.miniButton, GUILayout.Width(100f))) {
Undo.RecordObjects(targets, "Detect Settings");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectTintBlack((SkeletonGraphic)skeletonGraphic);
DetectCanvasGroupCompatible((SkeletonGraphic)skeletonGraphic);
DetectPMAVertexColors((SkeletonGraphic)skeletonGraphic);
}
}
if (GUILayout.Button("Detect Material", EditorStyles.miniButton, GUILayout.Width(100f))) {
Undo.RecordObjects(targets, "Detect Material");
foreach (UnityEngine.Object skeletonGraphic in targets) {
DetectMaterial((SkeletonGraphic)skeletonGraphic);
}
}
}
EditorGUILayout.PropertyField(addNormals, AddNormalsLabel);
EditorGUILayout.PropertyField(calculateTangents, CalculateTangentsLabel);
EditorGUILayout.PropertyField(immutableTriangles, ImmutableTrianglesLabel);
}
}
protected bool SkeletonHasMultipleSubmeshes () {
foreach (UnityEngine.Object target in targets) {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;
if (skeletonGraphic.HasMultipleSubmeshInstructions())
return true;
}
return false;
}
protected void OnSceneGUI () {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)target;
if (skeletonGraphic.layoutScaleMode != SkeletonGraphic.LayoutMode.None) {
if (skeletonGraphic.EditReferenceRect) {
SpineHandles.DrawRectTransformRect(skeletonGraphic, Color.gray);
SpineHandles.DrawReferenceRect(skeletonGraphic, Color.green);
} else {
SpineHandles.DrawReferenceRect(skeletonGraphic, Color.blue);
}
}
SpineHandles.DrawPivotOffsetHandle(skeletonGraphic, Color.green);
}
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
FieldInfo field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
field.SetValue(skeletonRenderer, newSlotNames);
}
public static string[] GetSeparatorSlotNames (SkeletonRenderer skeletonRenderer) {
FieldInfo field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
return field.GetValue(skeletonRenderer) as string[];
}
public static void SeparatorsField (SerializedProperty separatorSlotNames, SerializedProperty enableSeparatorSlots,
SerializedProperty updateSeparatorPartLocation, SerializedProperty updateSeparatorPartScale) {
bool multi = separatorSlotNames.serializedObject.isEditingMultipleObjects;
bool hasTerminalSlot = false;
if (!multi) {
ISkeletonComponent sr = separatorSlotNames.serializedObject.targetObject as ISkeletonComponent;
Skeleton skeleton = sr.Skeleton;
int lastSlot = skeleton.Slots.Count - 1;
if (skeleton != null) {
for (int i = 0, n = separatorSlotNames.arraySize; i < n; i++) {
string slotName = separatorSlotNames.GetArrayElementAtIndex(i).stringValue;
SlotData slot = skeleton.Data.FindSlot(slotName);
int index = slot != null ? slot.Index : -1;
if (index == 0 || index == lastSlot) {
hasTerminalSlot = true;
break;
}
}
}
}
string terminalSlotWarning = hasTerminalSlot ? " (!)" : "";
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
const string SeparatorsDescription = "Stored names of slots where the Skeleton's render will be split into different batches. This is used by separate components that split the render into different MeshRenderers or GameObjects.";
if (separatorSlotNames.isExpanded) {
EditorGUILayout.PropertyField(separatorSlotNames, SpineInspectorUtility.TempContent(separatorSlotNames.displayName + terminalSlotWarning, Icons.slotRoot, SeparatorsDescription), true);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("+", GUILayout.MaxWidth(28f), GUILayout.MaxHeight(15f))) {
separatorSlotNames.arraySize++;
}
GUILayout.EndHorizontal();
} else
EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + string.Format("{0} [{1}]", terminalSlotWarning, separatorSlotNames.arraySize), SeparatorsDescription), true);
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.PropertyField(enableSeparatorSlots, SpineInspectorUtility.TempContent("Enable Separation", tooltip: "Whether to enable separation at the above separator slots."));
EditorGUILayout.PropertyField(updateSeparatorPartLocation, SpineInspectorUtility.TempContent("Update Part Location", tooltip: "Update separator part GameObject location to match the position of the SkeletonGraphic. This can be helpful when re-parenting parts to a different GameObject."));
EditorGUILayout.PropertyField(updateSeparatorPartScale, SpineInspectorUtility.TempContent("Update Part Scale", tooltip: "Update separator part GameObject scale to match the scale (lossyScale) of the SkeletonGraphic. This can be helpful when re-parenting parts to a different GameObject."));
}
}
}
#region Auto Detect Setting
static void DetectTintBlack (SkeletonGraphic skeletonGraphic) {
bool requiresTintBlack = HasTintBlackSlot(skeletonGraphic);
if (requiresTintBlack)
Debug.Log(string.Format("Found Tint-Black slot at '{0}'", skeletonGraphic));
else
Debug.Log(string.Format("No Tint-Black slot found at '{0}'", skeletonGraphic));
skeletonGraphic.MeshGenerator.settings.tintBlack = requiresTintBlack;
}
static bool HasTintBlackSlot (SkeletonGraphic skeletonGraphic) {
SlotData[] slotsItems = skeletonGraphic.SkeletonData.Slots.Items;
for (int i = 0, count = skeletonGraphic.SkeletonData.Slots.Count; i < count; ++i) {
SlotData slotData = slotsItems[i];
if (slotData.HasSecondColor)
return true;
}
return false;
}
static void DetectCanvasGroupCompatible (SkeletonGraphic skeletonGraphic) {
bool requiresCanvasGroupCompatible = IsBelowCanvasGroup(skeletonGraphic);
if (requiresCanvasGroupCompatible)
Debug.Log(string.Format("Skeleton is a child of CanvasGroup: '{0}'", skeletonGraphic));
else
Debug.Log(string.Format("Skeleton is not a child of CanvasGroup: '{0}'", skeletonGraphic));
skeletonGraphic.MeshGenerator.settings.canvasGroupCompatible = requiresCanvasGroupCompatible;
}
static bool IsBelowCanvasGroup (SkeletonGraphic skeletonGraphic) {
return skeletonGraphic.gameObject.GetComponentInParent<CanvasGroup>() != null;
}
static void DetectPMAVertexColors (SkeletonGraphic skeletonGraphic) {
MeshGenerator.Settings settings = skeletonGraphic.MeshGenerator.settings;
bool usesSpineShader = MaterialChecks.UsesSpineShader(skeletonGraphic.material);
if (!usesSpineShader) {
Debug.Log(string.Format("Skeleton is not using a Spine shader, thus the shader is likely " +
"not using PMA vertex color: '{0}'", skeletonGraphic));
skeletonGraphic.MeshGenerator.settings.pmaVertexColors = false;
return;
}
bool requiresPMAVertexColorsDisabled = settings.canvasGroupCompatible && !settings.tintBlack;
if (requiresPMAVertexColorsDisabled) {
Debug.Log(string.Format("Skeleton requires PMA Vertex Colors disabled: '{0}'", skeletonGraphic));
skeletonGraphic.MeshGenerator.settings.pmaVertexColors = false;
} else {
Debug.Log(string.Format("Skeleton requires or permits PMA Vertex Colors enabled: '{0}'", skeletonGraphic));
skeletonGraphic.MeshGenerator.settings.pmaVertexColors = true;
}
}
static bool IsSkeletonTexturePMA (SkeletonGraphic skeletonGraphic, out bool detectionSucceeded) {
Texture texture = skeletonGraphic.mainTexture;
string texturePath = AssetDatabase.GetAssetPath(texture.GetInstanceID());
TextureImporter importer = (TextureImporter)TextureImporter.GetAtPath(texturePath);
if (importer.alphaIsTransparency != importer.sRGBTexture) {
Debug.LogWarning(string.Format("Texture '{0}' at skeleton '{1}' is neither configured correctly for " +
"PMA nor Straight Alpha.", texture, skeletonGraphic), texture);
detectionSucceeded = false;
return false;
}
detectionSucceeded = true;
bool isPMATexture = !importer.alphaIsTransparency && !importer.sRGBTexture;
return isPMATexture;
}
static void DetectMaterial (SkeletonGraphic skeletonGraphic) {
MeshGenerator.Settings settings = skeletonGraphic.MeshGenerator.settings;
bool detectionSucceeded;
bool usesPMATexture = IsSkeletonTexturePMA(skeletonGraphic, out detectionSucceeded);
if (!detectionSucceeded) {
Debug.LogWarning(string.Format("Unable to assign Material for skeleton '{0}'.", skeletonGraphic), skeletonGraphic);
return;
}
Material newMaterial = null;
if (usesPMATexture) {
if (settings.tintBlack) {
if (settings.canvasGroupCompatible)
newMaterial = MaterialWithName("SkeletonGraphicTintBlack-CanvasGroup");
else
newMaterial = MaterialWithName("SkeletonGraphicTintBlack");
} else { // not tintBlack
if (settings.canvasGroupCompatible)
newMaterial = MaterialWithName("SkeletonGraphicDefault-CanvasGroup");
else
newMaterial = MaterialWithName("SkeletonGraphicDefault");
}
} else { // straight alpha texture
if (settings.tintBlack) {
if (settings.canvasGroupCompatible)
newMaterial = MaterialWithName("SkeletonGraphicTintBlack-CanvasGroupStraight");
else
newMaterial = MaterialWithName("SkeletonGraphicTintBlack-Straight");
} else { // not tintBlack
if (settings.canvasGroupCompatible)
newMaterial = MaterialWithName("SkeletonGraphicDefault-CanvasGroupStraight");
else
newMaterial = MaterialWithName("SkeletonGraphicDefault-Straight");
}
}
if (newMaterial != null) {
Debug.Log(string.Format("Assigning material '{0}' at skeleton '{1}'",
newMaterial, skeletonGraphic), newMaterial);
skeletonGraphic.material = newMaterial;
}
}
static void DetectBlendModeMaterials (SkeletonGraphic skeletonGraphic) {
bool detectionSucceeded;
bool usesPMATexture = IsSkeletonTexturePMA(skeletonGraphic, out detectionSucceeded);
if (!detectionSucceeded) {
Debug.LogWarning(string.Format("Unable to assign Blend Mode materials for skeleton '{0}'.", skeletonGraphic), skeletonGraphic);
return;
}
DetectBlendModeMaterial(skeletonGraphic, BlendMode.Additive, usesPMATexture);
DetectBlendModeMaterial(skeletonGraphic, BlendMode.Multiply, usesPMATexture);
DetectBlendModeMaterial(skeletonGraphic, BlendMode.Screen, usesPMATexture);
}
static void DetectBlendModeMaterial (SkeletonGraphic skeletonGraphic, BlendMode blendMode, bool usesPMATexture) {
MeshGenerator.Settings settings = skeletonGraphic.MeshGenerator.settings;
string optionalTintBlack = settings.tintBlack ? "TintBlack" : "";
string blendModeString = blendMode.ToString();
string optionalDash = settings.canvasGroupCompatible || !usesPMATexture ? "-" : "";
string optionalCanvasGroup = settings.canvasGroupCompatible ? "CanvasGroup" : "";
string optionalStraight = !usesPMATexture ? "Straight" : "";
string materialName = string.Format("SkeletonGraphic{0}{1}{2}{3}{4}",
optionalTintBlack, blendModeString, optionalDash, optionalCanvasGroup, optionalStraight);
Material newMaterial = MaterialWithName(materialName);
if (newMaterial != null) {
switch (blendMode) {
case BlendMode.Additive:
skeletonGraphic.additiveMaterial = newMaterial;
break;
case BlendMode.Multiply:
skeletonGraphic.multiplyMaterial = newMaterial;
break;
case BlendMode.Screen:
skeletonGraphic.screenMaterial = newMaterial;
break;
}
}
}
#endregion
#region Menus
[MenuItem("CONTEXT/SkeletonGraphic/Match RectTransform with Mesh Bounds")]
static void MatchRectTransformWithBounds (MenuCommand command) {
SkeletonGraphic skeletonGraphic = (SkeletonGraphic)command.context;
MatchRectTransformWithBounds(skeletonGraphic);
}
static void MatchRectTransformWithBounds (SkeletonGraphic skeletonGraphic) {
if (!skeletonGraphic.MatchRectTransformWithBounds())
Debug.Log("Mesh was not previously generated.");
}
[MenuItem("GameObject/Spine/SkeletonGraphic (UnityUI)", false, 15)]
static public void SkeletonGraphicCreateMenuItem () {
GameObject parentGameObject = Selection.activeObject as GameObject;
RectTransform parentTransform = parentGameObject == null ? null : parentGameObject.GetComponent<RectTransform>();
if (parentTransform == null)
Debug.LogWarning("Your new SkeletonGraphic will not be visible until it is placed under a Canvas");
GameObject gameObject = NewSkeletonGraphicGameObject("New SkeletonGraphic");
gameObject.transform.SetParent(parentTransform, false);
EditorUtility.FocusProjectWindow();
Selection.activeObject = gameObject;
EditorGUIUtility.PingObject(Selection.activeObject);
}
// SpineEditorUtilities.InstantiateDelegate. Used by drag and drop.
public static Component SpawnSkeletonGraphicFromDrop (SkeletonDataAsset data) {
return InstantiateSkeletonGraphic(data);
}
public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, string skinName) {
return InstantiateSkeletonGraphic(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName));
}
public static SkeletonGraphic InstantiateSkeletonGraphic (SkeletonDataAsset skeletonDataAsset, Skin skin = null) {
string spineGameObjectName = string.Format("SkeletonGraphic ({0})", skeletonDataAsset.name.Replace("_SkeletonData", ""));
GameObject go = NewSkeletonGraphicGameObject(spineGameObjectName);
SkeletonGraphic graphic = go.GetComponent<SkeletonGraphic>();
graphic.skeletonDataAsset = skeletonDataAsset;
SkeletonData data = skeletonDataAsset.GetSkeletonData(true);
if (data == null) {
for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) {
string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]);
skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase));
}
data = skeletonDataAsset.GetSkeletonData(true);
}
skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0];
graphic.MeshGenerator.settings.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing;
graphic.startingLoop = SpineEditorUtilities.Preferences.defaultInstantiateLoop;
graphic.PhysicsPositionInheritanceFactor = SpineEditorUtilities.Preferences.defaultPhysicsPositionInheritance;
graphic.PhysicsRotationInheritanceFactor = SpineEditorUtilities.Preferences.defaultPhysicsRotationInheritance;
graphic.Initialize(false);
if (skin != null) graphic.Skeleton.SetSkin(skin);
graphic.initialSkinName = skin.Name;
graphic.Skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
graphic.UpdateMesh();
return graphic;
}
static GameObject NewSkeletonGraphicGameObject (string gameObjectName) {
GameObject go = EditorInstantiation.NewGameObject(gameObjectName, true, typeof(RectTransform), typeof(CanvasRenderer), typeof(SkeletonGraphic));
SkeletonGraphic graphic = go.GetComponent<SkeletonGraphic>();
graphic.material = SkeletonGraphicInspector.DefaultSkeletonGraphicMaterial;
graphic.additiveMaterial = SkeletonGraphicInspector.DefaultSkeletonGraphicAdditiveMaterial;
graphic.multiplyMaterial = SkeletonGraphicInspector.DefaultSkeletonGraphicMultiplyMaterial;
graphic.screenMaterial = SkeletonGraphicInspector.DefaultSkeletonGraphicScreenMaterial;
#if HAS_CULL_TRANSPARENT_MESH
CanvasRenderer canvasRenderer = go.GetComponent<CanvasRenderer>();
canvasRenderer.cullTransparentMesh = false;
#endif
return go;
}
public static Material DefaultSkeletonGraphicMaterial {
get { return MaterialWithName("SkeletonGraphicDefault"); }
}
public static Material DefaultSkeletonGraphicAdditiveMaterial {
get { return MaterialWithName("SkeletonGraphicAdditive"); }
}
public static Material DefaultSkeletonGraphicMultiplyMaterial {
get { return MaterialWithName("SkeletonGraphicMultiply"); }
}
public static Material DefaultSkeletonGraphicScreenMaterial {
get { return MaterialWithName("SkeletonGraphicScreen"); }
}
protected static Material MaterialWithName (string name) {
string[] guids = AssetDatabase.FindAssets(name + " t:material");
if (guids.Length <= 0) return null;
int closestNameDistance = int.MaxValue;
int closestNameIndex = 0;
for (int i = 0; i < guids.Length; ++i) {
string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
string assetName = System.IO.Path.GetFileNameWithoutExtension(assetPath);
int distance = string.CompareOrdinal(assetName, name);
if (distance < closestNameDistance) {
closestNameDistance = distance;
closestNameIndex = i;
}
}
string foundAssetPath = AssetDatabase.GUIDToAssetPath(guids[closestNameIndex]);
if (string.IsNullOrEmpty(foundAssetPath)) return null;
Material firstMaterial = AssetDatabase.LoadAssetAtPath<Material>(foundAssetPath);
return firstMaterial;
}
#endregion
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0d81cc76b52fcdf499b2db252a317726
timeCreated: 1455570945
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,153 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonMecanim))]
[CanEditMultipleObjects]
public class SkeletonMecanimInspector : SkeletonRendererInspector {
public static bool mecanimSettingsFoldout;
protected SerializedProperty autoReset;
protected SerializedProperty useCustomMixMode;
protected SerializedProperty layerMixModes;
protected SerializedProperty layerBlendModes;
protected override void OnEnable () {
base.OnEnable();
SerializedProperty mecanimTranslator = serializedObject.FindProperty("translator");
autoReset = mecanimTranslator.FindPropertyRelative("autoReset");
useCustomMixMode = mecanimTranslator.FindPropertyRelative("useCustomMixMode");
layerMixModes = mecanimTranslator.FindPropertyRelative("layerMixModes");
layerBlendModes = mecanimTranslator.FindPropertyRelative("layerBlendModes");
}
protected override void DrawInspectorGUI (bool multi) {
AddRootMotionComponentIfEnabled();
base.DrawInspectorGUI(multi);
using (new SpineInspectorUtility.BoxScope()) {
mecanimSettingsFoldout = EditorGUILayout.Foldout(mecanimSettingsFoldout, "Mecanim Translator");
if (mecanimSettingsFoldout) {
EditorGUILayout.PropertyField(autoReset, new GUIContent("Auto Reset",
"When set to true, the skeleton state is mixed out to setup-" +
"pose when an animation finishes, according to the " +
"animation's keyed items."));
EditorGUILayout.PropertyField(useCustomMixMode, new GUIContent("Custom MixMode",
"When disabled, the recommended MixMode is used according to the layer blend mode. Enable to specify a custom MixMode for each Mecanim layer."));
if (useCustomMixMode.hasMultipleDifferentValues || useCustomMixMode.boolValue == true) {
DrawLayerSettings();
EditorGUILayout.Space();
}
}
}
}
protected void AddRootMotionComponentIfEnabled () {
foreach (UnityEngine.Object t in targets) {
Component component = t as Component;
Animator animator = component.GetComponent<Animator>();
if (animator != null && animator.applyRootMotion) {
if (component.GetComponent<SkeletonMecanimRootMotion>() == null) {
component.gameObject.AddComponent<SkeletonMecanimRootMotion>();
}
}
}
}
protected void DrawLayerSettings () {
string[] layerNames = GetLayerNames();
float widthLayerColumn = 140;
float widthMixColumn = 84;
using (new GUILayout.HorizontalScope()) {
Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
rect.width = widthLayerColumn;
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mecanim Layer"), EditorStyles.boldLabel);
int savedIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
rect.position += new Vector2(rect.width, 0);
rect.width = widthMixColumn;
EditorGUI.LabelField(rect, SpineInspectorUtility.TempContent("Mix Mode"), EditorStyles.boldLabel);
EditorGUI.indentLevel = savedIndent;
}
using (new SpineInspectorUtility.IndentScope()) {
int layerCount = layerMixModes.arraySize;
for (int i = 0; i < layerCount; ++i) {
using (new GUILayout.HorizontalScope()) {
string layerName = i < layerNames.Length ? layerNames[i] : ("Layer " + i);
Rect rect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, EditorGUIUtility.singleLineHeight);
rect.width = widthLayerColumn;
EditorGUI.PrefixLabel(rect, SpineInspectorUtility.TempContent(layerName));
int savedIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
SerializedProperty mixMode = layerMixModes.GetArrayElementAtIndex(i);
rect.position += new Vector2(rect.width, 0);
rect.width = widthMixColumn;
EditorGUI.PropertyField(rect, mixMode, GUIContent.none);
EditorGUI.indentLevel = savedIndent;
}
}
}
}
protected string[] GetLayerNames () {
int maxLayerCount = 0;
int maxIndex = 0;
for (int i = 0; i < targets.Length; ++i) {
SkeletonMecanim skeletonMecanim = ((SkeletonMecanim)targets[i]);
int count = skeletonMecanim.Translator.MecanimLayerCount;
if (count > maxLayerCount) {
maxLayerCount = count;
maxIndex = i;
}
}
if (maxLayerCount == 0)
return new string[0];
SkeletonMecanim skeletonMecanimMaxLayers = ((SkeletonMecanim)targets[maxIndex]);
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6a9ca5213a3a4614c9a9f2e60909bc33
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,81 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonMecanimRootMotion))]
[CanEditMultipleObjects]
public class SkeletonMecanimRootMotionInspector : SkeletonRootMotionBaseInspector {
protected SerializedProperty mecanimLayerFlags;
protected GUIContent mecanimLayersLabel;
protected override void OnEnable () {
base.OnEnable();
mecanimLayerFlags = serializedObject.FindProperty("mecanimLayerFlags");
mecanimLayersLabel = new UnityEngine.GUIContent("Mecanim Layers", "Mecanim layers to apply root motion at. Defaults to the first Mecanim layer.");
}
override public void OnInspectorGUI () {
base.MainPropertyFields();
MecanimLayerMaskPropertyField();
base.OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected string[] GetLayerNames () {
int maxLayerCount = 0;
int maxIndex = 0;
for (int i = 0; i < targets.Length; ++i) {
SkeletonMecanim skeletonMecanim = ((SkeletonMecanimRootMotion)targets[i]).SkeletonMecanim;
int count = skeletonMecanim.Translator.MecanimLayerCount;
if (count > maxLayerCount) {
maxLayerCount = count;
maxIndex = i;
}
}
if (maxLayerCount == 0)
return new string[0];
SkeletonMecanim skeletonMecanimMaxLayers = ((SkeletonMecanimRootMotion)targets[maxIndex]).SkeletonMecanim;
return skeletonMecanimMaxLayers.Translator.MecanimLayerNames;
}
protected void MecanimLayerMaskPropertyField () {
string[] layerNames = GetLayerNames();
if (layerNames.Length > 0)
mecanimLayerFlags.intValue = EditorGUILayout.MaskField(
mecanimLayersLabel, mecanimLayerFlags.intValue, layerNames);
}
}
}

View File

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

View File

@ -0,0 +1,165 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#define SPINE_OPTIONAL_MATERIALOVERRIDE
// Contributed by: Lost Polygon
using Spine.Unity.Examples;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
// This script is not intended for use with code. See the readme.txt file in SkeletonRendererCustomMaterials folder to learn more.
[CustomEditor(typeof(SkeletonRendererCustomMaterials))]
public class SkeletonRendererCustomMaterialsInspector : UnityEditor.Editor {
List<SkeletonRendererCustomMaterials.AtlasMaterialOverride> componentCustomMaterialOverrides, _customMaterialOverridesPrev;
List<SkeletonRendererCustomMaterials.SlotMaterialOverride> componentCustomSlotMaterials, _customSlotMaterialsPrev;
SkeletonRendererCustomMaterials component;
const BindingFlags PrivateInstance = BindingFlags.Instance | BindingFlags.NonPublic;
MethodInfo RemoveCustomMaterialOverrides, RemoveCustomSlotMaterials, SetCustomMaterialOverrides, SetCustomSlotMaterials;
#region SkeletonRenderer context menu
[MenuItem("CONTEXT/SkeletonRenderer/Add Basic Serialized Custom Materials")]
static void AddSkeletonRendererCustomMaterials (MenuCommand menuCommand) {
SkeletonRenderer skeletonRenderer = (SkeletonRenderer)menuCommand.context;
SkeletonRendererCustomMaterials newComponent = skeletonRenderer.gameObject.AddComponent<SkeletonRendererCustomMaterials>();
Undo.RegisterCreatedObjectUndo(newComponent, "Add Basic Serialized Custom Materials");
}
[MenuItem("CONTEXT/SkeletonRenderer/Add Basic Serialized Custom Materials", true)]
static bool AddSkeletonRendererCustomMaterials_Validate (MenuCommand menuCommand) {
SkeletonRenderer skeletonRenderer = (SkeletonRenderer)menuCommand.context;
return (skeletonRenderer.GetComponent<SkeletonRendererCustomMaterials>() == null);
}
#endregion
void OnEnable () {
Type cm = typeof(SkeletonRendererCustomMaterials);
RemoveCustomMaterialOverrides = cm.GetMethod("RemoveCustomMaterialOverrides", PrivateInstance);
RemoveCustomSlotMaterials = cm.GetMethod("RemoveCustomSlotMaterials", PrivateInstance);
SetCustomMaterialOverrides = cm.GetMethod("SetCustomMaterialOverrides", PrivateInstance);
SetCustomSlotMaterials = cm.GetMethod("SetCustomSlotMaterials", PrivateInstance);
}
public override void OnInspectorGUI () {
component = (SkeletonRendererCustomMaterials)target;
SkeletonRenderer skeletonRenderer = component.skeletonRenderer;
// Draw the default inspector
DrawDefaultInspector();
if (serializedObject.isEditingMultipleObjects)
return;
if (componentCustomMaterialOverrides == null) {
Type cm = typeof(SkeletonRendererCustomMaterials);
componentCustomMaterialOverrides = cm.GetField("customMaterialOverrides", PrivateInstance).GetValue(component) as List<SkeletonRendererCustomMaterials.AtlasMaterialOverride>;
componentCustomSlotMaterials = cm.GetField("customSlotMaterials", PrivateInstance).GetValue(component) as List<SkeletonRendererCustomMaterials.SlotMaterialOverride>;
if (componentCustomMaterialOverrides == null) {
Debug.Log("Reflection failed.");
return;
}
}
// Fill with current values at start
if (_customMaterialOverridesPrev == null || _customSlotMaterialsPrev == null) {
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customSlotMaterialsPrev = CopyList(componentCustomSlotMaterials);
}
// Compare new values with saved. If change is detected:
// store new values, restore old values, remove overrides, restore new values, restore overrides.
// 1. Store new values
var customMaterialOverridesNew = CopyList(componentCustomMaterialOverrides);
var customSlotMaterialsNew = CopyList(componentCustomSlotMaterials);
// Detect changes
if (!_customMaterialOverridesPrev.SequenceEqual(customMaterialOverridesNew) ||
!_customSlotMaterialsPrev.SequenceEqual(customSlotMaterialsNew)) {
// 2. Restore old values
componentCustomMaterialOverrides.Clear();
componentCustomSlotMaterials.Clear();
componentCustomMaterialOverrides.AddRange(_customMaterialOverridesPrev);
componentCustomSlotMaterials.AddRange(_customSlotMaterialsPrev);
// 3. Remove overrides
RemoveCustomMaterials();
// 4. Restore new values
componentCustomMaterialOverrides.Clear();
componentCustomSlotMaterials.Clear();
componentCustomMaterialOverrides.AddRange(customMaterialOverridesNew);
componentCustomSlotMaterials.AddRange(customSlotMaterialsNew);
// 5. Restore overrides
SetCustomMaterials();
if (skeletonRenderer != null)
skeletonRenderer.LateUpdate();
}
_customMaterialOverridesPrev = CopyList(componentCustomMaterialOverrides);
_customSlotMaterialsPrev = CopyList(componentCustomSlotMaterials);
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Clear and Reapply Changes", tooltip: "Removes all non-serialized overrides in the SkeletonRenderer and reapplies the overrides on this component."))) {
if (skeletonRenderer != null) {
#if SPINE_OPTIONAL_MATERIALOVERRIDE
skeletonRenderer.CustomMaterialOverride.Clear();
#endif
skeletonRenderer.CustomSlotMaterials.Clear();
RemoveCustomMaterials();
SetCustomMaterials();
skeletonRenderer.LateUpdate();
}
}
}
void RemoveCustomMaterials () {
RemoveCustomMaterialOverrides.Invoke(component, null);
RemoveCustomSlotMaterials.Invoke(component, null);
}
void SetCustomMaterials () {
SetCustomMaterialOverrides.Invoke(component, null);
SetCustomSlotMaterials.Invoke(component, null);
}
static List<T> CopyList<T> (List<T> list) {
return list.GetRange(0, list.Count);
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e70f7f2a241d6d34aafd6a4a52a368d0
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,682 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#else
#define NO_PREFAB_MESH
#endif
#if UNITY_2018_1_OR_NEWER
#define PER_MATERIAL_PROPERTY_BLOCKS
#endif
#if UNITY_2017_1_OR_NEWER
#define BUILT_IN_SPRITE_MASK_COMPONENT
#endif
#if UNITY_2020_2_OR_NEWER
#define HAS_ON_POSTPROCESS_PREFAB
#endif
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Event = UnityEngine.Event;
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonRenderer))]
[CanEditMultipleObjects]
public class SkeletonRendererInspector : UnityEditor.Editor {
public static bool advancedFoldout;
protected bool loadingFailed = false;
const string SeparatorSlotNamesFieldName = "separatorSlotNames";
protected SerializedProperty skeletonDataAsset, initialSkinName;
protected SerializedProperty initialFlipX, initialFlipY;
protected SerializedProperty updateTiming, updateWhenInvisible, singleSubmesh, separatorSlotNames,
clearStateOnDisable, immutableTriangles, fixDrawOrder, fixPrefabOverrideViaMeshFilter;
protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings
protected SerializedProperty maskInteraction;
protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside;
protected SerializedProperty physicsPositionInheritanceFactor, physicsRotationInheritanceFactor, physicsMovementRelativeTo;
protected SpineInspectorUtility.SerializedSortingProperties sortingProperties;
protected bool wasInitParameterChanged = false;
protected bool requireRepaint = false;
protected bool isInspectingPrefab;
protected bool forceReloadQueued = false;
protected bool setMaskNoneMaterialsQueued = false;
protected bool setInsideMaskMaterialsQueued = false;
protected bool setOutsideMaskMaterialsQueued = false;
protected bool deleteInsideMaskMaterialsQueued = false;
protected bool deleteOutsideMaskMaterialsQueued = false;
protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel,
TintBlackLabel, UpdateTimingLabel, UpdateWhenInvisibleLabel, SingleSubmeshLabel, FixDrawOrderLabel, FixPrefabOverrideViaMeshFilterLabel;
protected GUIContent NormalsLabel, TangentsLabel, MaskInteractionLabel;
protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel;
protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel;
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 (X,Y) 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.");
const string ReloadButtonString = "Reload";
static GUILayoutOption reloadButtonWidth;
static GUILayoutOption ReloadButtonWidth { get { return reloadButtonWidth = reloadButtonWidth ?? GUILayout.Width(GUI.skin.label.CalcSize(new GUIContent(ReloadButtonString)).x + 20); } }
static GUIStyle ReloadButtonStyle { get { return EditorStyles.miniButton; } }
protected bool TargetIsValid {
get {
if (serializedObject.isEditingMultipleObjects) {
foreach (UnityEngine.Object o in targets) {
SkeletonRenderer component = (SkeletonRenderer)o;
if (!component.valid)
return false;
}
return true;
} else {
SkeletonRenderer component = (SkeletonRenderer)target;
return component.valid;
}
}
}
protected virtual void OnEnable () {
#if NEW_PREFAB_SYSTEM
isInspectingPrefab = false;
#else
isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
#endif
SpineEditorUtilities.ConfirmInitialization();
loadingFailed = false;
// Labels
SkeletonDataAssetLabel = new GUIContent("SkeletonData Asset", Icons.spine);
SkeletonUtilityButtonContent = new GUIContent("Add Skeleton Utility", Icons.skeletonUtility);
ImmubleTrianglesLabel = new GUIContent("Immutable Triangles", "Enable to optimize rendering for skeletons that never change attachment visbility");
PMAVertexColorsLabel = new GUIContent("PMA Vertex Colors", "Use this if you are using the default Spine/Skeleton shader or any premultiply-alpha shader.");
ClearStateOnDisableLabel = new GUIContent("Clear State On Disable", "Use this if you are pooling or enabling/disabling your Spine GameObject.");
ZSpacingLabel = new GUIContent("Z Spacing", "A value other than 0 adds a space between each rendered attachment to prevent Z Fighting when using shaders that read or write to the depth buffer. Large values may cause unwanted parallax and spaces depending on camera setup.");
NormalsLabel = new GUIContent("Add Normals", "Use this if your shader requires vertex normals. A more efficient solution for 2D setups is to modify the shader to assume a single normal value for the whole mesh.");
TangentsLabel = new GUIContent("Solve Tangents", "Calculates the tangents per frame. Use this if you are using lit shaders (usually with normal maps) that require vertex tangents.");
TintBlackLabel = new GUIContent("Tint Black (!)", "Adds black tint vertex data to the mesh as UV2 and UV3. Black tinting requires that the shader interpret UV2 and UV3 as black tint colors for this effect to work. You may also use the default [Spine/Skeleton Tint Black] shader.\n\nIf you only need to tint the whole skeleton and not individual parts, the [Spine/Skeleton Tint] shader is recommended for better efficiency and changing/animating the _Black material property via MaterialPropertyBlock.");
SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials.");
UpdateTimingLabel = new GUIContent("Animation Update", "Whether to update the animation in normal Update (the default), physics step FixedUpdate, or manually via a user call.");
UpdateWhenInvisibleLabel = new GUIContent("Update When Invisible", "Update mode used when the MeshRenderer becomes invisible. Update mode is automatically reset to UpdateMode.FullUpdate when the mesh becomes visible again.");
FixDrawOrderLabel = new GUIContent("Fix Draw Order", "Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. \"A B A\"). If true, GPU instancing will be disabled at all materials and MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes by e.g. the LWRP renderer, leading to incorrect draw order (e.g. \"A1 B A2\" changed to \"A1A2 B\"). You can disable this parameter when everything is drawn correctly to save the additional performance cost. Note: the GPU instancing setting will remain disabled at affected material assets after exiting play mode, you have to enable it manually if you accidentally enabled this parameter.");
FixPrefabOverrideViaMeshFilterLabel = new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost. For global settings see Edit - Preferences - Spine.");
MaskInteractionLabel = new GUIContent("Mask Interaction", "SkeletonRenderer's interaction with a Sprite Mask.");
MaskMaterialsHeadingLabel = new GUIContent("Mask Interaction Materials", "Materials used for different interaction with sprite masks.");
MaskMaterialsNoneLabel = new GUIContent("Normal Materials", "Normal materials used when Mask Interaction is set to None.");
MaskMaterialsInsideLabel = new GUIContent("Inside Mask", "Materials used when Mask Interaction is set to Inside Mask.");
MaskMaterialsOutsideLabel = new GUIContent("Outside Mask", "Materials used when Mask Interaction is set to Outside Mask.");
SetMaterialButtonLabel = new GUIContent("Set", "Prepares material references for switching to the corresponding Mask Interaction mode at runtime. Creates the required materials if they do not exist.");
ClearMaterialButtonLabel = new GUIContent("Clear", "Clears unused material references. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly.");
DeleteMaterialButtonLabel = new GUIContent("Delete", "Clears unused material references and deletes the corresponding assets. Note: when switching to the corresponding Mask Interaction mode at runtime, a new material is generated on the fly.");
SerializedObject so = this.serializedObject;
skeletonDataAsset = so.FindProperty("skeletonDataAsset");
initialSkinName = so.FindProperty("initialSkinName");
initialFlipX = so.FindProperty("initialFlipX");
initialFlipY = so.FindProperty("initialFlipY");
normals = so.FindProperty("addNormals");
tangents = so.FindProperty("calculateTangents");
immutableTriangles = so.FindProperty("immutableTriangles");
pmaVertexColors = so.FindProperty("pmaVertexColors");
clearStateOnDisable = so.FindProperty("clearStateOnDisable");
tintBlack = so.FindProperty("tintBlack");
updateTiming = so.FindProperty("updateTiming");
updateWhenInvisible = so.FindProperty("updateWhenInvisible");
singleSubmesh = so.FindProperty("singleSubmesh");
fixDrawOrder = so.FindProperty("fixDrawOrder");
fixPrefabOverrideViaMeshFilter = so.FindProperty("fixPrefabOverrideViaMeshFilter");
maskInteraction = so.FindProperty("maskInteraction");
maskMaterialsNone = so.FindProperty("maskMaterials.materialsMaskDisabled");
maskMaterialsInside = so.FindProperty("maskMaterials.materialsInsideMask");
maskMaterialsOutside = so.FindProperty("maskMaterials.materialsOutsideMask");
physicsPositionInheritanceFactor = so.FindProperty("physicsPositionInheritanceFactor");
physicsRotationInheritanceFactor = so.FindProperty("physicsRotationInheritanceFactor");
physicsMovementRelativeTo = so.FindProperty("physicsMovementRelativeTo");
separatorSlotNames = so.FindProperty("separatorSlotNames");
separatorSlotNames.isExpanded = true;
zSpacing = so.FindProperty("zSpacing");
SerializedObject renderersSerializedObject = SpineInspectorUtility.GetRenderersSerializedObject(serializedObject); // Allows proper multi-edit behavior.
sortingProperties = new SpineInspectorUtility.SerializedSortingProperties(renderersSerializedObject);
}
public void OnSceneGUI () {
SkeletonRenderer skeletonRenderer = (SkeletonRenderer)target;
if (loadingFailed)
return;
Skeleton skeleton = skeletonRenderer.Skeleton;
if (skeleton == null) {
loadingFailed = true;
return;
}
Transform transform = skeletonRenderer.transform;
if (skeleton == null) return;
SpineHandles.DrawBones(transform, skeleton);
}
override public void OnInspectorGUI () {
bool multi = serializedObject.isEditingMultipleObjects;
DrawInspectorGUI(multi);
HandleSkinChange();
if (serializedObject.ApplyModifiedProperties() || SpineInspectorUtility.UndoRedoPerformed(Event.current) ||
AreAnyMaskMaterialsMissing()) {
if (!Application.isPlaying) {
foreach (UnityEngine.Object o in targets)
SpineEditorUtilities.ReinitializeComponent((SkeletonRenderer)o);
SceneView.RepaintAll();
}
}
if (!isInspectingPrefab) {
if (requireRepaint) {
SceneView.RepaintAll();
requireRepaint = false;
}
}
}
protected virtual void DrawInspectorGUI (bool multi) {
// Initialize.
if (Event.current.type == EventType.Layout) {
if (forceReloadQueued) {
forceReloadQueued = false;
foreach (UnityEngine.Object c in targets) {
SpineEditorUtilities.ReloadSkeletonDataAssetAndComponent(c as SkeletonRenderer);
}
} else {
foreach (UnityEngine.Object c in targets) {
SkeletonRenderer component = c as SkeletonRenderer;
if (!component.valid) {
SpineEditorUtilities.ReinitializeComponent(component);
if (!component.valid) continue;
}
}
}
#if BUILT_IN_SPRITE_MASK_COMPONENT
if (setMaskNoneMaterialsQueued) {
setMaskNoneMaterialsQueued = false;
foreach (UnityEngine.Object c in targets)
EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.None);
}
if (setInsideMaskMaterialsQueued) {
setInsideMaskMaterialsQueued = false;
foreach (UnityEngine.Object c in targets)
EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask);
}
if (setOutsideMaskMaterialsQueued) {
setOutsideMaskMaterialsQueued = false;
foreach (UnityEngine.Object c in targets)
EditorSetMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask);
}
if (deleteInsideMaskMaterialsQueued) {
deleteInsideMaskMaterialsQueued = false;
foreach (UnityEngine.Object c in targets)
EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleInsideMask);
}
if (deleteOutsideMaskMaterialsQueued) {
deleteOutsideMaskMaterialsQueued = false;
foreach (UnityEngine.Object c in targets)
EditorDeleteMaskMaterials(c as SkeletonRenderer, SpriteMaskInteraction.VisibleOutsideMask);
}
#endif
#if NO_PREFAB_MESH
if (isInspectingPrefab) {
foreach (UnityEngine.Object c in targets) {
SkeletonRenderer component = (SkeletonRenderer)c;
MeshFilter meshFilter = component.GetComponent<MeshFilter>();
if (meshFilter != null && meshFilter.sharedMesh != null)
meshFilter.sharedMesh = null;
}
}
#endif
}
bool valid = TargetIsValid;
foreach (UnityEngine.Object o in targets)
ApplyModifiedMeshParameters(o as SkeletonRenderer);
// Fields.
if (multi) {
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) {
SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel);
if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth))
forceReloadQueued = true;
}
if (valid) EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin"));
} else {
SkeletonRenderer component = (SkeletonRenderer)target;
using (new EditorGUILayout.HorizontalScope(EditorStyles.helpBox)) {
SpineInspectorUtility.PropertyFieldFitLabel(skeletonDataAsset, SkeletonDataAssetLabel);
if (component.valid) {
if (GUILayout.Button(ReloadButtonString, ReloadButtonStyle, ReloadButtonWidth))
forceReloadQueued = true;
}
}
if (component.skeletonDataAsset == null) {
EditorGUILayout.HelpBox("SkeletonData asset required", MessageType.Warning);
return;
}
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.skeletonDataAsset)) {
EditorGUILayout.HelpBox("SkeletonData asset error. Please check SkeletonData asset.", MessageType.Error);
return;
}
if (valid)
EditorGUILayout.PropertyField(initialSkinName, SpineInspectorUtility.TempContent("Initial Skin"));
}
EditorGUILayout.Space();
// Sorting Layers
SpineInspectorUtility.SortingPropertyFields(sortingProperties, applyModifiedProperties: true);
if (maskInteraction != null) EditorGUILayout.PropertyField(maskInteraction, MaskInteractionLabel);
if (!valid)
return;
string errorMessage = null;
if (SpineEditorUtilities.Preferences.componentMaterialWarning &&
MaterialChecks.IsMaterialSetupProblematic((SkeletonRenderer)this.target, ref errorMessage)) {
EditorGUILayout.HelpBox(errorMessage, MessageType.Error, true);
}
// More Render Options...
using (new SpineInspectorUtility.BoxScope()) {
EditorGUI.BeginChangeCheck();
EditorGUILayout.BeginHorizontal(GUILayout.Height(EditorGUIUtility.singleLineHeight + 5));
advancedFoldout = EditorGUILayout.Foldout(advancedFoldout, "Advanced");
if (advancedFoldout) {
EditorGUILayout.Space();
if (GUILayout.Button("Debug", EditorStyles.miniButton, GUILayout.Width(65f)))
SkeletonDebugWindow.Init();
} else {
EditorGUILayout.Space();
}
EditorGUILayout.EndHorizontal();
if (advancedFoldout) {
using (new SpineInspectorUtility.IndentScope()) {
using (new EditorGUILayout.HorizontalScope()) {
EditorGUI.BeginChangeCheck();
SpineInspectorUtility.ToggleLeftLayout(initialFlipX);
SpineInspectorUtility.ToggleLeftLayout(initialFlipY);
wasInitParameterChanged |= EditorGUI.EndChangeCheck(); // Value used in the next update.
EditorGUILayout.Space();
}
EditorGUILayout.Space();
EditorGUILayout.LabelField("Renderer and Update Settings", EditorStyles.boldLabel);
using (new SpineInspectorUtility.LabelWidthScope()) {
// Optimization options
if (updateTiming != null) EditorGUILayout.PropertyField(updateTiming, UpdateTimingLabel);
if (updateWhenInvisible != null) EditorGUILayout.PropertyField(updateWhenInvisible, UpdateWhenInvisibleLabel);
if (singleSubmesh != null) EditorGUILayout.PropertyField(singleSubmesh, SingleSubmeshLabel);
#if PER_MATERIAL_PROPERTY_BLOCKS
if (fixDrawOrder != null) EditorGUILayout.PropertyField(fixDrawOrder, FixDrawOrderLabel);
#endif
if (immutableTriangles != null) EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
EditorGUILayout.Space();
#if HAS_ON_POSTPROCESS_PREFAB
if (fixPrefabOverrideViaMeshFilter != null) EditorGUILayout.PropertyField(fixPrefabOverrideViaMeshFilter, FixPrefabOverrideViaMeshFilterLabel);
EditorGUILayout.Space();
#endif
}
SeparatorsField(separatorSlotNames);
EditorGUILayout.Space();
// Render options
const float MinZSpacing = -0.1f;
const float MaxZSpacing = 0f;
EditorGUILayout.Slider(zSpacing, MinZSpacing, MaxZSpacing, ZSpacingLabel);
EditorGUILayout.Space();
using (new SpineInspectorUtility.LabelWidthScope()) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Vertex Data", SpineInspectorUtility.UnityIcon<MeshFilter>()), EditorStyles.boldLabel);
if (pmaVertexColors != null) EditorGUILayout.PropertyField(pmaVertexColors, PMAVertexColorsLabel);
EditorGUILayout.PropertyField(tintBlack, TintBlackLabel);
// Optional fields. May be disabled in SkeletonRenderer.
if (normals != null) EditorGUILayout.PropertyField(normals, NormalsLabel);
if (tangents != null) EditorGUILayout.PropertyField(tangents, TangentsLabel);
}
#if BUILT_IN_SPRITE_MASK_COMPONENT
EditorGUILayout.Space();
if (maskMaterialsNone.arraySize > 0 || maskMaterialsInside.arraySize > 0 || maskMaterialsOutside.arraySize > 0) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Mask Interaction Materials", SpineInspectorUtility.UnityIcon<SpriteMask>()), EditorStyles.boldLabel);
bool differentMaskModesSelected = maskInteraction.hasMultipleDifferentValues;
int activeMaskInteractionValue = differentMaskModesSelected ? -1 : maskInteraction.intValue;
bool ignoredParam = true;
MaskMaterialsEditingField(ref setMaskNoneMaterialsQueued, ref ignoredParam, maskMaterialsNone, MaskMaterialsNoneLabel,
differentMaskModesSelected, allowDelete: false, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.None);
MaskMaterialsEditingField(ref setInsideMaskMaterialsQueued, ref deleteInsideMaskMaterialsQueued, maskMaterialsInside, MaskMaterialsInsideLabel,
differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleInsideMask);
MaskMaterialsEditingField(ref setOutsideMaskMaterialsQueued, ref deleteOutsideMaskMaterialsQueued, maskMaterialsOutside, MaskMaterialsOutsideLabel,
differentMaskModesSelected, allowDelete: true, isActiveMaterial: activeMaskInteractionValue == (int)SpriteMaskInteraction.VisibleOutsideMask);
}
#endif
using (new SpineInspectorUtility.LabelWidthScope()) {
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);
}
EditorGUILayout.Space();
if (valid && !isInspectingPrefab) {
if (multi) {
// Support multi-edit SkeletonUtility button.
// EditorGUILayout.Space();
// bool addSkeletonUtility = GUILayout.Button(buttonContent, GUILayout.Height(30));
// foreach (UnityEngine.Object t in targets) {
// Component component = t as Component;
// if (addSkeletonUtility && component.GetComponent<SkeletonUtility>() == null)
// component.gameObject.AddComponent<SkeletonUtility>();
// }
} else {
Component component = (Component)target;
if (component.GetComponent<SkeletonUtility>() == null) {
if (SpineInspectorUtility.CenteredButton(SkeletonUtilityButtonContent, 21, true, 200f))
component.gameObject.AddComponent<SkeletonUtility>();
}
}
}
EditorGUILayout.Space();
}
}
if (EditorGUI.EndChangeCheck())
SceneView.RepaintAll();
}
}
protected void ApplyModifiedMeshParameters (SkeletonRenderer skeletonRenderer) {
if (skeletonRenderer == null) return;
if (!skeletonRenderer.valid)
return;
if (!isInspectingPrefab) {
if (wasInitParameterChanged) {
wasInitParameterChanged = false;
if (!Application.isPlaying) {
skeletonRenderer.Initialize(true);
skeletonRenderer.LateUpdate();
requireRepaint = true;
}
}
}
}
protected void SkeletonRootMotionParameter () {
SkeletonRootMotionParameter(targets);
}
public static void SkeletonRootMotionParameter (Object[] targets) {
int rootMotionComponentCount = 0;
foreach (UnityEngine.Object t in targets) {
Component component = t as Component;
if (component.GetComponent<SkeletonRootMotion>() != null) {
++rootMotionComponentCount;
}
}
bool allHaveRootMotion = rootMotionComponentCount == targets.Length;
bool anyHaveRootMotion = rootMotionComponentCount > 0;
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Root Motion");
if (!allHaveRootMotion) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Component", Icons.constraintTransform), GUILayout.MaxWidth(130), GUILayout.Height(18))) {
foreach (UnityEngine.Object t in targets) {
Component component = t as Component;
if (component.GetComponent<SkeletonRootMotion>() == null) {
component.gameObject.AddComponent<SkeletonRootMotion>();
}
}
}
}
if (anyHaveRootMotion) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Remove Component", Icons.constraintTransform), GUILayout.MaxWidth(140), GUILayout.Height(18))) {
foreach (UnityEngine.Object t in targets) {
Component component = t as Component;
SkeletonRootMotion rootMotionComponent = component.GetComponent<SkeletonRootMotion>();
if (rootMotionComponent != null) {
DestroyImmediate(rootMotionComponent);
}
}
}
}
}
}
public static void SetSeparatorSlotNames (SkeletonRenderer skeletonRenderer, string[] newSlotNames) {
FieldInfo field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
field.SetValue(skeletonRenderer, newSlotNames);
}
public static string[] GetSeparatorSlotNames (SkeletonRenderer skeletonRenderer) {
FieldInfo field = SpineInspectorUtility.GetNonPublicField(typeof(SkeletonRenderer), SeparatorSlotNamesFieldName);
return field.GetValue(skeletonRenderer) as string[];
}
public static void SeparatorsField (SerializedProperty separatorSlotNames) {
bool multi = separatorSlotNames.serializedObject.isEditingMultipleObjects;
bool hasTerminalSlot = false;
if (!multi) {
ISkeletonComponent sr = separatorSlotNames.serializedObject.targetObject as ISkeletonComponent;
Skeleton skeleton = sr.Skeleton;
int lastSlot = skeleton.Slots.Count - 1;
if (skeleton != null) {
for (int i = 0, n = separatorSlotNames.arraySize; i < n; i++) {
string slotName = separatorSlotNames.GetArrayElementAtIndex(i).stringValue;
SlotData slot = skeleton.Data.FindSlot(slotName);
int index = slot != null ? slot.Index : -1;
if (index == 0 || index == lastSlot) {
hasTerminalSlot = true;
break;
}
}
}
}
string terminalSlotWarning = hasTerminalSlot ? " (!)" : "";
using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) {
const string SeparatorsDescription = "Stored names of slots where the Skeleton's render will be split into different batches. This is used by separate components that split the render into different MeshRenderers or GameObjects.";
if (separatorSlotNames.isExpanded) {
EditorGUILayout.PropertyField(separatorSlotNames, SpineInspectorUtility.TempContent(separatorSlotNames.displayName + terminalSlotWarning, Icons.slotRoot, SeparatorsDescription), true);
GUILayout.BeginHorizontal();
GUILayout.FlexibleSpace();
if (GUILayout.Button("+", GUILayout.MaxWidth(28f), GUILayout.MaxHeight(15f))) {
separatorSlotNames.arraySize++;
}
GUILayout.EndHorizontal();
EditorGUILayout.Space();
} else
EditorGUILayout.PropertyField(separatorSlotNames, new GUIContent(separatorSlotNames.displayName + string.Format("{0} [{1}]", terminalSlotWarning, separatorSlotNames.arraySize), SeparatorsDescription), true);
}
}
public void MaskMaterialsEditingField (ref bool wasSetRequested, ref bool wasDeleteRequested,
SerializedProperty maskMaterials, GUIContent label,
bool differentMaskModesSelected, bool allowDelete, bool isActiveMaterial) {
using (new EditorGUILayout.HorizontalScope()) {
EditorGUILayout.LabelField(label, isActiveMaterial ? EditorStyles.boldLabel : EditorStyles.label, GUILayout.MinWidth(80f), GUILayout.MaxWidth(140));
EditorGUILayout.LabelField(maskMaterials.hasMultipleDifferentValues ? "-" : maskMaterials.arraySize.ToString(), EditorStyles.miniLabel, GUILayout.Width(42f));
bool enableSetButton = differentMaskModesSelected || maskMaterials.arraySize == 0;
bool enableClearButtons = differentMaskModesSelected || (maskMaterials.arraySize != 0 && !isActiveMaterial);
EditorGUI.BeginDisabledGroup(!enableSetButton);
if (GUILayout.Button(SetMaterialButtonLabel, EditorStyles.miniButtonLeft, GUILayout.Width(46f))) {
wasSetRequested = true;
}
EditorGUI.EndDisabledGroup();
EditorGUI.BeginDisabledGroup(!enableClearButtons);
{
if (GUILayout.Button(ClearMaterialButtonLabel, allowDelete ? EditorStyles.miniButtonMid : EditorStyles.miniButtonRight, GUILayout.Width(46f))) {
maskMaterials.ClearArray();
} else if (allowDelete && GUILayout.Button(DeleteMaterialButtonLabel, EditorStyles.miniButtonRight, GUILayout.Width(46f))) {
wasDeleteRequested = true;
}
if (!allowDelete)
GUILayout.Space(46f);
}
EditorGUI.EndDisabledGroup();
}
}
void HandleSkinChange () {
if (!Application.isPlaying && Event.current.type == EventType.Layout && !initialSkinName.hasMultipleDifferentValues) {
bool mismatchDetected = false;
string newSkinName = initialSkinName.stringValue;
foreach (UnityEngine.Object o in targets) {
mismatchDetected |= UpdateIfSkinMismatch((SkeletonRenderer)o, newSkinName);
}
if (mismatchDetected) {
mismatchDetected = false;
SceneView.RepaintAll();
}
}
}
static bool UpdateIfSkinMismatch (SkeletonRenderer skeletonRenderer, string componentSkinName) {
if (!skeletonRenderer.valid || skeletonRenderer.EditorSkipSkinSync) return false;
Skin skin = skeletonRenderer.Skeleton.Skin;
string skeletonSkinName = skin != null ? skin.Name : null;
bool defaultCase = skin == null && string.IsNullOrEmpty(componentSkinName);
bool fieldMatchesSkin = defaultCase || string.Equals(componentSkinName, skeletonSkinName, System.StringComparison.Ordinal);
if (!fieldMatchesSkin) {
Skin skinToSet = string.IsNullOrEmpty(componentSkinName) ? null : skeletonRenderer.Skeleton.Data.FindSkin(componentSkinName);
skeletonRenderer.Skeleton.SetSkin(skinToSet);
skeletonRenderer.Skeleton.SetSlotsToSetupPose();
// Note: the UpdateIfSkinMismatch concept shall be replaced with e.g. an OnValidate based
// solution or in a separate commit. The current solution does not repaint the Game view because
// it is first applying values and in the next editor pass is calling this skin-changing method.
if (skeletonRenderer is SkeletonAnimation)
((SkeletonAnimation)skeletonRenderer).Update(0f);
else if (skeletonRenderer is SkeletonMecanim)
((SkeletonMecanim)skeletonRenderer).Update();
skeletonRenderer.LateUpdate();
return true;
}
return false;
}
bool AreAnyMaskMaterialsMissing () {
#if BUILT_IN_SPRITE_MASK_COMPONENT
foreach (UnityEngine.Object o in targets) {
SkeletonRenderer component = (SkeletonRenderer)o;
if (!component.valid)
continue;
if (SpineMaskUtilities.AreMaskMaterialsMissing(component))
return true;
}
#endif
return false;
}
#if BUILT_IN_SPRITE_MASK_COMPONENT
static void EditorSetMaskMaterials (SkeletonRenderer component, SpriteMaskInteraction maskType) {
if (component == null) return;
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
SpineMaskUtilities.EditorInitMaskMaterials(component, component.maskMaterials, maskType);
}
static void EditorDeleteMaskMaterials (SkeletonRenderer component, SpriteMaskInteraction maskType) {
if (component == null) return;
if (!SpineEditorUtilities.SkeletonDataAssetIsValid(component.SkeletonDataAsset)) return;
SpineMaskUtilities.EditorDeleteMaskMaterials(component.maskMaterials, maskType);
}
#endif
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: d0fc5db9788bce4418ad3252d43faa8a
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,148 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonRootMotionBase))]
[CanEditMultipleObjects]
public class SkeletonRootMotionBaseInspector : UnityEditor.Editor {
protected SerializedProperty rootMotionBoneName;
protected SerializedProperty transformPositionX;
protected SerializedProperty transformPositionY;
protected SerializedProperty transformRotation;
protected SerializedProperty rootMotionScaleX;
protected SerializedProperty rootMotionScaleY;
protected SerializedProperty rootMotionScaleRotation;
protected SerializedProperty rootMotionTranslateXPerY;
protected SerializedProperty rootMotionTranslateYPerX;
protected SerializedProperty rigidBody2D;
protected SerializedProperty applyRigidbody2DGravity;
protected SerializedProperty rigidBody;
protected GUIContent rootMotionBoneNameLabel;
protected GUIContent transformPositionXLabel;
protected GUIContent transformPositionYLabel;
protected GUIContent transformRotationLabel;
protected GUIContent rootMotionScaleXLabel;
protected GUIContent rootMotionScaleYLabel;
protected GUIContent rootMotionScaleRotationLabel;
protected GUIContent rootMotionTranslateXPerYLabel;
protected GUIContent rootMotionTranslateYPerXLabel;
protected GUIContent rigidBody2DLabel;
protected GUIContent applyRigidbody2DGravityLabel;
protected GUIContent rigidBodyLabel;
protected virtual void OnEnable () {
rootMotionBoneName = serializedObject.FindProperty("rootMotionBoneName");
transformPositionX = serializedObject.FindProperty("transformPositionX");
transformPositionY = serializedObject.FindProperty("transformPositionY");
transformRotation = serializedObject.FindProperty("transformRotation");
rootMotionScaleX = serializedObject.FindProperty("rootMotionScaleX");
rootMotionScaleY = serializedObject.FindProperty("rootMotionScaleY");
rootMotionScaleRotation = serializedObject.FindProperty("rootMotionScaleRotation");
rootMotionTranslateXPerY = serializedObject.FindProperty("rootMotionTranslateXPerY");
rootMotionTranslateYPerX = serializedObject.FindProperty("rootMotionTranslateYPerX");
rigidBody2D = serializedObject.FindProperty("rigidBody2D");
applyRigidbody2DGravity = serializedObject.FindProperty("applyRigidbody2DGravity");
rigidBody = serializedObject.FindProperty("rigidBody");
rootMotionBoneNameLabel = new UnityEngine.GUIContent("Root Motion Bone", "The bone to take the motion from.");
transformPositionXLabel = new UnityEngine.GUIContent("X", "Root transform position (X)");
transformPositionYLabel = new UnityEngine.GUIContent("Y", "Use the Y-movement of the bone.");
transformRotationLabel = new UnityEngine.GUIContent("Rotation", "Use the rotation of the bone.");
rootMotionScaleXLabel = new UnityEngine.GUIContent("Root Motion Scale (X)", "Scale applied to the horizontal root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rootMotionScaleYLabel = new UnityEngine.GUIContent("Root Motion Scale (Y)", "Scale applied to the vertical root motion delta. Can be used for delta compensation to e.g. stretch a jump to the desired distance.");
rootMotionScaleRotationLabel = new UnityEngine.GUIContent("Root Motion Scale (Rotation)", "Scale applied to the rotational root motion delta. Can be used for delta compensation to e.g. adjust an angled jump landing to the desired platform angle.");
rootMotionTranslateXPerYLabel = new UnityEngine.GUIContent("Root Motion Translate (X)", "Added X translation per root motion Y delta. Can be used for delta compensation when scaling is not enough, to e.g. offset a horizontal jump to a vertically different goal.");
rootMotionTranslateYPerXLabel = new UnityEngine.GUIContent("Root Motion Translate (Y)", "Added Y translation per root motion X delta. Can be used for delta compensation when scaling is not enough, to e.g. offset a horizontal jump to a vertically different goal.");
rigidBody2DLabel = new UnityEngine.GUIContent("Rigidbody2D",
"Optional Rigidbody2D: Assign a Rigidbody2D here if you want " +
" to apply the root motion to the rigidbody instead of the Transform." +
"\n\n" +
"Note that animation and physics updates are not always in sync." +
"Some jitter may result at certain framerates.");
applyRigidbody2DGravityLabel = new UnityEngine.GUIContent("Apply Gravity",
"Apply Rigidbody2D Gravity");
rigidBodyLabel = new UnityEngine.GUIContent("Rigidbody",
"Optional Rigidbody: Assign a Rigidbody here if you want " +
" to apply the root motion to the rigidbody instead of the Transform." +
"\n\n" +
"Note that animation and physics updates are not always in sync." +
"Some jitter may result at certain framerates.");
}
public override void OnInspectorGUI () {
MainPropertyFields();
OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected virtual void MainPropertyFields () {
EditorGUILayout.PropertyField(rootMotionBoneName, rootMotionBoneNameLabel);
EditorGUILayout.PropertyField(transformPositionX, transformPositionXLabel);
EditorGUILayout.PropertyField(transformPositionY, transformPositionYLabel);
EditorGUILayout.PropertyField(transformRotation, transformRotationLabel);
EditorGUILayout.PropertyField(rootMotionScaleX, rootMotionScaleXLabel);
EditorGUILayout.PropertyField(rootMotionScaleY, rootMotionScaleYLabel);
EditorGUILayout.PropertyField(rootMotionScaleRotation, rootMotionScaleRotationLabel);
EditorGUILayout.PropertyField(rootMotionTranslateXPerY, rootMotionTranslateXPerYLabel);
EditorGUILayout.PropertyField(rootMotionTranslateYPerX, rootMotionTranslateYPerXLabel);
}
protected virtual void OptionalPropertyFields () {
EditorGUILayout.PropertyField(rigidBody2D, rigidBody2DLabel);
if (rigidBody2D.objectReferenceValue != null || rigidBody2D.hasMultipleDifferentValues) {
using (new SpineInspectorUtility.IndentScope())
EditorGUILayout.PropertyField(applyRigidbody2DGravity, applyRigidbody2DGravityLabel);
}
EditorGUILayout.PropertyField(rigidBody, rigidBodyLabel);
DisplayWarnings();
}
protected void DisplayWarnings () {
bool usesRigidbodyPhysics = rigidBody.objectReferenceValue != null || rigidBody2D.objectReferenceValue != null;
if (usesRigidbodyPhysics) {
SkeletonRootMotionBase rootMotionComponent = (SkeletonRootMotionBase)serializedObject.targetObject;
ISkeletonAnimation skeletonComponent = rootMotionComponent ? rootMotionComponent.TargetSkeletonAnimationComponent : null;
if (skeletonComponent != null && skeletonComponent.UpdateTiming == UpdateTiming.InUpdate) {
string warningMessage = "Skeleton component uses 'Advanced - Animation Update' mode 'In Update'.\n" +
"When using a Rigidbody, 'In FixedUpdate' is recommended instead.";
EditorGUILayout.HelpBox(warningMessage, MessageType.Warning, true);
}
}
}
}
}

View File

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

View File

@ -0,0 +1,79 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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 UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
[CustomEditor(typeof(SkeletonRootMotion))]
[CanEditMultipleObjects]
public class SkeletonRootMotionInspector : SkeletonRootMotionBaseInspector {
protected SerializedProperty animationTrackFlags;
protected GUIContent animationTrackFlagsLabel;
string[] TrackNames;
protected override void OnEnable () {
base.OnEnable();
animationTrackFlags = serializedObject.FindProperty("animationTrackFlags");
animationTrackFlagsLabel = new UnityEngine.GUIContent("Animation Tracks",
"Animation tracks to apply root motion at. Defaults to the first" +
" animation track (index 0).");
}
override public void OnInspectorGUI () {
base.MainPropertyFields();
AnimationTracksPropertyField();
base.OptionalPropertyFields();
serializedObject.ApplyModifiedProperties();
}
protected void AnimationTracksPropertyField () {
if (TrackNames == null) {
InitTrackNames();
}
animationTrackFlags.intValue = EditorGUILayout.MaskField(
animationTrackFlagsLabel, animationTrackFlags.intValue, TrackNames);
}
protected void InitTrackNames () {
int numEntries = 32;
TrackNames = new string[numEntries];
for (int i = 0; i < numEntries; ++i) {
TrackNames[i] = string.Format("Track {0}", i);
}
}
}
}

View File

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

View File

@ -0,0 +1,43 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2024, 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 UnityEditor;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonSubmeshGraphic))]
[CanEditMultipleObjects]
public class SkeletonGraphicSubmeshInspector : UnityEditor.Editor {
public override void OnInspectorGUI () {
EditorGUILayout.HelpBox("This component is manged by the parent SkeletonGraphic component.", MessageType.None);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1bc35530b2335ef4da1dafa6214b6ccd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,542 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
// Contributed by: Mitch Thompson
#if UNITY_2019_2_OR_NEWER
#define HINGE_JOINT_NEW_BEHAVIOUR
#endif
using Spine;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonUtilityBone)), CanEditMultipleObjects]
public class SkeletonUtilityBoneInspector : UnityEditor.Editor {
SerializedProperty mode, boneName, zPosition, position, rotation, scale, overrideAlpha, hierarchy, parentReference;
GUIContent hierarchyLabel;
//multi selected flags
bool containsFollows, containsOverrides, multiObject;
//single selected helpers
SkeletonUtilityBone utilityBone;
SkeletonUtility skeletonUtility;
bool canCreateHingeChain = false;
Dictionary<Slot, List<BoundingBoxAttachment>> boundingBoxTable = new Dictionary<Slot, List<BoundingBoxAttachment>>();
void OnEnable () {
mode = this.serializedObject.FindProperty("mode");
boneName = this.serializedObject.FindProperty("boneName");
zPosition = this.serializedObject.FindProperty("zPosition");
position = this.serializedObject.FindProperty("position");
rotation = this.serializedObject.FindProperty("rotation");
scale = this.serializedObject.FindProperty("scale");
overrideAlpha = this.serializedObject.FindProperty("overrideAlpha");
hierarchy = this.serializedObject.FindProperty("hierarchy");
hierarchyLabel = new GUIContent("Skeleton Utility Parent");
parentReference = this.serializedObject.FindProperty("parentReference");
utilityBone = (SkeletonUtilityBone)target;
skeletonUtility = utilityBone.hierarchy;
EvaluateFlags();
if (!utilityBone.valid && skeletonUtility != null) {
if (skeletonUtility.skeletonRenderer != null)
skeletonUtility.skeletonRenderer.Initialize(false);
if (skeletonUtility.skeletonGraphic != null)
skeletonUtility.skeletonGraphic.Initialize(false);
}
canCreateHingeChain = CanCreateHingeChain();
boundingBoxTable.Clear();
if (multiObject) return;
if (utilityBone.bone == null) return;
Skeleton skeleton = utilityBone.bone.Skeleton;
int slotCount = skeleton.Slots.Count;
Skin skin = skeleton.Skin;
if (skeleton.Skin == null)
skin = skeleton.Data.DefaultSkin;
for (int i = 0; i < slotCount; i++) {
Slot slot = skeletonUtility.Skeleton.Slots.Items[i];
if (slot.Bone == utilityBone.bone) {
List<Skin.SkinEntry> slotAttachments = new List<Skin.SkinEntry>();
int slotIndex = skeleton.Data.FindSlot(slot.Data.Name).Index;
skin.GetAttachments(slotIndex, slotAttachments);
List<BoundingBoxAttachment> boundingBoxes = new List<BoundingBoxAttachment>();
foreach (Skin.SkinEntry entry in slotAttachments) {
BoundingBoxAttachment boundingBoxAttachment = entry.Attachment as BoundingBoxAttachment;
if (boundingBoxAttachment != null)
boundingBoxes.Add(boundingBoxAttachment);
}
if (boundingBoxes.Count > 0)
boundingBoxTable.Add(slot, boundingBoxes);
}
}
}
void EvaluateFlags () {
if (Selection.objects.Length == 1) {
containsFollows = utilityBone.mode == SkeletonUtilityBone.Mode.Follow;
containsOverrides = utilityBone.mode == SkeletonUtilityBone.Mode.Override;
} else {
int boneCount = 0;
foreach (Object o in Selection.objects) {
GameObject go = o as GameObject;
if (go != null) {
SkeletonUtilityBone sub = go.GetComponent<SkeletonUtilityBone>();
if (sub != null) {
boneCount++;
containsFollows |= (sub.mode == SkeletonUtilityBone.Mode.Follow);
containsOverrides |= (sub.mode == SkeletonUtilityBone.Mode.Override);
}
}
}
multiObject |= (boneCount > 1);
}
}
public override void OnInspectorGUI () {
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(mode);
if (EditorGUI.EndChangeCheck()) {
containsOverrides = mode.enumValueIndex == 1;
containsFollows = mode.enumValueIndex == 0;
}
using (new EditorGUI.DisabledGroupScope(multiObject)) {
string str = boneName.stringValue;
if (str == "")
str = "<None>";
if (multiObject)
str = "<Multiple>";
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.PrefixLabel("Bone");
if (GUILayout.Button(str, EditorStyles.popup)) {
BoneSelectorContextMenu(str, ((SkeletonUtilityBone)target).hierarchy.Skeleton.Bones, "<None>", TargetBoneSelected);
}
}
}
bool isOverrideMode = mode.enumValueIndex == 1;
using (new EditorGUI.DisabledGroupScope(isOverrideMode))
EditorGUILayout.PropertyField(zPosition);
EditorGUILayout.PropertyField(position, new GUIContent("XY Position"));
EditorGUILayout.PropertyField(rotation);
EditorGUILayout.PropertyField(scale);
using (new EditorGUI.DisabledGroupScope(containsFollows)) {
EditorGUILayout.PropertyField(overrideAlpha);
EditorGUILayout.PropertyField(parentReference);
EditorGUILayout.PropertyField(hierarchy, hierarchyLabel);
}
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || utilityBone.bone.Children.Count == 0)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Child Bone", Icons.bone), GUILayout.MinWidth(120), GUILayout.Height(24)))
BoneSelectorContextMenu("", utilityBone.bone.Children, "<Recursively>", SpawnChildBoneSelected);
}
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || utilityBone.bone == null || containsOverrides)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Add Override", Icons.poseBones), GUILayout.MinWidth(120), GUILayout.Height(24)))
SpawnOverride();
}
EditorGUILayout.Space();
}
EditorGUILayout.Space();
using (new GUILayout.HorizontalScope()) {
EditorGUILayout.Space();
using (new EditorGUI.DisabledGroupScope(multiObject || !utilityBone.valid || !canCreateHingeChain)) {
if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 3D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
CreateHingeChain();
if (GUILayout.Button(SpineInspectorUtility.TempContent("Create 2D Hinge Chain", Icons.hingeChain), GUILayout.MinWidth(120), GUILayout.Height(24)))
CreateHingeChain2D();
}
EditorGUILayout.Space();
}
using (new EditorGUI.DisabledGroupScope(multiObject || boundingBoxTable.Count == 0)) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bounding Boxes", Icons.boundingBox), EditorStyles.boldLabel);
foreach (KeyValuePair<Slot, List<BoundingBoxAttachment>> entry in boundingBoxTable) {
Slot slot = entry.Key;
List<BoundingBoxAttachment> boundingBoxes = entry.Value;
EditorGUI.indentLevel++;
EditorGUILayout.LabelField(slot.Data.Name);
EditorGUI.indentLevel++;
{
foreach (BoundingBoxAttachment box in boundingBoxes) {
using (new GUILayout.HorizontalScope()) {
GUILayout.Space(30);
string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name;
if (GUILayout.Button(buttonLabel, GUILayout.Width(200))) {
utilityBone.bone.Skeleton.UpdateWorldTransform(Skeleton.Physics.Update);
Transform bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name); // Use FindChild in older versions of Unity.
if (bbTransform != null) {
PolygonCollider2D originalCollider = bbTransform.GetComponent<PolygonCollider2D>();
if (originalCollider != null)
SkeletonUtility.SetColliderPointsLocal(originalCollider, slot, box);
else
SkeletonUtility.AddBoundingBoxAsComponent(box, slot, bbTransform.gameObject);
} else {
PolygonCollider2D newPolygonCollider = SkeletonUtility.AddBoundingBoxGameObject(null, box, slot, utilityBone.transform);
bbTransform = newPolygonCollider.transform;
}
EditorGUIUtility.PingObject(bbTransform);
}
}
}
}
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
}
}
BoneFollowerInspector.RecommendRigidbodyButton(utilityBone);
serializedObject.ApplyModifiedProperties();
}
static void BoneSelectorContextMenu (string current, ExposedList<Bone> bones, string topValue, GenericMenu.MenuFunction2 callback) {
GenericMenu menu = new GenericMenu();
if (topValue != "")
menu.AddItem(new GUIContent(topValue), current == topValue, callback, null);
for (int i = 0; i < bones.Count; i++)
menu.AddItem(new GUIContent(bones.Items[i].Data.Name), bones.Items[i].Data.Name == current, callback, bones.Items[i]);
menu.ShowAsContext();
}
void TargetBoneSelected (object obj) {
if (obj == null) {
boneName.stringValue = "";
serializedObject.ApplyModifiedProperties();
} else {
Bone bone = (Bone)obj;
boneName.stringValue = bone.Data.Name;
serializedObject.ApplyModifiedProperties();
utilityBone.Reset();
}
}
void SpawnChildBoneSelected (object obj) {
if (obj == null) {
// Add recursively
foreach (Bone bone in utilityBone.bone.Children) {
GameObject go = skeletonUtility.SpawnBoneRecursively(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
SkeletonUtilityBone[] newUtilityBones = go.GetComponentsInChildren<SkeletonUtilityBone>();
foreach (SkeletonUtilityBone utilBone in newUtilityBones)
SkeletonUtilityInspector.AttachIcon(utilBone);
}
} else {
Bone bone = (Bone)obj;
GameObject go = skeletonUtility.SpawnBone(bone, utilityBone.transform, utilityBone.mode, utilityBone.position, utilityBone.rotation, utilityBone.scale);
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
}
}
void SpawnOverride () {
GameObject go = skeletonUtility.SpawnBone(utilityBone.bone, utilityBone.transform.parent, SkeletonUtilityBone.Mode.Override, utilityBone.position, utilityBone.rotation, utilityBone.scale);
go.name = go.name + " [Override]";
SkeletonUtilityInspector.AttachIcon(go.GetComponent<SkeletonUtilityBone>());
Selection.activeGameObject = go;
EditorGUIUtility.PingObject(go);
}
bool CanCreateHingeChain () {
if (utilityBone == null)
return false;
if (utilityBone.GetComponent<Rigidbody>() != null || utilityBone.GetComponent<Rigidbody2D>() != null)
return false;
if (utilityBone.bone != null && utilityBone.bone.Children.Count == 0)
return false;
Rigidbody[] rigidbodies = utilityBone.GetComponentsInChildren<Rigidbody>();
Rigidbody2D[] rigidbodies2D = utilityBone.GetComponentsInChildren<Rigidbody2D>();
return rigidbodies.Length <= 0 && rigidbodies2D.Length <= 0;
}
void CreateHingeChain2D () {
SkeletonUtilityBone kinematicParentUtilityBone = utilityBone.transform.parent.GetComponent<SkeletonUtilityBone>();
if (kinematicParentUtilityBone == null) {
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();
kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true;
GameObject commonParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
ActivateBasedOnFlipDirection commonParentActivateOnFlip = commonParentObject.AddComponent<ActivateBasedOnFlipDirection>();
commonParentActivateOnFlip.skeletonRenderer = skeletonUtility.skeletonRenderer;
commonParentActivateOnFlip.skeletonGraphic = skeletonUtility.skeletonGraphic;
// HingeChain Parent
// Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum.
GameObject normalChainParentObject = new GameObject("HingeChain");
normalChainParentObject.transform.SetParent(commonParentObject.transform);
commonParentActivateOnFlip.activeOnNormalX = normalChainParentObject;
//FollowSkeletonUtilityRootRotation followRotationComponent = normalChainParentObject.AddComponent<FollowSkeletonUtilityRootRotation>();
//followRotationComponent.reference = skeletonUtility.boneRoot;
// Follower Kinematic Rigidbody
GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower");
followerKinematicObject.transform.parent = normalChainParentObject.transform;
Rigidbody2D followerRigidbody = followerKinematicObject.AddComponent<Rigidbody2D>();
followerRigidbody.mass = mass;
followerRigidbody.isKinematic = true;
followerKinematicObject.AddComponent<FollowLocationRigidbody2D>().reference = kinematicParentUtilityBone.transform;
followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position;
followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation;
// Child Bones
SkeletonUtilityBone[] utilityBones = utilityBone.GetComponentsInChildren<SkeletonUtilityBone>();
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<HingeJoint2D>();
joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody2D>();
joint.useLimits = true;
ApplyJoint2DAngleLimits(joint, rotationLimit, childBoneParentReference, childBone.transform);
childBone.GetComponent<Rigidbody2D>().mass = mass;
childBoneParentReference = childBone.transform;
}
Duplicate2DHierarchyForFlippedChains(normalChainParentObject, commonParentActivateOnFlip, skeletonUtility.transform, rotationLimit);
UnityEditor.Selection.activeGameObject = commonParentObject;
}
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;
float minAngle = referenceAngle - rotationLimit;
float maxAngle = referenceAngle + rotationLimit;
if (maxAngle > 270f) {
minAngle -= 360f;
maxAngle -= 360f;
}
if (minAngle < -90f) {
minAngle += 360f;
maxAngle += 360f;
}
#else
float minAngle = -rotationLimit;
float maxAngle = rotationLimit;
#endif
joint.limits = new JointAngleLimits2D {
min = minAngle,
max = maxAngle
};
}
void Duplicate2DHierarchyForFlippedChains (GameObject normalChainParentObject, ActivateBasedOnFlipDirection commonParentActivateOnFlip,
Transform skeletonUtilityRoot, float rotationLimit) {
GameObject mirroredChain = GameObject.Instantiate(normalChainParentObject, normalChainParentObject.transform.position,
normalChainParentObject.transform.rotation, commonParentActivateOnFlip.transform);
mirroredChain.name = normalChainParentObject.name + " FlippedX";
commonParentActivateOnFlip.activeOnFlippedX = mirroredChain;
FollowLocationRigidbody2D followerKinematicObject = mirroredChain.GetComponentInChildren<FollowLocationRigidbody2D>();
followerKinematicObject.followFlippedX = true;
FlipBone2DHorizontal(followerKinematicObject.transform, skeletonUtilityRoot);
HingeJoint2D[] childBoneJoints = mirroredChain.GetComponentsInChildren<HingeJoint2D>();
Transform prevRotatedChild = null;
Transform parentTransformForAngles = followerKinematicObject.transform;
for (int i = 0; i < childBoneJoints.Length; ++i) {
HingeJoint2D joint = childBoneJoints[i];
FlipBone2DHorizontal(joint.transform, skeletonUtilityRoot);
ApplyJoint2DAngleLimits(joint, rotationLimit, parentTransformForAngles, joint.transform);
GameObject rotatedChild = GameObject.Instantiate(joint.gameObject, joint.transform, true);
rotatedChild.name = joint.name + " rotated";
Vector3 rotationEulerAngles = rotatedChild.transform.localEulerAngles;
rotationEulerAngles.x = 180;
rotatedChild.transform.localEulerAngles = rotationEulerAngles;
DestroyImmediate(rotatedChild.GetComponent<HingeJoint2D>());
DestroyImmediate(rotatedChild.GetComponent<BoxCollider2D>());
DestroyImmediate(rotatedChild.GetComponent<Rigidbody2D>());
DestroyImmediate(joint.gameObject.GetComponent<SkeletonUtilityBone>());
if (i > 0) {
SkeletonUtilityBone utilityBone = rotatedChild.GetComponent<SkeletonUtilityBone>();
utilityBone.parentReference = prevRotatedChild;
}
prevRotatedChild = rotatedChild.transform;
parentTransformForAngles = joint.transform;
}
mirroredChain.SetActive(false);
}
void FlipBone2DHorizontal (Transform bone, Transform mirrorPosition) {
Vector3 position = bone.position;
position.x = 2 * mirrorPosition.position.x - position.x; // = mirrorPosition + (mirrorPosition - bone.position)
bone.position = position;
Vector3 boneZ = bone.forward;
Vector3 boneX = bone.right;
boneX.x *= -1;
bone.rotation = Quaternion.LookRotation(boneZ, Vector3.Cross(boneZ, boneX));
}
void CreateHingeChain () {
SkeletonUtilityBone kinematicParentUtilityBone = utilityBone.transform.parent.GetComponent<SkeletonUtilityBone>();
if (kinematicParentUtilityBone == null) {
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;
}
SetSkeletonUtilityToFlipByRotation();
kinematicParentUtilityBone.mode = SkeletonUtilityBone.Mode.Follow;
kinematicParentUtilityBone.position = kinematicParentUtilityBone.rotation = kinematicParentUtilityBone.scale = kinematicParentUtilityBone.zPosition = true;
// HingeChain Parent
// Needs to be on top hierarchy level (not attached to the moving skeleton at least) for physics to apply proper momentum.
GameObject chainParentObject = new GameObject(skeletonUtility.name + " HingeChain Parent " + utilityBone.name);
FollowSkeletonUtilityRootRotation followRotationComponent = chainParentObject.AddComponent<FollowSkeletonUtilityRootRotation>();
followRotationComponent.reference = skeletonUtility.boneRoot;
// Follower Kinematic Rigidbody
GameObject followerKinematicObject = new GameObject(kinematicParentUtilityBone.name + " Follower");
followerKinematicObject.transform.parent = chainParentObject.transform;
Rigidbody followerRigidbody = followerKinematicObject.AddComponent<Rigidbody>();
followerRigidbody.mass = 10;
followerRigidbody.isKinematic = true;
followerKinematicObject.AddComponent<FollowLocationRigidbody>().reference = kinematicParentUtilityBone.transform;
followerKinematicObject.transform.position = kinematicParentUtilityBone.transform.position;
followerKinematicObject.transform.rotation = kinematicParentUtilityBone.transform.rotation;
// Child Bones
SkeletonUtilityBone[] utilityBones = utilityBone.GetComponentsInChildren<SkeletonUtilityBone>();
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;
HingeJoint joint = childBone.gameObject.AddComponent<HingeJoint>();
joint.axis = Vector3.forward;
joint.connectedBody = childBoneParentReference.GetComponent<Rigidbody>();
joint.useLimits = true;
joint.limits = new JointLimits {
min = -20,
max = 20
};
childBone.GetComponent<Rigidbody>().mass = childBoneParentReference.transform.GetComponent<Rigidbody>().mass * 0.75f;
childBoneParentReference = childBone.transform;
}
UnityEditor.Selection.activeGameObject = chainParentObject;
}
void SetSkeletonUtilityToFlipByRotation () {
if (!skeletonUtility.flipBy180DegreeRotation) {
skeletonUtility.flipBy180DegreeRotation = true;
Debug.Log("Set SkeletonUtility " + skeletonUtility.name + " to flip by rotation instead of negative scale (required).", skeletonUtility);
}
}
static void AttachRigidbodyAndCollider (SkeletonUtilityBone utilBone, bool enableCollider = false) {
if (utilBone.GetComponent<Collider>() == null) {
if (utilBone.bone.Data.Length == 0) {
SphereCollider sphere = utilBone.gameObject.AddComponent<SphereCollider>();
sphere.radius = 0.1f;
sphere.enabled = enableCollider;
} else {
float length = utilBone.bone.Data.Length;
BoxCollider box = utilBone.gameObject.AddComponent<BoxCollider>();
box.size = new Vector3(length, length / 3f, 0.2f);
box.center = new Vector3(length / 2f, 0, 0);
box.enabled = enableCollider;
}
}
utilBone.gameObject.AddComponent<Rigidbody>();
}
static void AttachRigidbodyAndCollider2D (SkeletonUtilityBone utilBone, bool enableCollider = false) {
if (utilBone.GetComponent<Collider2D>() == null) {
if (utilBone.bone.Data.Length == 0) {
CircleCollider2D sphere = utilBone.gameObject.AddComponent<CircleCollider2D>();
sphere.radius = 0.1f;
sphere.enabled = enableCollider;
} else {
float length = utilBone.bone.Data.Length;
BoxCollider2D box = utilBone.gameObject.AddComponent<BoxCollider2D>();
box.size = new Vector3(length, length / 3f, 0.2f);
box.offset = new Vector3(length / 2f, 0, 0);
box.enabled = enableCollider;
}
}
utilBone.gameObject.AddComponent<Rigidbody2D>();
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: b3ae20b4bcc31f645afd6f5b64f82473
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,195 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated July 28, 2023. Replaces all prior versions.
*
* Copyright (c) 2013-2023, 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.
*****************************************************************************/
#if UNITY_2018_3 || UNITY_2019 || UNITY_2018_3_OR_NEWER
#define NEW_PREFAB_SYSTEM
#endif
#if UNITY_2021_2_OR_NEWER
#define PUBLIC_SET_ICON_FOR_OBJECT
#endif
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Spine.Unity.Editor {
using Icons = SpineEditorUtilities.Icons;
[CustomEditor(typeof(SkeletonUtility))]
public class SkeletonUtilityInspector : UnityEditor.Editor {
SkeletonUtility skeletonUtility;
Skeleton skeleton;
SkeletonRenderer skeletonRenderer;
SkeletonGraphic skeletonGraphic;
#if !NEW_PREFAB_SYSTEM
bool isPrefab;
#endif
readonly GUIContent SpawnHierarchyButtonLabel = new GUIContent("Spawn Hierarchy", Icons.skeleton);
void OnEnable () {
skeletonUtility = (SkeletonUtility)target;
skeletonRenderer = skeletonUtility.skeletonRenderer;
skeletonGraphic = skeletonUtility.skeletonGraphic;
skeleton = skeletonUtility.Skeleton;
if (skeleton == null) {
if (skeletonRenderer != null) {
skeletonRenderer.Initialize(false);
skeletonRenderer.LateUpdate();
} else if (skeletonGraphic != null) {
skeletonGraphic.Initialize(false);
skeletonGraphic.LateUpdate();
}
skeleton = skeletonUtility.Skeleton;
}
if ((skeletonRenderer != null && !skeletonRenderer.valid) ||
(skeletonGraphic != null && !skeletonGraphic.IsValid)) return;
#if !NEW_PREFAB_SYSTEM
isPrefab |= PrefabUtility.GetPrefabType(this.target) == PrefabType.Prefab;
#endif
}
public override void OnInspectorGUI () {
#if !NEW_PREFAB_SYSTEM
if (isPrefab) {
GUILayout.Label(new GUIContent("Cannot edit Prefabs", Icons.warning));
return;
}
#endif
serializedObject.Update();
if ((skeletonRenderer != null && !skeletonRenderer.valid) ||
(skeletonGraphic != null && !skeletonGraphic.IsValid)) {
GUILayout.Label(new GUIContent("Spine Component invalid. Check SkeletonData asset.", Icons.warning));
return;
}
EditorGUILayout.PropertyField(serializedObject.FindProperty("boneRoot"), SpineInspectorUtility.TempContent("Skeleton Root"));
EditorGUILayout.PropertyField(serializedObject.FindProperty("flipBy180DegreeRotation"), SpineInspectorUtility.TempContent("Flip by Rotation", null,
"If true, Skeleton.ScaleX and Skeleton.ScaleY are followed " +
"by 180 degree rotation. If false, negative Transform scale is used. " +
"Note that using negative scale is consistent with previous behaviour (hence the default), " +
"however causes serious problems with rigidbodies and physics. Therefore, it is recommended to " +
"enable this parameter where possible. When creating hinge chains for a chain of skeleton bones " +
"via SkeletonUtilityBone, it is mandatory to have this parameter enabled."));
bool hasRootBone = skeletonUtility.boneRoot != null;
if (!hasRootBone)
EditorGUILayout.HelpBox("No hierarchy found. Use Spawn Hierarchy to generate GameObjects for bones.", MessageType.Info);
using (new EditorGUI.DisabledGroupScope(hasRootBone)) {
if (SpineInspectorUtility.LargeCenteredButton(SpawnHierarchyButtonLabel))
SpawnHierarchyContextMenu();
}
if (hasRootBone) {
if (SpineInspectorUtility.CenteredButton(new GUIContent("Remove Hierarchy"))) {
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Remove Hierarchy");
Undo.DestroyObjectImmediate(skeletonUtility.boneRoot.gameObject);
skeletonUtility.boneRoot = null;
}
}
serializedObject.ApplyModifiedProperties();
}
void SpawnHierarchyContextMenu () {
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Follow all bones"), false, SpawnFollowHierarchy);
menu.AddItem(new GUIContent("Follow (Root Only)"), false, SpawnFollowHierarchyRootOnly);
menu.AddSeparator("");
menu.AddItem(new GUIContent("Override all bones"), false, SpawnOverrideHierarchy);
menu.AddItem(new GUIContent("Override (Root Only)"), false, SpawnOverrideHierarchyRootOnly);
menu.ShowAsContext();
}
public static void AttachIcon (SkeletonUtilityBone boneComponent) {
Skeleton skeleton = boneComponent.hierarchy.Skeleton;
Texture2D icon = boneComponent.bone.Data.Length == 0 ? Icons.nullBone : Icons.boneNib;
foreach (IkConstraint c in skeleton.IkConstraints)
if (c.Target == boneComponent.bone) {
icon = Icons.constraintNib;
break;
}
#if PUBLIC_SET_ICON_FOR_OBJECT
EditorGUIUtility.SetIconForObject(boneComponent.gameObject, icon);
#else
typeof(EditorGUIUtility).InvokeMember("SetIconForObject", BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, null, null, new object[2] {
boneComponent.gameObject,
icon
});
#endif
}
static void AttachIconsToChildren (Transform root) {
if (root != null) {
SkeletonUtilityBone[] utilityBones = root.GetComponentsInChildren<SkeletonUtilityBone>();
foreach (SkeletonUtilityBone utilBone in utilityBones)
AttachIcon(utilBone);
}
}
void SpawnFollowHierarchy () {
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Spawn Hierarchy");
Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Follow, true, true, true);
AttachIconsToChildren(skeletonUtility.boneRoot);
}
void SpawnFollowHierarchyRootOnly () {
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Spawn Root");
Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Follow, true, true, true);
AttachIconsToChildren(skeletonUtility.boneRoot);
}
void SpawnOverrideHierarchy () {
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Spawn Hierarchy");
Selection.activeGameObject = skeletonUtility.SpawnHierarchy(SkeletonUtilityBone.Mode.Override, true, true, true);
AttachIconsToChildren(skeletonUtility.boneRoot);
}
void SpawnOverrideHierarchyRootOnly () {
Undo.RegisterCompleteObjectUndo(skeletonUtility, "Spawn Root");
Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true);
AttachIconsToChildren(skeletonUtility.boneRoot);
}
}
}

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a5b90df955eb8c2429ac67c8b2de6c5c
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: bfaea6b7e7f52bc46b8d1c3cb5e9eaa1
folderAsset: yes
DefaultImporter:
userData:

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 3fc714a0dc1cf6b4b959e073fff2844e
timeCreated: 1508165143
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 1024
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

View File

@ -0,0 +1,46 @@
fileFormatVersion: 2
guid: 68defdbc95b30a74a9ad396bfc9a2277
TextureImporter:
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: 52b12ec801461494185a4d3dc66f3d1d
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: 3d1be4ea889f3a14b864352fe49a1bde
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 289 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 04ae56b3698d3e844844cfcef2f009e7
timeCreated: 1494928093
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: 8322793223a533a4ca8be6f430256dfc
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 411 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: 97a43f11e00735147a9dc3dff6d68191
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

View File

@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 955aed20030d0504b8a9c6934a5cb47a
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: f5fff1b5caee03642ab77c9984b4bb6a
timeCreated: 1497479335
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 02822eb69e09dd947b434ab81e3d938f
timeCreated: 1494878353
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: de1a4f5ad4bdf1a4ea072c4d59ba87d8
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: c1aae98dd56b14c4b8c25360000b7e9e
timeCreated: 1494878353
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,124 @@
fileFormatVersion: 2
guid: 10e534174824cb04e8a7ec21825f2827
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 471 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: 4709175437c21f64bab9b061f98a49fc
timeCreated: 1494878353
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

View File

@ -0,0 +1,92 @@
fileFormatVersion: 2
guid: ed0736a1eb519ef42b4892d1db2426b3
timeCreated: 1494878353
licenseType: Free
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 4
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 0
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Standalone
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: Android
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
- buildTarget: WebGL
maxTextureSize: 2048
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: d226a80acc775714aa78b85e16a00e9b
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

View File

@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 2c2c6d283dcf3654baf40001c982891c
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: 2b3a6f35bbaa8414eb51a344743ee641
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 B

View File

@ -0,0 +1,53 @@
fileFormatVersion: 2
guid: a309a2e14638a204091b915126910f45
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
cubemapConvolution: 0
cubemapConvolutionSteps: 8
cubemapConvolutionExponent: 1.5
seamlessCubemap: 0
textureFormat: -1
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
rGBM: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More