From d0681d79296b0d328c42d8c1f92fdad854479d12 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 10 Nov 2020 16:44:19 +0100 Subject: [PATCH] [unity] Previous commit 75b9321 was missing two added files. Added BoundingBoxFollowerGraphic component. [..] See #1770. --- .../Following/BoundingBoxFollowerGraphic.cs | 255 ++++++++++++++++++ .../BoundingBoxFollowerGraphic.cs.meta | 11 + 2 files changed, 266 insertions(+) create mode 100644 spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs create mode 100644 spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs.meta diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs new file mode 100644 index 000000000..106a9810d --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs @@ -0,0 +1,255 @@ +/****************************************************************************** + * Spine Runtimes License Agreement + * Last updated January 1, 2020. Replaces all prior versions. + * + * Copyright (c) 2013-2020, 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 UnityEngine; +using System.Collections.Generic; + +namespace Spine.Unity { + + #if NEW_PREFAB_SYSTEM + [ExecuteAlways] + #else + [ExecuteInEditMode] + #endif + [HelpURL("http://esotericsoftware.com/spine-unity#BoundingBoxFollowerGraphic")] + public class BoundingBoxFollowerGraphic : MonoBehaviour { + internal static bool DebugMessages = true; + + #region Inspector + public SkeletonGraphic skeletonGraphic; + [SpineSlot(dataField: "skeletonGraphic", containsBoundingBoxes: true)] + public string slotName; + public bool isTrigger; + public bool clearStateOnDisable = true; + #endregion + + Slot slot; + BoundingBoxAttachment currentAttachment; + string currentAttachmentName; + PolygonCollider2D currentCollider; + + public readonly Dictionary colliderTable = new Dictionary(); + public readonly Dictionary nameTable = new Dictionary(); + + public Slot Slot { get { return slot; } } + public BoundingBoxAttachment CurrentAttachment { get { return currentAttachment; } } + public string CurrentAttachmentName { get { return currentAttachmentName; } } + public PolygonCollider2D CurrentCollider { get { return currentCollider; } } + public bool IsTrigger { get { return isTrigger; } } + + void Start () { + Initialize(); + } + + void OnEnable () { + if (skeletonGraphic != null) { + skeletonGraphic.OnRebuild -= HandleRebuild; + skeletonGraphic.OnRebuild += HandleRebuild; + } + + Initialize(); + } + + void HandleRebuild (SkeletonGraphic sr) { + //if (BoundingBoxFollowerGraphic.DebugMessages) Debug.Log("Skeleton was rebuilt. Repopulating BoundingBoxFollowerGraphic."); + Initialize(); + } + + /// + /// Initialize and instantiate the BoundingBoxFollowerGraphic colliders. This is method checks if the BoundingBoxFollowerGraphic has already been initialized for the skeleton instance and slotName and prevents overwriting unless it detects a new setup. + public void Initialize (bool overwrite = false) { + if (skeletonGraphic == null) + return; + + skeletonGraphic.Initialize(false); + + if (string.IsNullOrEmpty(slotName)) + return; + + // Don't reinitialize if the setup did not change. + if (!overwrite + && + colliderTable.Count > 0 && slot != null // Slot is set and colliders already populated. + && + skeletonGraphic.Skeleton == slot.Skeleton // Skeleton object did not change. + && + slotName == slot.data.name // Slot object did not change. + ) + return; + + slot = null; + currentAttachment = null; + currentAttachmentName = null; + currentCollider = null; + colliderTable.Clear(); + nameTable.Clear(); + + var skeleton = skeletonGraphic.Skeleton; + slot = skeleton.FindSlot(slotName); + int slotIndex = skeleton.FindSlotIndex(slotName); + + if (slot == null) { + if (BoundingBoxFollowerGraphic.DebugMessages) + Debug.LogWarning(string.Format("Slot '{0}' not found for BoundingBoxFollowerGraphic on '{1}'. (Previous colliders were disposed.)", slotName, this.gameObject.name)); + return; + } + + int requiredCollidersCount = 0; + var colliders = GetComponents(); + if (this.gameObject.activeInHierarchy) { + var canvas = skeletonGraphic.canvas; + if (canvas == null) canvas = skeletonGraphic.GetComponentInParent(); + float scale = canvas != null ? canvas.referencePixelsPerUnit : 100.0f; + + foreach (var skin in skeleton.Data.Skins) + AddCollidersForSkin(skin, slotIndex, colliders, scale, ref requiredCollidersCount); + + if (skeleton.skin != null) + AddCollidersForSkin(skeleton.skin, slotIndex, colliders, scale, ref requiredCollidersCount); + } + DisposeExcessCollidersAfter(requiredCollidersCount); + + if (BoundingBoxFollowerGraphic.DebugMessages) { + bool valid = colliderTable.Count != 0; + 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."); + } + } + } + + void AddCollidersForSkin (Skin skin, int slotIndex, PolygonCollider2D[] previousColliders, float scale, ref int collidersCount) { + if (skin == null) return; + var skinEntries = new List(); + skin.GetAttachments(slotIndex, skinEntries); + + foreach (var entry in skinEntries) { + var attachment = skin.GetAttachment(slotIndex, entry.Name); + var boundingBoxAttachment = attachment as BoundingBoxAttachment; + + if (BoundingBoxFollowerGraphic.DebugMessages && attachment != null && boundingBoxAttachment == null) + Debug.Log("BoundingBoxFollowerGraphic tried to follow a slot that contains non-boundingbox attachments: " + slotName); + + if (boundingBoxAttachment != null) { + if (!colliderTable.ContainsKey(boundingBoxAttachment)) { + var bbCollider = collidersCount < previousColliders.Length ? + previousColliders[collidersCount] : gameObject.AddComponent(); + ++collidersCount; + SkeletonUtility.SetColliderPointsLocal(bbCollider, slot, boundingBoxAttachment, scale); + bbCollider.isTrigger = isTrigger; + bbCollider.enabled = false; + bbCollider.hideFlags = HideFlags.NotEditable; + bbCollider.isTrigger = IsTrigger; + colliderTable.Add(boundingBoxAttachment, bbCollider); + nameTable.Add(boundingBoxAttachment, entry.Name); + } + } + } + } + + void OnDisable () { + if (clearStateOnDisable) + ClearState(); + + if (skeletonGraphic != null) + skeletonGraphic.OnRebuild -= HandleRebuild; + } + + public void ClearState () { + if (colliderTable != null) + foreach (var col in colliderTable.Values) + col.enabled = false; + + currentAttachment = null; + currentAttachmentName = null; + currentCollider = null; + } + + void DisposeExcessCollidersAfter (int requiredCount) { + var colliders = GetComponents(); + if (colliders.Length == 0) return; + + for (int i = requiredCount; i < colliders.Length; ++i) { + var collider = colliders[i]; + if (collider != null) { +#if UNITY_EDITOR + if (Application.isEditor && !Application.isPlaying) + DestroyImmediate(collider); + else +#endif + Destroy(collider); + } + } + } + + void LateUpdate () { + if (slot != null && slot.Attachment != currentAttachment) + MatchAttachment(slot.Attachment); + } + + /// Sets the current collider to match attachment. + /// If the attachment is not a bounding box, it will be treated as null. + void MatchAttachment (Attachment attachment) { + var bbAttachment = attachment as BoundingBoxAttachment; + + if (BoundingBoxFollowerGraphic.DebugMessages && attachment != null && bbAttachment == null) + Debug.LogWarning("BoundingBoxFollowerGraphic tried to match a non-boundingbox attachment. It will treat it as null."); + + if (currentCollider != null) + currentCollider.enabled = false; + + if (bbAttachment == null) { + currentCollider = null; + currentAttachment = null; + currentAttachmentName = null; + } else { + PolygonCollider2D foundCollider; + colliderTable.TryGetValue(bbAttachment, out foundCollider); + if (foundCollider != null) { + currentCollider = foundCollider; + currentCollider.enabled = true; + currentAttachment = bbAttachment; + currentAttachmentName = nameTable[bbAttachment]; + } else { + currentCollider = null; + currentAttachment = bbAttachment; + currentAttachmentName = null; + if (BoundingBoxFollowerGraphic.DebugMessages) Debug.LogFormat("Collider for BoundingBoxAttachment named '{0}' was not initialized. It is possibly from a new skin. currentAttachmentName will be null. You may need to call BoundingBoxFollowerGraphic.Initialize(overwrite: true);", bbAttachment.Name); + } + } + } + } + +} diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs.meta b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs.meta new file mode 100644 index 000000000..05dc86256 --- /dev/null +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/Following/BoundingBoxFollowerGraphic.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c0bf7b497af9f74280040d96cdf88da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: