// --------------------------------------------------------------------------------------------- // PhotonNetwork Framework for Unity - Copyright (C) 2020 Exit Games GmbH // developer@exitgames.com // --------------------------------------------------------------------------------------------- using System.Collections.Generic; using UnityEngine; namespace Fusion.Editor { public static class BoundsTools { public enum BoundsType { Both, MeshRenderer, Collider, Manual } // 3d private static readonly List meshFilters = new List(); private static readonly List meshRenderers = new List(); private static readonly List colliders = new List(); private static readonly List validColliders = new List(); // 2d private static readonly List spriteRenderers = new List(); #if !DISABLE_PHYSICS_2D private static readonly List colliders2D = new List(); private static readonly List validColliders2D = new List(); #endif /// /// Collect the bounds of the indicated types (MeshRenderer and/or Collider) on the object and all of its children, and returns bounds that are a sum of all of those. /// /// GameObject to start search from. /// The types of bounds to factor in. /// Whether to search all children for bounds. /// public static Bounds CollectMyBounds(this GameObject go, BoundsType factorIn, out int numOfBoundsFound, bool includeChildren = true, bool includeInactive = false) { // if we are ignoring inactive, an inactive parent is already a null. Quit here. if (!go.activeInHierarchy && !!includeInactive) { numOfBoundsFound = 0; return new Bounds(); } bool bothtype = factorIn == BoundsType.Both; bool rendtype = bothtype || factorIn == BoundsType.MeshRenderer; bool colltype = bothtype || factorIn == BoundsType.Collider; // Clear the reusables so they have counts of zero meshFilters.Clear(); meshRenderers.Clear(); colliders.Clear(); spriteRenderers.Clear(); validColliders.Clear(); #if !DISABLE_PHYSICS_2D validColliders2D.Clear(); #endif int myBoundsCount = 0; // Find all of the MeshRenderers and Colliders (as specified) if (rendtype) { if (go.activeInHierarchy) { if (includeChildren) { go.GetComponentsInChildren(includeInactive, meshRenderers); go.GetComponentsInChildren(includeInactive, meshFilters); go.GetComponentsInChildren(includeInactive, spriteRenderers); } else { go.GetComponents(meshRenderers); go.GetComponents(meshFilters); go.GetComponents(spriteRenderers); } } } if (colltype) { if (go.activeInHierarchy) { if (includeChildren) { go.GetComponentsInChildren(includeInactive, colliders); #if !DISABLE_PHYSICS_2D go.GetComponentsInChildren(includeInactive, colliders2D); #endif } else { go.GetComponents(colliders); #if !DISABLE_PHYSICS_2D go.GetComponents(colliders2D); #endif } } } // Add any MeshRenderer attached to the found MeshFilters to their own list. // We want the MeshRenderer for its bounds, but only if there is a MeshFilter, otherwise there is a risk of a 0,0,0 for (int i = 0; i < meshFilters.Count; i++) { Renderer mr = meshFilters[i].GetComponent(); if (mr && (mr.enabled || includeInactive)) { if (!meshRenderers.Contains(mr)) meshRenderers.Add(mr); } } // Collect only the valid colliders (ignore inactive if not includeInactive) for (int i = 0; i < colliders.Count; i++) { if (colliders[i].enabled || includeInactive) if (colliders[i]) validColliders.Add(colliders[i]); } #if !DISABLE_PHYSICS_2D // Collect only the valid colliders (ignore inactive if not includeInactive) for (int i = 0; i < colliders2D.Count; i++) { if (colliders2D[i] && colliders2D[i].enabled || includeInactive) // 2d colliders arrive as null but present in scene changes, test for null if (colliders2D[i]) validColliders2D.Add(colliders2D[i]); } #endif // Make sure we found some bounds objects, or we need to quit. numOfBoundsFound = meshRenderers.Count + spriteRenderers.Count + validColliders.Count #if !DISABLE_PHYSICS_2D + validColliders2D.Count #endif ; // No values means no bounds will be found, and this will break things if we try to use it. if (numOfBoundsFound == 0) { return new Bounds(); } // Get a starting bounds. We need this because the default of centered 0,0,0 will break things if the map is // offset and doesn't encapsulate the world origin. Bounds compositeBounds; if (meshRenderers.Count > 0) compositeBounds = meshRenderers[0].bounds; else if (validColliders.Count > 0) compositeBounds = validColliders[0].bounds; #if !DISABLE_PHYSICS_2D else if (validColliders2D.Count > 0 && validColliders2D[0]) compositeBounds = validColliders2D[0].bounds; #endif else if (spriteRenderers.Count > 0) compositeBounds = spriteRenderers[0].bounds; /// nothing found, return an empty bounds else return new Bounds(); for (int i = 0; i < spriteRenderers.Count; i++) { myBoundsCount++; compositeBounds.Encapsulate(spriteRenderers[i].bounds); } // Encapsulate all outer found bounds into that. We will be adding the root to itself, but no biggy, this only runs once. for (int i = 0; i < meshRenderers.Count; i++) { myBoundsCount++; compositeBounds.Encapsulate(meshRenderers[i].bounds); } for (int i = 0; i < validColliders.Count; i++) { myBoundsCount++; compositeBounds.Encapsulate(validColliders[i].bounds); } #if !DISABLE_PHYSICS_2D for (int i = 0; i < validColliders2D.Count; i++) { myBoundsCount++; if (validColliders2D[i]) compositeBounds.Encapsulate(validColliders2D[i].bounds); } #endif return compositeBounds; } public static Bounds CollectMyBounds(GameObject go, BoundsType factorIn, bool includeChildren = true) { int dummy; return CollectMyBounds(go, factorIn, out dummy, includeChildren); } } }