mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-10 09:08:42 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
05c7cde3c0
@ -12,7 +12,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-c works with data exported from Spine version 3.3.07.
|
||||
spine-c works with data exported from the latest version of Spine.
|
||||
|
||||
spine-c supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-cocos2d-objc works with data exported from Spine version 3.3.07.
|
||||
spine-cocos2d-objc works with data exported from from the latest version of Spine.
|
||||
|
||||
spine-cocos2d-objc supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-cocos2dx works with data exported from Spine version 3.3.07.
|
||||
spine-cocos2dx works with data exported from from the latest version of Spine.
|
||||
|
||||
spine-cocos2dx supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-csharp works with data exported from Spine 3.3.07.
|
||||
spine-csharp works with data exported from the latest version of Spine.
|
||||
|
||||
spine-csharp supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-monogame works with data exported from Spine 3.3.07.
|
||||
spine-monogame works with data exported from from the latest version of Spine.
|
||||
|
||||
spine-monogame supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-sfml works with data exported from Spine version 3.3.07.
|
||||
spine-sfml works with data exported from the latest version of Spine.
|
||||
|
||||
spine-sfml supports all Spine features.
|
||||
|
||||
|
||||
@ -32,28 +32,30 @@ using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Spine.Unity {
|
||||
|
||||
[ExecuteInEditMode]
|
||||
public class BoundingBoxFollower : MonoBehaviour {
|
||||
|
||||
#region Inspector
|
||||
public SkeletonRenderer skeletonRenderer;
|
||||
|
||||
[SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)]
|
||||
public string slotName;
|
||||
#endregion
|
||||
|
||||
Slot slot;
|
||||
BoundingBoxAttachment currentAttachment;
|
||||
PolygonCollider2D currentCollider;
|
||||
string currentAttachmentName;
|
||||
PolygonCollider2D currentCollider;
|
||||
|
||||
bool valid = false;
|
||||
bool hasReset;
|
||||
|
||||
public Dictionary<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
|
||||
public Dictionary<BoundingBoxAttachment, string> attachmentNameTable = new Dictionary<BoundingBoxAttachment, string>();
|
||||
public readonly Dictionary<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
|
||||
public readonly Dictionary<BoundingBoxAttachment, string> attachmentNameTable = new Dictionary<BoundingBoxAttachment, string>();
|
||||
|
||||
public string CurrentAttachmentName { get { return currentAttachmentName; } }
|
||||
public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } }
|
||||
public PolygonCollider2D CurrentCollider { get { return currentCollider; } }
|
||||
public Slot Slot { get { return slot; } }
|
||||
public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } }
|
||||
public string CurrentAttachmentName { get { return currentAttachmentName; } }
|
||||
public PolygonCollider2D CurrentCollider { get { return currentCollider; } }
|
||||
|
||||
void OnEnable () {
|
||||
ClearColliders();
|
||||
@ -62,74 +64,96 @@ namespace Spine.Unity {
|
||||
skeletonRenderer = GetComponentInParent<SkeletonRenderer>();
|
||||
|
||||
if (skeletonRenderer != null) {
|
||||
skeletonRenderer.OnRebuild -= HandleReset;
|
||||
skeletonRenderer.OnRebuild += HandleReset;
|
||||
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||
skeletonRenderer.OnRebuild += HandleRebuild;
|
||||
|
||||
if (hasReset)
|
||||
HandleReset(skeletonRenderer);
|
||||
HandleRebuild(skeletonRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
void OnDisable () {
|
||||
skeletonRenderer.OnRebuild -= HandleReset;
|
||||
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||
}
|
||||
|
||||
void Start () {
|
||||
if (!hasReset && skeletonRenderer != null)
|
||||
HandleReset(skeletonRenderer);
|
||||
HandleRebuild(skeletonRenderer);
|
||||
}
|
||||
|
||||
public void HandleReset (SkeletonRenderer renderer) {
|
||||
public void HandleRebuild (SkeletonRenderer renderer) {
|
||||
if (string.IsNullOrEmpty(slotName))
|
||||
return;
|
||||
|
||||
hasReset = true;
|
||||
|
||||
ClearColliders();
|
||||
colliderTable.Clear();
|
||||
|
||||
if (skeletonRenderer.skeleton == null) {
|
||||
skeletonRenderer.OnRebuild -= HandleReset;
|
||||
skeletonRenderer.OnRebuild -= HandleRebuild;
|
||||
skeletonRenderer.Initialize(false);
|
||||
skeletonRenderer.OnRebuild += HandleReset;
|
||||
skeletonRenderer.OnRebuild += HandleRebuild;
|
||||
}
|
||||
|
||||
var skeleton = skeletonRenderer.skeleton;
|
||||
slot = skeleton.FindSlot(slotName);
|
||||
int slotIndex = skeleton.FindSlotIndex(slotName);
|
||||
|
||||
foreach (var skin in skeleton.Data.Skins) {
|
||||
var attachmentNames = new List<string>();
|
||||
skin.FindNamesForSlot(slotIndex, attachmentNames);
|
||||
if (this.gameObject.activeInHierarchy) {
|
||||
foreach (var skin in skeleton.Data.Skins) {
|
||||
var attachmentNames = new List<string>();
|
||||
skin.FindNamesForSlot(slotIndex, attachmentNames);
|
||||
|
||||
foreach (var attachmentName in attachmentNames) {
|
||||
var attachment = skin.GetAttachment(slotIndex, attachmentName);
|
||||
var boundingBoxAttachment = attachment as BoundingBoxAttachment;
|
||||
if (boundingBoxAttachment != null) {
|
||||
var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true);
|
||||
bbCollider.enabled = false;
|
||||
bbCollider.hideFlags = HideFlags.HideInInspector;
|
||||
colliderTable.Add(boundingBoxAttachment, bbCollider);
|
||||
attachmentNameTable.Add(boundingBoxAttachment, attachmentName);
|
||||
foreach (var attachmentName in attachmentNames) {
|
||||
var attachment = skin.GetAttachment(slotIndex, attachmentName);
|
||||
var boundingBoxAttachment = attachment as BoundingBoxAttachment;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (attachment != null && boundingBoxAttachment == null)
|
||||
Debug.Log("BoundingBoxFollower tried to follow a slot that contains non-boundingbox attachments.");
|
||||
#endif
|
||||
|
||||
if (boundingBoxAttachment != null) {
|
||||
var bbCollider = SkeletonUtility.AddBoundingBoxAsComponent(boundingBoxAttachment, gameObject, true);
|
||||
bbCollider.enabled = false;
|
||||
bbCollider.hideFlags = HideFlags.NotEditable;
|
||||
colliderTable.Add(boundingBoxAttachment, bbCollider);
|
||||
attachmentNameTable.Add(boundingBoxAttachment, attachmentName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
valid = colliderTable.Count != 0;
|
||||
|
||||
if (!valid)
|
||||
Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!");
|
||||
if (!valid) {
|
||||
if (this.gameObject.activeInHierarchy)
|
||||
Debug.LogWarning("Bounding Box Follower not valid! Slot [" + slotName + "] does not contain any Bounding Box Attachments!");
|
||||
else
|
||||
Debug.LogWarning("Bounding Box Follower tried to rebuild as a prefab.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ClearColliders () {
|
||||
var colliders = GetComponents<PolygonCollider2D>();
|
||||
if (colliders.Length == 0) return;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying) {
|
||||
foreach (var c in colliders)
|
||||
Destroy(c);
|
||||
foreach (var c in colliders) {
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
}
|
||||
} else {
|
||||
foreach (var c in colliders)
|
||||
DestroyImmediate(c);
|
||||
}
|
||||
#else
|
||||
foreach (var c in colliders)
|
||||
if (c != null)
|
||||
Destroy(c);
|
||||
#endif
|
||||
|
||||
colliderTable.Clear();
|
||||
attachmentNameTable.Clear();
|
||||
@ -139,25 +163,32 @@ namespace Spine.Unity {
|
||||
if (!skeletonRenderer.valid)
|
||||
return;
|
||||
|
||||
if (slot != null) {
|
||||
if (slot.Attachment != currentAttachment)
|
||||
SetCurrent((BoundingBoxAttachment)slot.Attachment);
|
||||
}
|
||||
if (slot != null && slot.Attachment != currentAttachment)
|
||||
MatchAttachment(slot.Attachment);
|
||||
}
|
||||
|
||||
void SetCurrent (BoundingBoxAttachment attachment) {
|
||||
if (currentCollider)
|
||||
/// <summary>Sets the current collider to match attachment.</summary>
|
||||
/// <param name="attachment">If the attachment is not a bounding box, it will be treated as null.</param>
|
||||
void MatchAttachment (Attachment attachment) {
|
||||
var bbAttachment = attachment as BoundingBoxAttachment;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
if (attachment != null && bbAttachment == null)
|
||||
Debug.LogWarning("BoundingBoxFollower tried to match a non-boundingbox attachment. It will treat it as null.");
|
||||
#endif
|
||||
|
||||
if (currentCollider != null)
|
||||
currentCollider.enabled = false;
|
||||
|
||||
if (attachment != null) {
|
||||
currentCollider = colliderTable[attachment];
|
||||
currentCollider.enabled = true;
|
||||
} else {
|
||||
if (bbAttachment == null) {
|
||||
currentCollider = null;
|
||||
} else {
|
||||
currentCollider = colliderTable[bbAttachment];
|
||||
currentCollider.enabled = true;
|
||||
}
|
||||
|
||||
currentAttachment = attachment;
|
||||
currentAttachmentName = currentAttachment == null ? null : attachmentNameTable[attachment];
|
||||
currentAttachment = bbAttachment;
|
||||
currentAttachmentName = currentAttachment == null ? null : attachmentNameTable[bbAttachment];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,7 +31,6 @@
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections;
|
||||
|
||||
namespace Spine.Unity.Editor {
|
||||
|
||||
@ -39,7 +38,8 @@ namespace Spine.Unity.Editor {
|
||||
public class BoundingBoxFollowerInspector : UnityEditor.Editor {
|
||||
SerializedProperty skeletonRenderer, slotName;
|
||||
BoundingBoxFollower follower;
|
||||
bool needToReset = false;
|
||||
bool rebuildRequired = false;
|
||||
bool addBoneFollower = false;
|
||||
|
||||
void OnEnable () {
|
||||
skeletonRenderer = serializedObject.FindProperty("skeletonRenderer");
|
||||
@ -48,41 +48,63 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI () {
|
||||
if (needToReset) {
|
||||
follower.HandleReset(null);
|
||||
needToReset = false;
|
||||
bool isInspectingPrefab = (PrefabUtility.GetPrefabType(target) == PrefabType.Prefab);
|
||||
bool repaintEvent = UnityEngine.Event.current.type == EventType.Repaint;
|
||||
|
||||
if (rebuildRequired) {
|
||||
follower.HandleRebuild(null);
|
||||
rebuildRequired = false;
|
||||
}
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(skeletonRenderer);
|
||||
EditorGUILayout.PropertyField(slotName, new GUIContent("Slot"));
|
||||
|
||||
if (EditorGUI.EndChangeCheck()){
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
needToReset = true;
|
||||
if (!isInspectingPrefab)
|
||||
rebuildRequired = true;
|
||||
}
|
||||
|
||||
bool hasBone = follower.GetComponent<BoneFollower>() != null;
|
||||
|
||||
EditorGUI.BeginDisabledGroup(hasBone || follower.Slot == null);
|
||||
{
|
||||
bool hasBoneFollower = follower.GetComponent<BoneFollower>() != null;
|
||||
using (new EditorGUI.DisabledGroupScope(hasBoneFollower || follower.Slot == null)) {
|
||||
if (GUILayout.Button(new GUIContent("Add Bone Follower", SpineEditorUtilities.Icons.bone))) {
|
||||
var boneFollower = follower.gameObject.AddComponent<BoneFollower>();
|
||||
boneFollower.boneName = follower.Slot.Data.BoneData.Name;
|
||||
addBoneFollower = true;
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
if (isInspectingPrefab) {
|
||||
follower.colliderTable.Clear();
|
||||
follower.attachmentNameTable.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.
|
||||
var collider = follower.GetComponent<PolygonCollider2D>();
|
||||
if (collider != null) Debug.LogWarning("Found BoundingBoxFollower collider components in prefab. These are disposed and regenerated at runtime.");
|
||||
|
||||
//GUILayout.Space(20);
|
||||
GUILayout.Label("Attachment Names", EditorStyles.boldLabel);
|
||||
foreach (var kp in follower.attachmentNameTable) {
|
||||
string name = kp.Value;
|
||||
var collider = follower.colliderTable[kp.Key];
|
||||
bool isPlaceholder = name != kp.Key.Name;
|
||||
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? name : name + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled);
|
||||
} else {
|
||||
EditorGUILayout.LabelField(string.Format("Attachment Names ({0} PolygonCollider2D)", follower.colliderTable.Count), EditorStyles.boldLabel);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
foreach (var kp in follower.attachmentNameTable) {
|
||||
string attachmentName = kp.Value;
|
||||
var collider = follower.colliderTable[kp.Key];
|
||||
bool isPlaceholder = attachmentName != kp.Key.Name;
|
||||
collider.enabled = EditorGUILayout.ToggleLeft(new GUIContent(!isPlaceholder ? attachmentName : attachmentName + " [" + kp.Key.Name + "]", isPlaceholder ? SpineEditorUtilities.Icons.skinPlaceholder : SpineEditorUtilities.Icons.boundingBox), collider.enabled);
|
||||
}
|
||||
if (EditorGUI.EndChangeCheck()) {
|
||||
SceneView.RepaintAll();
|
||||
}
|
||||
|
||||
if (!Application.isPlaying)
|
||||
EditorGUILayout.HelpBox("\nAt runtime, BoundingBoxFollower enables and disables PolygonCollider2Ds based on the currently active attachment in the slot.\n\nCheckboxes in Edit Mode are only for preview. Checkbox states are not saved.\n", MessageType.Info);
|
||||
}
|
||||
|
||||
if (addBoneFollower && repaintEvent) {
|
||||
var boneFollower = follower.gameObject.AddComponent<BoneFollower>();
|
||||
boneFollower.boneName = follower.Slot.Data.BoneData.Name;
|
||||
addBoneFollower = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -235,7 +235,6 @@ namespace Spine.Unity {
|
||||
ExposedList<Slot> drawOrder = skeleton.drawOrder;
|
||||
var drawOrderItems = drawOrder.Items;
|
||||
int drawOrderCount = drawOrder.Count;
|
||||
int separatorSlotCount = separatorSlots.Count;
|
||||
bool renderMeshes = this.renderMeshes;
|
||||
|
||||
// Clear last state of attachments and submeshes
|
||||
@ -298,9 +297,7 @@ namespace Spine.Unity {
|
||||
}
|
||||
|
||||
#if !SPINE_TK2D
|
||||
// Material material = (Material)((AtlasRegion)rendererObject).page.rendererObject; // For no customSlotMaterials
|
||||
|
||||
Material material;
|
||||
Material material; //= (Material)((AtlasRegion)rendererObject).page.rendererObject; // For no customSlotMaterials
|
||||
if (isCustomSlotMaterialsPopulated) {
|
||||
if (!customSlotMaterials.TryGetValue(slot, out material)) {
|
||||
material = (Material)((AtlasRegion)rendererObject).page.rendererObject;
|
||||
@ -313,8 +310,8 @@ namespace Spine.Unity {
|
||||
#endif
|
||||
|
||||
// Create a new SubmeshInstruction when material changes. (or when forced to separate by a submeshSeparator)
|
||||
bool forceSeparate = (separatorSlotCount > 0 && separatorSlots.Contains(slot));
|
||||
if ((vertexCount > 0 && lastMaterial.GetInstanceID() != material.GetInstanceID()) || forceSeparate) {
|
||||
bool forceSeparate = (separatorSlots.Count > 0 && separatorSlots.Contains(slot));
|
||||
if (vertexCount > 0 && (lastMaterial.GetInstanceID() != material.GetInstanceID() || forceSeparate)) {
|
||||
workingSubmeshInstructions.Add(
|
||||
new Spine.Unity.MeshGeneration.SubmeshInstruction {
|
||||
skeleton = this.skeleton,
|
||||
@ -327,14 +324,13 @@ namespace Spine.Unity {
|
||||
forceSeparate = forceSeparate
|
||||
}
|
||||
);
|
||||
|
||||
submeshTriangleCount = 0;
|
||||
submeshVertexCount = 0;
|
||||
submeshFirstVertex = vertexCount;
|
||||
submeshStartSlotIndex = i;
|
||||
}
|
||||
// Update state for the next iteration.
|
||||
lastMaterial = material;
|
||||
|
||||
submeshTriangleCount += attachmentTriangleCount;
|
||||
vertexCount += attachmentVertexCount;
|
||||
submeshVertexCount += attachmentVertexCount;
|
||||
@ -382,10 +378,7 @@ namespace Spine.Unity {
|
||||
#if SPINE_OPTIONAL_RENDEROVERRIDE
|
||||
if (this.generateMeshOverride != null) {
|
||||
this.generateMeshOverride(workingInstruction);
|
||||
|
||||
if (disableRenderingOnOverride) {
|
||||
return;
|
||||
}
|
||||
if (disableRenderingOnOverride) return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -876,9 +869,8 @@ namespace Spine.Unity {
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++) {
|
||||
triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
|
||||
}
|
||||
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii++, triangleIndex++)
|
||||
triangles[triangleIndex] = firstVertex + attachmentTriangles[ii];
|
||||
#endif
|
||||
|
||||
firstVertex += attachmentVertexCount;
|
||||
|
||||
@ -14,7 +14,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-unity works with data exported from Spine 3.3.07.
|
||||
spine-unity works with data exported from the latest version of Spine.
|
||||
|
||||
spine-unity supports all Spine features.
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-xna works with data exported from Spine 3.7.07.
|
||||
spine-xna works with data exported from the latest version of Spine.
|
||||
|
||||
spine-xna supports all Spine features.
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user