General utilities for Unity.
Warning
Unity 2020.1+ (lower versions may be supported, but will miss features).
Simple static class for managing object pools.
// Retrieve or instance an object from the pool
MyComponent instance = InstancePool.Get(Prefab);
// Return an instance to the pool.
// The instance is moved to the Instance Pool scene and deactivated.
InstancePool.Pool(Prefab, instance);
TrimExcess
will reduce the size of the pool (by deleting pooled instances) to the limits set by SetCapacity
.
This is helpful when reloading a game/scene to ensure the pool never gets out of hand in the long term.
// Sets the pool to only keep 30 instances of a specific prefab when TrimExcess is called.
InstancePool.SetCapacity(Prefab, 30);
// Sets the pool to only keep 30 instances of all pooled PoolObject prefabs when TrimExcess is called.
InstancePool.SetCapacities<PoolObject>(30);
// Trims all instances in every pool down to their capacities (20 is the default argument)
InstancePool.TrimExcess();
// Trims instances in the PoolObject pool down to their capacities (20 is the default argument)
InstancePool.TrimExcess<PoolObject>();
// Trims instances from a specific prefab down to its capacity (20 is the default argument)
InstancePool.TrimExcess(Prefab);
// Instances and immediately pools 30 instances of prefab spread over 30 frames.
StartCoroutine(InstancePool.WarmupCoroutine(Prefab, 30));
// Instances and immediately pools 30 instances of prefab.
InstancePool.Warmup(Prefab, 30);
It's advised to avoid retaining references from pooled objects or prefabs to other objects in the scene. Clear these references before an object is pooled, then call TrimExcess
instead to bring these allocated objects down to a predictable level.
When this cannot be achieved, because we're dealing with static pools you may want to ensure that they're completely unloaded at a safe point.
Having references from pooled objects retained in a pool is memory leak unless those references are reset in rotation, so the following methods allow you to clean up.
// Remove a pool from the system, and optionally handle what happens to the currently pooled instances.
InstancePool.RemovePool(Prefab, instance => Destroy(instance.gameObject));
// Remove all pools of a component type from the system, and optionally handle what happens to the currently pooled instances.
InstancePool.RemovePools<MyComponent>(instance => Destroy(instance.gameObject));
// Remove *all pools*, and optionally handle what happens to the currently pooled instances. This can be done to resolve all possible memory leaks.
// You may also choose to unload the instance pool scene, but there is no utility method for doing this.
InstancePool.RemovePools(instance => Destroy(instance.gameObject));
You can use different types of pools with the Override
method. Custom pools can also be created by inheriting from IComponentPool<T>
.
Supported pool types are:
Type | Description |
---|---|
ExpandablePool |
A pool that will expand to contain all instances pooled into it. Only instances that are freed to the pool can be returned by Get . |
ExpandablePoolUnchecked |
ExpandablePool , but there are no safety checks performed in high-frequency operations.If abused, you can enter instances into the pool multiple times or destroy objects that are in the pool, which will result in logic errors and unhandled exceptions. |
CircularPool |
A fixed-capacity pool that uses the least recent entry when Get is called.Instances are always considered a part of the pool, and can be requested at any moment. The pool will grow to the internal size unless warmed up beforehand. This pool use useful in circumstances where there's a fixed count of an unimportant resource, like bullet hole decals for example. |
Data type for associating serialized data with an enum.
Note
This data is kept updated via the Inspector. To maintain parity it is important to inspect these fields when updating the associated enums.
public enum Shape
{
Box,
Sphere,
Capsule,
Cylinder
}
[System.Serializable]
public class ShapeElement
{
public string Name;
public Material Material;
public Mesh Mesh;
}
You can optionally add the [HideFirstEnumValue]
attribute to hide the None/0 value if it is irrelevant.
[SerializeField]
private EnumToValue<Shape, ShapeElement> _data;
[SerializeField] private Shape _shape;
private void Start()
{
GameObject g = gameObject;
if (!g.TryGetComponent(out MeshRenderer meshRenderer))
meshRenderer = g.AddComponent<MeshRenderer>();
if (!g.TryGetComponent(out MeshFilter meshFilter))
meshFilter = g.AddComponent<MeshFilter>();
//Configure target components with our data
var value = _data[_shape];
g.name = value.Name;
meshRenderer.sharedMaterial = value.Material;
meshFilter.sharedMesh = value.Mesh;
}
A ScriptableObject containing an EnumToValue
structure for data reuse.
public class DataDescriptionExample : EnumDataDescription<EnumToValue<Shape, ShapeElement>> { }
A vertical ScrollView that contains fixed-height elements that are pooled.
Navigation is automatically set within the list's contents.
// Binds a list to the ListView
public void Bind(IList elements)
// A UnityEvent to bind UI items with list item content
// int index, RectTransform root
public BindEvent BindItem
// Call to regenerate content when the bound list changes
public void Refresh()
Helper class for managing multiple values so they always total the same amount.
The example below will keep all child Sliders the component in sync proportionally.
private void Start()
{
var sliders = GetComponentsInChildren<Slider>();
var proportionalValues = new ProportionalValues(sliders.Length);
for (int i = 0; i < proportionalValues.Length; i++)
{
int iLocal = i;
// Initialise the sliders to their calculated values.
sliders[i].SetValueWithoutNotify(proportionalValues[i]);
// When a slider changes, set the associated proportional value (this will force a recalculation)
sliders[i].onValueChanged.AddListener(v => proportionalValues[iLocal] = v);
}
// When the proportional value changes, inform the sliders.
proportionalValues.OnValueChanged += (index, v) => sliders[index].SetValueWithoutNotify(v);
}
Bounds2D
, (and NullableBounds2D
) is a parallel to Bounds
that implements similar methods.
Rect
is commonly used, but it's not built for purpose.
Bounds
, but Encapsulate
doesn't expand from the default (0,0,0)
when first called.
If a value has not yet been assigned methods like Intersects
, IntersectRay
, Contains
, will return false.
Other query methods have TryGet
alternatives.
Name | Description |
---|---|
IList<T>.RemoveUnordered IList<T>.RemoveUnorderedAt |
Removes an item from a list without caring about maintaining order. (Moves the last element into the hole and removes it from the end) |
UnityEngine.Object.TrimName |
Trims appended text from Object names. Will trim (Clone) by default.This is not recursive, and only will remove a single instance of the word. |
Name | Description |
---|---|
EditorOnly |
A call to a lambda that will be stripped in builds. |
DebugOnly |
A call to a lambda that will be stripped in release builds. |
Many helper functions for random editor functionality I use, often or otherwise.
Name | Description |
---|---|
Assets | |
LoadAssetOfType LoadAssetsOfType |
Loads assets matching a type with an optional name query. |
Project Browser | |
GetProjectBrowserWindow |
Gets an instance of the project browser EditorWindow. |
ShowFolderContents |
Reveals the contents of a folder in the project browser. |
GetCurrentlyFocusedProjectFolder |
Returns the currently focused folder in the project browser. |
SetProjectBrowserSearch |
Sets the value of the project browser search. |
Editor Extensions | |
GetEditorExtensionsOfType |
Returns lists of containing newly instanced classes that inherit from the provided type. |
Scene | |
BuildSceneScope |
A scope that can be enumerated that will iterate over the scenes in the Build Settings and reset when disposed. The scope also provides a method to draw a progress bar. |
GetAllComponentsInScene GetAllGameObjectsInScene |
Recursively iterates all Components/GameObjects. |
GetGameObjectsIncludingRoot |
Recursively iterates a Transform hierarchy. |
Logging | |
GetPathForObject |
Returns an appropriate full path to the object. This includes the scene if relevant. |
Serialized Properties | |
FindBackingProperty FindBackingPropertyRelative |
Finds a backing property by name. Ie. a field serialized with [field: SerializeField] or [field: SerializeReference] . |
GetIndexFromArrayProperty |
Gets the array index associated with a property via string manipulation. |
LogAllProperties |
Logs all properties on a SerializedObject. |
GetPropertyValue |
Retrieves most basic System.Object values associated with the property via the property itself. |
ToFullString |
Attempts to log the value in the serialized property. |
SimpleCopyTo |
Simple automatic copy for most basic serialized property types. |
SimpleCopyInto |
Copy an object of the same type into most basic serialized property types. Handles collections, but not generic objects. Combine with GetFields to get the most out of it. |
Reverse |
Reverses serialized property arrays. |
Many helper functions for random editor IMGUI functionality I use.
Name | Description |
---|---|
Exponential Slider |
A slider that represents its values exponentially. Useful for things like camera FoV. |
DrawSplitter |
Draws a horizontal rule. |
ButtonOverPreviousControl |
Uses GUILayout.GetLastRect to draw a button over the last drawn control. |
OutlineScope |
Wraps a group of controls to surround them in an outline/background. Similar in style to ReorderableList, so can be combined if drawn before a list with its header set to headerHeight = 0 . |
DrawOutline |
Manually draw an outline. Can be useful to surround a SerializedProperty in a PropertyDrawer. |
ContainerScope |
Wraps a group of controls to surround them in an background. Also draws a header for the group. |
Name | Description |
---|---|
HeightWithSpacing |
singleLineHeight + standardVerticalSpacing |
rect.NextGUIRect() |
Advances the rect to the next position with a standardVerticalSpacing gap. |
rect.Indent() rect.GetIndentedRect() |
EditorGUI.IndentedRect alternatives. |
EditorGUIUtils.ZeroIndentScope |
Temporarily resets EditorGUI.indentLevel. |
Name | Description |
---|---|
ReorderableListAddButton |
Draws an alternate add button if run after a reorderable list's DoLayoutList function. Set displayAdd = false when initialising the list. |
ReorderableListHeaderClearButton |
Draws a Clear button in the top right of a ReorderableList's header when run in the header callback. |
Name | Description |
---|---|
CenteredMiniLabel CenteredBoldMiniLabel |
Variations of EditorStyles.miniLabel /EditorStyles.miniBoldLabel |
CenteredBoldLabel |
Variation of EditorStyles.boldLabel |
Helper class for authoring AdvancedDropdown menus.
IPropertyDropdownItem
can be implemented to provide names and paths ("Folder/Sub Folder"
).
CreateAdvancedDropdownFromAttribute
can generate an AdvancedDropdown from all types that implement an inherited AdvancedDropdownAttribute
.
For dropdowns created from a type inheritance structure consider using AdvancedDropdownOfSubtypes
.
If you find this resource helpful:
Add from OpenUPM | via scoped registry, recommended
This package is available on OpenUPM: https://openupm.com/packages/com.vertx.utilities
To add it the package to your project:
- open
Edit/Project Settings/Package Manager
- add a new Scoped Registry:
Name: OpenUPM URL: https://package.openupm.com/ Scope(s): com.vertx
- click Save
- open Package Manager
- click +
- select Add from Git URL
- paste
com.vertx.utilities
- click Add
Add from GitHub | not recommended, no updates through UPM
Note that you won't be able to receive updates through Package Manager this way, you'll have to update manually.
- open Package Manager
- click +
- select Add from Git URL
- paste
https://github.com/vertxxyz/Vertx.Utilities.git
- click Add
or - Edit your
manifest.json
file to contain"com.vertx.utilities": "https://github.com/vertxxyz/Vertx.Utilities.git"
,
To update the package with new changes, remove the lock from the packages-lock.json
file.