123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /******************************************************************************
- * 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#BoundingBoxFollower")]
- public class BoundingBoxFollower : MonoBehaviour {
- internal static bool DebugMessages = true;
- #region Inspector
- public SkeletonRenderer skeletonRenderer;
- [SpineSlot(dataField: "skeletonRenderer", containsBoundingBoxes: true)]
- public string slotName;
- public bool isTrigger;
- public bool clearStateOnDisable = true;
- #endregion
- Slot slot;
- BoundingBoxAttachment currentAttachment;
- string currentAttachmentName;
- PolygonCollider2D currentCollider;
- public readonly Dictionary<BoundingBoxAttachment, PolygonCollider2D> colliderTable = new Dictionary<BoundingBoxAttachment, PolygonCollider2D>();
- public readonly Dictionary<BoundingBoxAttachment, string> nameTable = new Dictionary<BoundingBoxAttachment, string>();
- 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 (skeletonRenderer != null) {
- skeletonRenderer.OnRebuild -= HandleRebuild;
- skeletonRenderer.OnRebuild += HandleRebuild;
- }
- Initialize();
- }
- void HandleRebuild (SkeletonRenderer sr) {
- //if (BoundingBoxFollower.DebugMessages) Debug.Log("Skeleton was rebuilt. Repopulating BoundingBoxFollower.");
- Initialize();
- }
- /// <summary>
- /// Initialize and instantiate the BoundingBoxFollower colliders. This is method checks if the BoundingBoxFollower has already been initialized for the skeleton instance and slotName and prevents overwriting unless it detects a new setup.</summary>
- public void Initialize (bool overwrite = false) {
- if (skeletonRenderer == null)
- return;
- skeletonRenderer.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.
- &&
- skeletonRenderer.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 = skeletonRenderer.skeleton;
- if (skeleton == null)
- return;
- slot = skeleton.FindSlot(slotName);
- int slotIndex = skeleton.FindSlotIndex(slotName);
- if (slot == null) {
- if (BoundingBoxFollower.DebugMessages)
- Debug.LogWarning(string.Format("Slot '{0}' not found for BoundingBoxFollower on '{1}'. (Previous colliders were disposed.)", slotName, this.gameObject.name));
- return;
- }
- int requiredCollidersCount = 0;
- var colliders = GetComponents<PolygonCollider2D>();
- if (this.gameObject.activeInHierarchy) {
- foreach (var skin in skeleton.Data.Skins)
- AddCollidersForSkin(skin, slotIndex, colliders, ref requiredCollidersCount);
- if (skeleton.skin != null)
- AddCollidersForSkin(skeleton.skin, slotIndex, colliders, ref requiredCollidersCount);
- }
- DisposeExcessCollidersAfter(requiredCollidersCount);
- if (BoundingBoxFollower.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, ref int collidersCount) {
- if (skin == null) return;
- var skinEntries = new List<Skin.SkinEntry>();
- skin.GetAttachments(slotIndex, skinEntries);
- foreach (var entry in skinEntries) {
- var attachment = skin.GetAttachment(slotIndex, entry.Name);
- var boundingBoxAttachment = attachment as BoundingBoxAttachment;
- if (BoundingBoxFollower.DebugMessages && attachment != null && boundingBoxAttachment == null)
- Debug.Log("BoundingBoxFollower 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<PolygonCollider2D>();
- ++collidersCount;
- SkeletonUtility.SetColliderPointsLocal(bbCollider, slot, boundingBoxAttachment);
- 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 (skeletonRenderer != null)
- skeletonRenderer.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<PolygonCollider2D>();
- 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);
- }
- /// <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 (BoundingBoxFollower.DebugMessages && attachment != null && bbAttachment == null)
- Debug.LogWarning("BoundingBoxFollower 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 (BoundingBoxFollower.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 BoundingBoxFollower.Initialize(overwrite: true);", bbAttachment.Name);
- }
- }
- }
- }
- }
|