A small set of null-safe extension methods for everyday UnityEngine types - Transform, GameObject, Component, Animator, Vector3 - plus a StringBuilder-backed string helper.
English | 한국어
Every method guards against null and does nothing instead of throwing, so the usual "is this reference still alive?" boilerplate disappears:
// before
if (target != null)
target.position = new Vector3(8801f, target.position.y, target.position.z);
// after
target.SetPositionX(8801f);- Unity 2018.3 or newer (the example project is 2018.3.0f2)
- No external dependencies
Copy UnityExtension/UnityExtension/*.cs anywhere under your project's Assets/.
Copy UnityExtension/UnityExtension/bin/Debug/UnityExtension.dll into Assets/Plugins/.
The example project already ships it at Example/Assets/Plugins/UnityExtension.dll.
Everything lives in the UnityExtension namespace:
using UnityExtension;using UnityEngine;
using UnityExtension;
public class ExtensionExample : MonoBehaviour
{
public Animator _Animator;
void Start()
{
// Transform - set a single axis
transform.SetPositionY(8801f);
// String - no per-call StringBuilder allocation
Debug.Log(StringEx.Combine("a", "b", "c", "d")); // a/b/c/d
Debug.Log(StringEx.Concat("a", "b", "c", "d")); // abcd
Debug.Log(StringEx.Join(",", "a", "b", "c", "d")); // a,b,c,d
// GameObject - null-safe activation
gameObject.SetActiveSafely(true);
// Animator - state queries
Debug.Log(_Animator.IsPlaying());
Debug.Log(_Animator.IsPlaying("StateName"));
}
}| Method | Description |
|---|---|
SetPositionX/Y/Z(float) |
Sets one world-position axis, keeping the others. |
SetPositionXY/YZ/XZ(float, float) |
Sets two world-position axes. |
SetPositionY(Transform source, float y) |
Copies source's X/Z, overrides Y. |
SetPositionY(Vector3 source, float y) |
Same, from a Vector3. |
SetLocalPositionX/Y/Z(float) |
Local-position counterparts. |
SetLocalPositionXY/YZ/XZ(float, float) |
Local-position counterparts. |
SetLocalPosition(Transform src) |
Copies src.localPosition. |
SetLocalScaleX/Y/Z(float) |
Sets one local-scale axis. |
SetLocalScaleXY/XZ(float, float) |
Sets two local-scale axes. |
SetActiveSafely(bool) |
gameObject.SetActive guarded by a null check. |
Copy(Transform src) |
Copies world position, rotation and local scale. |
AttachNode(Transform child) |
Reparents child under this transform. |
AttachIdentityNode(Transform child) |
Reparents and resets the child's local TRS. |
Identify() |
Resets this transform's local position/rotation/scale. |
GetFullPath(Transform root = null) |
Hierarchy path up to root, e.g. Canvas/Panel/Button. |
Direction(Transform target) / Direction(Vector3 targetPosition) |
Normalized direction to the target. |
Distance(Transform target) |
Distance to the target. |
| Method | Description |
|---|---|
SetLocalPositionX(float) |
Forwards to transform.SetLocalPositionX. |
SetActiveSafely(bool) |
SetActive guarded by a null check. |
GetActiveInHierarchy() / GetActiveSelf() |
false when the object is null or destroyed. |
Bind<T>(ref T target, string path, bool deepSearch = false) |
Finds a child by path and assigns its T. |
Bind(ref GameObject target, string path, bool deepSearch = false) |
Same, assigning the GameObject. |
| Method | Description |
|---|---|
SetActiveSafely(bool) |
Activates/deactivates the owning GameObject. |
GetActiveInHierarchy() / GetActiveSelf() |
Null-safe active checks. |
Bind<T>(ref T target, string path, bool deepSearch = false) |
Same contract as GameObjectEx.Bind. |
Bind(ref GameObject target, string path, bool deepSearch = false) |
Same, assigning the GameObject. |
| Method | Description |
|---|---|
SetEnableSafely(bool) |
Sets enabled guarded by a null check. |
| Method | Description |
|---|---|
GetFocusStateInfo(int layerIndex = 0) |
Next state info while in transition, otherwise the current one. |
IsPlaying(int layerIndex = 0) |
true while the focused state loops or has not reached normalizedTime 1. |
IsPlaying(string stateName, int layerIndex = 0) |
Same, restricted to a named state. |
IsPlaying(int fullPathHash, int layerIndex = 0) |
Same, matched by fullPathHash. |
GetNormalizedTime(int fullPathHash, int layerIndex = 0) |
Normalized time, or -1 when the hash does not match. |
GetAnimatorStateLength(int layerIndex = 0) |
Length of the focused state. |
GetAnimationClipLengh(string clipName, int layerIndex = 0) |
Length of a clip on the controller (the name is misspelled in the source). |
| Method | Description |
|---|---|
Direction(Vector3 target) |
Normalized direction from this vector to target. |
XZ() |
Copy with y zeroed. |
Distance(Vector3 target) |
Distance between the two points. |
DistanceXZ(Vector3 target) |
Distance on the XZ plane only. |
Backed by one shared StringBuilder, so repeated calls do not allocate a builder per call.
| Method | Description |
|---|---|
Format(string format, ...) |
string.Format for 1-3 args or params object[]. |
Concat(...) |
Concatenates 2-4 string/object args, or params. |
Join(string separator, string[] values) |
Joins with a separator. |
Join(string separator, params object[] args) |
Same, for arbitrary objects. |
Combine(params string[] values) |
Joins with / - path style. Combine("a", "b") returns a/b. |
Bind resolves a child by path once and writes it into a field passed by ref. It returns early when target is already set, so calling it repeatedly is cheap.
[SerializeField] private Button _confirmButton;
[SerializeField] private GameObject _panel;
private void Awake()
{
this.Bind(ref _confirmButton, "Panel/ConfirmButton");
this.Bind(ref _panel, "Panel");
// deepSearch: falls back to a name search through all children
// (including inactive ones) when the path does not resolve
this.Bind(ref _confirmButton, "ConfirmButton", deepSearch: true);
}When the path cannot be resolved, Bind logs Assertion failed: <path> as a warning and leaves target untouched.
StringExis not thread-safe. All methods share one staticStringBuilder. Call them from the main thread only.StringEx.Format(format, params object[])returnsstring.Emptywhenargsis empty orformatis empty, wherestring.Formatwould return the format string. The fixed-arity overloads do not have this guard.AnimatorEx.IsPlaying(stateName, layerIndex)composes the full state name correctly only for layer 0. Layer 0 uses the"Base Layer."prefix; other layers concatenate the layer name without the separating., producingMyLayerMyStateinstead ofMyLayer.MyState. Use thefullPathHashoverload for non-base layers.GetAnimationClipLenghis misspelled (missingt). Kept as is for source compatibility; itslayerIndexparameter is unused.Bindis a lookup helper, not a cache. Nothing invalidates the reference when the hierarchy changes at runtime.- The DLL project targets .NET Framework 4.5.2 and references
UnityEngine.dllthrough an absoluteHintPath(C:/Program Files/Unity/...). Fix that reference for your install before rebuilding, or just use the sources.
Example/ is a Unity 2018.3.0f2 project. Open Assets/Example/Scenes/ExtensionExample.unity and enter Play Mode; ExtensionExample.cs exercises the Transform, String, GameObject and Animator extensions.
MIT. Copyright (c) 2019 Minu Baek. See LICENSE.