|
/// @creator: Slipp Douglas Thompson |
|
/// @license: Public Domain per The Unlicense. See <http://unlicense.org/>. |
|
/// @purpose: More-flexible GO-tree searching for Components by type, configurable via `SearchExtent` enum arg. |
|
/// @why: Because this functionality should be built-into Unity. |
|
/// @usage: Call `this.gameObject.FindComponent<«component-type»>(«SearchExtent-type»);`. |
|
/// @intended project path: Assets/Plugins/UnityEngine Extensions/GameObjectFindComponentExtension.cs |
|
/// @interwebsouce: https://gist.github.com/capnslipp/ac26e38fce770b5c4594 |
|
|
|
using System; |
|
using UnityEngine; |
|
|
|
|
|
|
|
public static class GameObjectFindComponentExtension |
|
{ |
|
public enum SearchExtent { |
|
Local = 1, |
|
Ancestry, // you are part of your own ancestry |
|
Ancestors, // you are *not* your own ancestor |
|
Descendantry, // you are part of your own descendantry |
|
Descendants, // you are *not* your own descendant |
|
|
|
None = 0 |
|
} |
|
|
|
public static Component FindComponent(this GameObject @this, |
|
Type componentType, |
|
SearchExtent extent=SearchExtent.Local |
|
) |
|
{ |
|
if (@this == null) |
|
throw new ArgumentNullException("This extension method was called on a null object, which is not allowed.", "@this"); |
|
|
|
string failMessageHead = null; |
|
Component foundComponent = SearchForComponent(@this, componentType, extent, out failMessageHead); |
|
|
|
if (foundComponent == null) |
|
Debug.LogWarning(failMessageHead+" "+@this.GetType()+".", @this); |
|
|
|
return foundComponent; |
|
} |
|
|
|
public static ComponentT FindComponent<ComponentT>(this GameObject @this, |
|
SearchExtent extent=SearchExtent.Local |
|
) where ComponentT : Component |
|
{ |
|
return (ComponentT)FindComponent(@this, typeof(ComponentT), extent); |
|
} |
|
|
|
|
|
static Component SearchForComponent( |
|
GameObject localGameObject, |
|
Type componentType, |
|
SearchExtent extent, |
|
out string failMessageHead |
|
) |
|
{ |
|
switch (extent) { |
|
case SearchExtent.Local: |
|
return SearchForComponentInLocal(localGameObject, componentType, out failMessageHead); |
|
case SearchExtent.Ancestry: |
|
return SearchForComponentInAncestry(localGameObject, componentType, out failMessageHead, skipLocal: false); |
|
case SearchExtent.Ancestors: |
|
return SearchForComponentInAncestry(localGameObject, componentType, out failMessageHead, skipLocal: true); |
|
case SearchExtent.Descendantry: |
|
return SearchForComponentInDescendantry(localGameObject, componentType, out failMessageHead, skipLocal: false); |
|
case SearchExtent.Descendants: |
|
return SearchForComponentInDescendantry(localGameObject, componentType, out failMessageHead, skipLocal: true); |
|
|
|
default: |
|
failMessageHead = null; |
|
return null; |
|
} |
|
} |
|
|
|
static Component SearchForComponentInLocal( |
|
GameObject localGameObject, |
|
Type componentType, |
|
out string failMessageHead |
|
) |
|
{ |
|
Component foundComponent = localGameObject.GetComponent(componentType); |
|
|
|
if (foundComponent != null) { |
|
failMessageHead = null; |
|
return foundComponent; |
|
} |
|
else { |
|
failMessageHead = string.Format("No "+componentType+" assigned and unable to find one for this"); |
|
return null; |
|
} |
|
} |
|
|
|
static Component SearchForComponentInAncestry( |
|
GameObject localGameObject, |
|
Type componentType, |
|
out string failMessageHead, |
|
bool skipLocal=false |
|
) |
|
{ |
|
Transform searchTransform = localGameObject.transform; |
|
if (skipLocal) |
|
searchTransform = localGameObject.transform.parent; |
|
|
|
Component foundComponent = null; |
|
while (searchTransform != null) { |
|
foundComponent = searchTransform.GetComponent(componentType); |
|
|
|
if (foundComponent != null) |
|
break; |
|
|
|
searchTransform = searchTransform.parent; |
|
} |
|
|
|
if (foundComponent != null) { |
|
failMessageHead = null; |
|
return foundComponent; |
|
} |
|
else { |
|
failMessageHead = string.Format("Unable to find a "+componentType+" "+(skipLocal ? "" : "on or ")+"above this"); |
|
return null; |
|
} |
|
} |
|
|
|
static Component SearchForComponentInDescendantry( |
|
GameObject localGameObject, |
|
Type componentType, |
|
out string failMessageHead, |
|
bool skipLocal=false |
|
) |
|
{ |
|
failMessageHead = null; |
|
|
|
Component[] foundComponents = localGameObject.GetComponentsInChildren(componentType, includeInactive: true); // actually searches self and all descendents, despite the name |
|
foreach (Component oneComponent in foundComponents) |
|
{ |
|
if (oneComponent.gameObject == localGameObject) { |
|
if (skipLocal) |
|
continue; |
|
else |
|
return oneComponent; |
|
} |
|
else { // non-local |
|
return oneComponent; |
|
} |
|
} |
|
|
|
failMessageHead = string.Format("Unable to find a "+componentType+" "+(skipLocal ? "" : "on or ")+"under this"); |
|
return null; |
|
} |
|
} |