Unity Asset Package: Lazy Shortcuts - Custom shortcuts for common tasks in Unity
One of the excellent plus points of Unity Editor is its extendability. You can easily extend its functionalities by writing some code to make working on the Unity Editor more convenient. Shared below are some of the useful codes I use to make working in Unity Editor faster and more efficient.
Reset Transform
This is probably most of the people’s top frequent task on Unity Editor. Whenever we place a GameObject on the scene, Unity tends to place it in a random position in the scene. So what people do is to click on the gear symbol on the Transform Section of the Inspector and select Reset to reset its transform for housekeeping or out of necessity. The code below will allow you to have it as a MenuItem to reset the GameObject selected and a shortcut key Alt+r to do this frequent task from you. This code comes adapted from Github Gist of thebeardphantom. In fact, some of my other useful codes use the same code to select the gameobjects. You can also do in bulk this task which makes it even more effecient.
[MenuItem("Tools/Reset Transform &r")]
static void ResetTransform()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Zero Position");
foreach (GameObject go in selection)
{
InternalZeroPosition(go);
InternalZeroRotation(go);
InternalZeroScale(go);
}
}
private static void InternalZeroPosition(GameObject go)
{
go.transform.localPosition = Vector3.zero;
}
private static void InternalZeroRotation(GameObject go)
{
go.transform.localRotation = Quaternion.Euler(Vector3.zero);
}
private static void InternalZeroScale(GameObject go)
{
go.transform.localScale = Vector3.one;
}
Reset Name
This comes from the annoyance of an updated unity feature(I think it is added after version 4.6) where if you try to add another gameobject(e.g., via duplicate, create or drag and drop) to the hierarchy or scene. If there is already a gameobject with the same name, it will add a suffix of ascending number enclosed with parentheses. See below to know what I mean and how ugly and untidy it looks. (it wasn’t that bad last time…sobz…sobz)
The code below will allow you to have it as a MenuItem to rename the GameObject removing the suffix or a shortcut key Alt+n to do this satisfying task for you. Better still, you can select in bulk to rename at one go!
[MenuItem("Tools/Reset Name &n")]
static void ResetName()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Reset Name");
foreach (GameObject go in selection)
{
Rename(go);
}
}
private static void Rename(GameObject go)
{
int start = go.name.IndexOf("(");
int end = go.name.IndexOf(")");
if (start != -1 && end != -1 && start < end)
{
go.name = go.name.Substring(0, start);
}
}
Lock and Unlock Inspector
Another frequently performed task. You will need to lock the inspector a lot of times when trying to drag objects to the inspector as it happens quite frequently the focus in inspector will accidentally move to the objects you want to drag instead. The code is actually from an old unity forum thread. The code below will allow you to toggle lock and unlock on the
[MenuItem("Tools/Toggle Lock Inspector &l")]
static void LockUnlockInspector()
{
ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
ActiveEditorTracker.sharedTracker.activeEditors[0].Repaint();
}
Revert to prefab
There are times where you want to revert a prefab instance changes to the same as its prefab. This useful code will help you do that via a MenuItem or shortcut key Alt+p. And you can do this in bulk!
[MenuItem("Tools/Revert Prefab &p")]
static void RevertPrefab()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Revert Prefab");
foreach (GameObject go in selection)
{
if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
{
PrefabUtility.RevertPrefabInstance(go);
}
}
}
Apply changes to Prefab
This is to apply the changes done to a prefab instance to a prefab. You can do this via a MenuItem or shortcut key Alt+a.
[MenuItem("Tools/Apply changes to Prefab &a")]
static void SaveChangesToPrefab()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Apply Prefab");
foreach (GameObject go in selection)
{
if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
{
PrefabUtility.ReplacePrefab(go, PrefabUtility.GetPrefabParent(go));
PrefabUtility.RevertPrefabInstance(go);
}
}
}
Toggle Debug or Normal Inspector
This one is a bit tricky as the methods to use are not exposed(set inspector mode to debug or normal). So we need to use System.Reflection to invoke the method. In addition, to invoke the method, we need to get the Type InspectorWindow which again is not exposed, and I work around it by doing a Resources.FindObjectsOfTypeAll
[MenuItem("Tools/Toggle Debug or Normal &d")]
static void ToggleDebugNormalView()
{
EditorWindow inspectorWindow;
EditorWindow[] editorWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
foreach (EditorWindow editorWindow in editorWindows)
{
if (editorWindow.GetType().Name == "InspectorWindow")
{
if (EditorWindow.focusedWindow == editorWindow)
{
inspectorWindow = editorWindow;
Type inspector = inspectorWindow.GetType();
MethodInfo methodInfo = inspector.GetMethod("SetMode", BindingFlags.NonPublic | BindingFlags.Instance);
if (inspector.GetField("m_InspectorMode").GetValue(inspectorWindow).ToString() == "Debug")
{
methodInfo.Invoke(inspectorWindow, new object[] { InspectorMode.Normal });
}
else methodInfo.Invoke(inspectorWindow, new object[] { InspectorMode.Debug });
break;
}
}
}
}
Outro
One of the things I did not mention is on
Update: I have made these shortcuts into a unity asset store package called Lazy Shortcuts. It is available as a free download if you do not wish to create these shortcuts by yourself.
#if (UNITY_EDITOR)
using UnityEngine;
using UnityEditor;
//inspired from https://gist.github.com/thebeardphantom/ea6362139ee195a8abce
public class MyMenuItem : MonoBehaviour
{
[MenuItem("Tools/Reset Transform &r")]
static void ResetTransform()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Zero Position");
foreach (GameObject go in selection)
{
InternalZeroPosition(go);
InternalZeroRotation(go);
InternalZeroScale(go);
}
}
[MenuItem("Tools/Reset Name &n")]
static void ResetName()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Reset Name");
foreach (GameObject go in selection)
{
Rename(go);
}
}
[MenuItem("Tools/Revert Prefab &p")]
static void RevertPrefab()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Revert Prefab");
foreach (GameObject go in selection)
{
if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
{
PrefabUtility.RevertPrefabInstance(go);
}
}
}
[MenuItem("Tools/Apply changes to Prefab &a")]
static void SaveChangesToPrefab()
{
GameObject[] selection = Selection.gameObjects;
if (selection.Length < 1) return;
Undo.RegisterCompleteObjectUndo(selection, "Apply Prefab");
foreach (GameObject go in selection)
{
if (PrefabUtility.GetPrefabType(go) == PrefabType.PrefabInstance)
{
PrefabUtility.ReplacePrefab(go, PrefabUtility.GetPrefabParent(go));
PrefabUtility.RevertPrefabInstance(go);
}
}
}
[MenuItem("Tools/Toggle Lock Inspector &l")]
static void LockUnlockInspector()
{
ActiveEditorTracker.sharedTracker.isLocked = !ActiveEditorTracker.sharedTracker.isLocked;
ActiveEditorTracker.sharedTracker.activeEditors[0].Repaint();
}
[MenuItem("Tools/Toggle Debug or Normal &d")]
static void ToggleDebugNormalView()
{
EditorWindow inspectorWindow;
EditorWindow[] editorWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
foreach (EditorWindow editorWindow in editorWindows)
{
if (editorWindow.GetType().Name == "InspectorWindow")
{
if (EditorWindow.focusedWindow == editorWindow)
{
inspectorWindow = editorWindow;
Type inspector = inspectorWindow.GetType();
MethodInfo methodInfo = inspector.GetMethod("SetMode", BindingFlags.NonPublic | BindingFlags.Instance);
if (inspector.GetField("m_InspectorMode").GetValue(inspectorWindow).ToString() == "Debug")
{
methodInfo.Invoke(inspectorWindow, new object[] { InspectorMode.Normal });
}
else methodInfo.Invoke(inspectorWindow, new object[] { InspectorMode.Debug });
break;
}
}
}
}
private static void Rename(GameObject go)
{
int start = go.name.IndexOf("(");
int end = go.name.IndexOf(")");
if (start != -1 && end != -1 && start < end)
{
go.name = go.name.Substring(0, start);
}
}
private static void InternalZeroPosition(GameObject go)
{
go.transform.localPosition = Vector3.zero;
}
private static void InternalZeroRotation(GameObject go)
{
go.transform.localRotation = Quaternion.Euler(Vector3.zero);
}
private static void InternalZeroScale(GameObject go)
{
go.transform.localScale = Vector3.one;
}
}
#endif