{"id":10,"date":"2016-08-27T10:00:00","date_gmt":"2016-08-27T14:00:00","guid":{"rendered":"http:\/\/naplandgames.com\/blog\/2016\/08\/27\/unity-3d-tutorial-custom-transform-inspector\/"},"modified":"2018-12-18T09:09:28","modified_gmt":"2018-12-18T14:09:28","slug":"unity-3d-tutorial-custom-transform-inspector","status":"publish","type":"post","link":"https:\/\/naplandgames.com\/blog\/2016\/08\/27\/unity-3d-tutorial-custom-transform-inspector\/","title":{"rendered":"Unity 3D Tutorial &#8211; Custom Transform Inspector"},"content":{"rendered":"<p>Hi everyone!<br \/>\nOne of the awesome things about Unity is you can customize the editor to add all sorts of cool functionality. This article will show you how to override Unity&#8217;s transform inspector with a more useful customized version. The Custom Transform Component includes:<\/p>\n<ul>\n<li>The ability to view and edit the quaternion rotation (nice for experimenting and learning how quaternions work).<\/li>\n<li>The ability to show the local axes in the Scene view even when the object is not selected.<\/li>\n<li>Some special operations for aligning to other objects, random rotation, random scale, and random position.<\/li>\n<\/ul>\n<p>Here&#8217;s what the final product will look like:<\/p>\n<p><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/08\/custom-transform-inspector-1.png\" rel=\"lightbox[10]\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-77 size-full\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/08\/custom-transform-inspector-1.png\" alt=\"custom-transform-inspector\" width=\"945\" height=\"700\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/08\/custom-transform-inspector-1.png 945w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/08\/custom-transform-inspector-1-300x222.png 300w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2016\/08\/custom-transform-inspector-1-768x569.png 768w\" sizes=\"(max-width: 945px) 100vw, 945px\" \/><\/a><\/p>\n<h1>Part I: Extending the Default Transform Inspector<\/h1>\n<hr \/>\n<h3>Overriding the Defaults<\/h3>\n<div>First, thing&#8217;s first. We&#8217;ll need to recreate Unity&#8217;s transform inspector (not completely necessary). To make any custom editor scripts you&#8217;ll first need a folded called &#8220;Editor&#8221; in your Assets folder. This is a special folder that Unity looks in to for scripts that can only run in the Editor i.e. any script <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"http:\/\/docs.unity3d.com\/ScriptReference\/\" target=\"_blank\" rel=\"noopener\">using UnityEditor<\/a>;.<\/span><span style=\"font-family: inherit;\">\u00a0You&#8217;re not limited to one Editor folder per project so you can organize your editor scripts right alongside your MonoBehaviour scripts if you like. <a href=\"http:\/\/docs.unity3d.com\/Manual\/SpecialFolders.html\" target=\"_blank\" rel=\"noopener\">More info on on Unity&#8217;s special folders can be found here<\/a>. The <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">UnityEditor<\/span><span style=\"font-family: inherit;\"> namespace\u00a0This gives us access to a whole bunch of awesome tools for writing editor windows, inspectors, importing assets, and pretty much anything that you need in the Editor.\u00a0<\/span><\/div>\n<div><span style=\"font-family: inherit;\">\u00a0<\/span><\/div>\n<div><span style=\"font-family: inherit;\">The first part of our script is a bit boring and doesn&#8217;t really add any functionality to the Transform component. Some other notes before\u00a0<\/span>proceeding<span style=\"font-family: inherit;\">:<\/span><\/div>\n<div>\n<ul>\n<li>Custom inspector scripts need to inherit from Unity&#8217;s <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Editor <\/span>class.<\/li>\n<li>To indicate what component (in our case the Transform component) the custom editor is for we will use the CustomEditor attribute.<\/li>\n<li>Very commonly, you&#8217;ll want to be able to select multiple items simultaneously and edit them. For this you&#8217;ll need to add the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">CanEditMultpleObjects <\/span>attribute. There are some caveats to this and you may need to write your own methods to apply changes to all selected objects as in the example below.<\/li>\n<\/ul>\n<div>\n<p>The first part of our class will basically recreate Unity&#8217;s transform component. Unity draws the inspector in the method <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Editor.OnInspectorGUI.html\" target=\"_blank\" rel=\"noopener\">OnInspectorGUI()<\/a> <\/span>we will <span style=\"font-family: 'courier new' , 'courier' , monospace;\">override <\/span>this to make our custom inspector. Now, you don&#8217;t <i>need<\/i>\u00a0to recreate the default inspector (the part that shows position, rotation, and scale). I&#8217;m doing it here to give you insight on how custom editors work, \u00a0If you just want to use Unity&#8217;s default then you can call <span style=\"font-family: 'courier new' , 'courier' , monospace;\">base.OnInspectorGUI()<\/span> from your override of <span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnInspetorGUI()<\/span>. As you may see from the extents of the code below, that may be your preferred option.<\/p>\n<\/div>\n<\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent.cs\">using UnityEngine;\r\nusing UnityEditor;\r\n \r\n[CustomEditor(typeof(Transform))]\r\n[CanEditMultipleObjects]\r\npublic class CustomTransformComponent : Editor\r\n{\r\n    private Transform _transform;\r\n   \r\n    public override void OnInspectorGUI()\r\n    {\r\n        \/\/We need this for all OnInspectorGUI sub methods\r\n        _transform = (Transform)target;\r\n \r\n        StandardTransformInspector();\r\n    }\r\n \r\n    private void StandardTransformInspector()\r\n    {\r\n        bool didPositionChange = false;\r\n        bool didRotationChange = false;\r\n        bool didScaleChange = false;\r\n \r\n        \/\/ Watch for changes.\r\n        \/\/  1)  Float values are imprecise, so floating point error may cause changes\r\n        \/\/      when you've not actually made a change.\r\n        \/\/  2)  This allows us to also record an undo point properly since we're only\r\n        \/\/      recording when something has changed.\r\n \r\n        \/\/ Store current values for checking later\r\n        Vector3 initialLocalPosition = _transform.localPosition;\r\n        Vector3 initialLocalEuler = _transform.localEulerAngles;\r\n        Vector3 initialLocalScale = _transform.localScale;\r\n \r\n        EditorGUI.BeginChangeCheck();\r\n        Vector3 localPosition = EditorGUILayout.Vector3Field(\"Position\", _transform.localPosition);\r\n        if (EditorGUI.EndChangeCheck())\r\n            didPositionChange = true;\r\n \r\n        EditorGUI.BeginChangeCheck();\r\n        Vector3 localEulerAngles = EditorGUILayout.Vector3Field(\"Euler Rotation\", _transform.localEulerAngles);\r\n        if (EditorGUI.EndChangeCheck())\r\n            didRotationChange = true;\r\n \r\n        EditorGUI.BeginChangeCheck();\r\n        Vector3 localScale = EditorGUILayout.Vector3Field(\"Scale\", _transform.localScale);\r\n        if (EditorGUI.EndChangeCheck())\r\n            didScaleChange = true;\r\n \r\n        \/\/ Apply changes with record undo\r\n        if (didPositionChange || didRotationChange || didScaleChange)\r\n        {\r\n            Undo.RecordObject(_transform, _transform.name);\r\n \r\n            if (didPositionChange)\r\n                _transform.localPosition = localPosition;\r\n \r\n            if (didRotationChange)\r\n                _transform.localEulerAngles = localEulerAngles;\r\n \r\n            if (didScaleChange)\r\n                _transform.localScale = localScale;\r\n \r\n        }\r\n \r\n        \/\/ Since BeginChangeCheck only works on the selected object\r\n        \/\/ we need to manually apply transform changes to all selected objects.\r\n        Transform[] selectedTransforms = Selection.transforms;\r\n        if (selectedTransforms.Length &gt; 1)\r\n        {\r\n            foreach (var item in selectedTransforms)\r\n            {\r\n                if (didPositionChange || didRotationChange || didScaleChange)\r\n                    Undo.RecordObject(item, item.name);\r\n \r\n                if (didPositionChange)\r\n                {\r\n                    item.localPosition = ApplyChangesOnly(\r\n                        item.localPosition, initialLocalPosition, _transform.localPosition);\r\n                }\r\n \r\n                if (didRotationChange)\r\n                {\r\n                    item.localEulerAngles = ApplyChangesOnly(\r\n                        item.localEulerAngles, initialLocalEuler, _transform.localEulerAngles);\r\n                }\r\n \r\n                if (didScaleChange)\r\n                {\r\n                    item.localScale = ApplyChangesOnly(\r\n                        item.localScale, initialLocalScale, _transform.localScale);\r\n                }\r\n               \r\n            }\r\n        }\r\n    }\r\n \r\n    private Vector3 ApplyChangesOnly(Vector3 toApply, Vector3 initial, Vector3 changed)\r\n    {\r\n        if (!Mathf.Approximately(initial.x, changed.x))\r\n            toApply.x = _transform.localPosition.x;\r\n \r\n        if (!Mathf.Approximately(initial.y, changed.y))\r\n            toApply.y = _transform.localPosition.y;\r\n \r\n        if (!Mathf.Approximately(initial.z, changed.z))\r\n            toApply.z = _transform.localPosition.z;\r\n \r\n        return toApply;\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div>Some extra explanation beyond the comments as to what&#8217;s going on here. First, we set up a class level <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Transform <\/span>(aptly named <span style=\"font-family: 'courier new' , 'courier' , monospace;\">_transform<\/span>) to hold the transform of the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">target <\/span>(the selected object) so that we can refer to it throughout the class. We override <span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnInspectorGUI()<\/span> and immediately cast <span style=\"font-family: 'courier new' , 'courier' , monospace;\">target <\/span>(a property of the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Editor <\/span>class) to a <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Transform <\/span>type and set <span style=\"font-family: 'courier new' , 'courier' , monospace;\">_transform<\/span>.. <span style=\"font-family: inherit;\">Then we call our new method,<\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\"> StandardTransformInspector()<\/span><span style=\"font-family: inherit;\">.\u00a0<\/span><br \/>\n<span style=\"font-family: inherit;\"><br \/>\n<\/span><span style=\"font-family: inherit;\">In the\u00a0<\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">StandardTransformInspector()<\/span><span style=\"font-family: inherit;\">\u00a0method we have a few things going on. First, we set up some bools to flag when a value is changed in the inspector and we store the initial position, rotation, and scale of our transform so that we can make a comparison later. Then you&#8217;ll see three spots where we check for changes with <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/EditorGUI.BeginChangeCheck.html\" target=\"_blank\" rel=\"noopener\">EditorGUI.BeginChangeCheck()<\/a><\/span><span style=\"font-family: inherit;\"> and flag our bools if a change has occurred by checking <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/EditorGUI.EndChangeCheck.html\" target=\"_blank\" rel=\"noopener\">EditorGUI.EndChangeCheck()<\/a><\/span><span style=\"font-family: inherit;\">. Once that has finished and when know what if something has changed we now use <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Undo.RecordObject.html\" target=\"_blank\" rel=\"noopener\">Undo.RecordObject()<\/a><\/span><span style=\"font-family: inherit;\"> to record the state of the object <b>before <\/b>any change has been made (this allows use to Undo the operation). Then we simply apply only the changes that have occurred.<\/span><br \/>\n<span style=\"font-family: inherit;\"><br \/>\n<\/span><span style=\"font-family: inherit;\">Next, we have some adjustments to make to get our inspector to work like Unity&#8217;s default inspector. Since we&#8217;re using <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">BeginChangeCheck()<\/span><span style=\"font-family: inherit;\"> and <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">EndChangeCheck()<\/span><span style=\"font-family: inherit;\"> our changes will only be applied to the last selected object. So this basically breaks multi-selection editing which is what we&#8217;re fixing next.To help us out I created another method, <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">ApplyChangesOnly()<\/span><span style=\"font-family: inherit;\">, which will only apply a change to the x, y, or z value of the vector if it was changed in the selected transform. So if you change the x position it <b>only <\/b>changes the x position of all selected objects. Similarly I set up an undo state if anything will be changed, then iterate through all of the selected transforms (retrieved with <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">Selection.transforms<\/span><span style=\"font-family: inherit;\">) and apply changes when it is appropriate.<\/span><br \/>\n<span style=\"font-family: inherit;\"><br \/>\n<\/span><span style=\"font-family: inherit;\">That&#8217;ll cover all the changes we need for recreating the default inspector for transforms. The only actual change I made over the default is I named the &#8220;Rotation&#8221; fields to &#8220;Euler Rotation&#8221;. This is just so that we can see how to do this, and we&#8217;ll be showing the Quaternion rotation in the inspector next.<\/span><\/div>\n<h3>Showing the Quaternion Rotation<\/h3>\n<div><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Quaternion.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-family: 'courier new' , 'courier' , monospace;\">Quaternions<\/span><\/a><span style=\"font-family: inherit;\"> are what Unity (and many other 3D applications) use to store rotational information. They&#8217;re a bit complex and not as intuitive as euler angles (degrees for x, y, and z). However, they are a necessity in 3D applications because euler angles don&#8217;t fully describe rotation and the suffer from <a href=\"https:\/\/en.wikipedia.org\/wiki\/Gimbal_lock\" target=\"_blank\" rel=\"noopener\">Gimbal lock<\/a>. Check out the links to learn more on these. A discussion on Quaternions go well beyond the aim of this post and, honestly, I&#8217;d probably do a bad job explaining them. A quaternions are often a mystery to many and I decided to expose them in the inspector so that we can view and optionally edit them to get a better understanding of their behavior.<\/span><\/div>\n<div><\/div>\n<div>This section of the inspector will use a foldout (the little arrow head that shows more info when clicked). To maintain the state of the foldout we use a bool (is it open or closed?) and we&#8217;ll use a new method, <span style=\"font-family: 'courier new' , 'courier' , monospace;\">QuaterionInspector()<\/span>, to display the quaternion&#8217;s values.We&#8217;ll also need to add a call to the method in\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnInspetorGUI()<\/span>\u00a0as can be seen below:<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true\" title=\"CustomTransformComponent .OnInspectorGUI()\">    public override void OnInspectorGUI()\r\n    {\r\n        \/\/We need this for all OnInspectorGUI sub methods\r\n        _transform = (Transform)target;\r\n        StandardTransformInspector();\r\n        QuaternionInspector();\r\n    }<\/pre>\n<\/div>\n<div>The new <span style=\"font-family: 'courier new' , 'courier' , monospace;\">QuaternionInspector()<\/span> method uses familiar components as the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">StandardTransformInspector()<\/span> method, but also uses <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/EditorGUILayout.Foldout.html\" target=\"_blank\" rel=\"noopener\">EditorGUILayout.Foldout()<\/a><\/span> to tell us whether the foldout should be open or not. A special note here: I used a static bool to store the state of the foldout. This means that when you open the foldout for any game object they will all be open since they&#8217;re using a global <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/79b3xss3.aspx#Anchor_0\" target=\"_blank\" rel=\"noopener\"><span style=\"font-family: 'courier new' , 'courier' , monospace;\">static<\/span> <\/a>value. This decision was made because I didn&#8217;t like opening it on one object, then making a multiselection and having to open it again. There&#8217;s also a couple utility methods for converting the quaternion to and from a <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Vector4.html\" target=\"_blank\" rel=\"noopener\">Vector4<\/a><\/span> since Unity doesn&#8217;t offer a GUI item for quaternions and quaternions at their base are <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Vector4<\/span>s, Those utility methods are pretty basic so hopefully you&#8217;ll understand without extra explanation. Here&#8217;s the new chunk of code we add to get it all working:<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true\" title=\"CustomTransformComponent - Quaternion Inspector\">    private static bool quaternionFoldout = false;\r\n    private void QuaternionInspector()\r\n    {\r\n        \/\/Additional element to also view the Quaternion rotation values\r\n        quaternionFoldout = EditorGUILayout.Foldout(quaternionFoldout, \"Quaternion Rotation:    \" + _transform.localRotation.ToString(\"F3\"));\r\n        if (quaternionFoldout)\r\n        {\r\n            EditorGUI.BeginChangeCheck();\r\n            Vector4 qRotation = EditorGUILayout.Vector4Field(\"Be careful!\", QuaternionToVector4(_transform.localRotation));\r\n \r\n            if (EditorGUI.EndChangeCheck())\r\n            {\r\n                Undo.RecordObject(_transform, \"modify quaternion rotation on \" + _transform.name);\r\n                _transform.localRotation = ConvertToQuaternion(qRotation);\r\n            }\r\n        }\r\n    }\r\n \r\n \r\n    private Quaternion ConvertToQuaternion(Vector4 v4)\r\n    {\r\n        return new Quaternion(v4.x, v4.y, v4.z, v4.w);\r\n    }\r\n \r\n \r\n    private Vector4 QuaternionToVector4(Quaternion q)\r\n    {\r\n        return new Vector4(q.x, q.y, q.z, q.w);\r\n    }\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>Now we have a custom inspector for transform components that shows us (and allows us to edit) the quaternion rotation. Pretty cool, but not overly useful. Next up we&#8217;re going to add some utilities to our inspector to get the most out of it.<\/p>\n<\/div>\n<h3>Showing the Local Axis<\/h3>\n<div>Oftentimes I&#8217;ve found that I&#8217;ll really need to see the direction an object is pointing when I don&#8217;t have it selected. It can be a pain to try to align rotations when you can&#8217;t see the rotation of the object you&#8217;re trying to align to! So I created a simple MonoBehaviour class that does just that. Now, you don&#8217;t need the custom transform component for this, but the goal here is to show you how to integrate another component with your custom inspector. We could control all of the values of the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis <\/span>component via our custom transform component, but for such a simple component it is pretty pointless. Besides Unity already exposes the only variable we have in the component: <span style=\"font-family: 'courier new' , 'courier' , monospace;\">handleLength<\/span>. The goal here is to show you how to properly add and remove a component from another component via the inspector.<\/div>\n<div><\/div>\n<div>Here&#8217;s the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis <\/span>class. It&#8217;s pretty short and makes use of <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/MonoBehaviour.OnDrawGizmos.html\" target=\"_blank\" rel=\"noopener\">OnDrawgizmos()<\/a><\/span> to show some lines that represent the axes of the object it is attached to. It allows for variable length of the lines (<span style=\"font-family: 'courier new' , 'courier' , monospace;\">handleLength<\/span>) which have been limited using the <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/RangeAttribute.html\" target=\"_blank\" rel=\"noopener\">Range<\/a><\/span> attribute. The <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Range<\/span> attribute sets up a nice slider in the inspector for us. We are also using the HideInInspector attribute to prevent Unity from showing a public bool, <span style=\"font-family: 'courier new' , 'courier' , monospace;\">destroyWhenSafe<\/span>, whose purpose I will explain in a bit. Otherwise, the class should be pretty straight forward. It is just drawing a line on the local x, y, and z axes. To set the Gizmo&#8217;s space to the object&#8217;s local space we set <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Gizmos-matrix.html\">Gizmos.matrix<\/a><\/span> to <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Transform-localToWorldMatrix.html\"><span style=\"font-family: 'courier new' , 'courier' , monospace;\">transform.localToWorldMatrix<\/span><\/a>.<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true\" title=\"ShowLocalAxis.cs\">using UnityEngine;\r\n \r\npublic class ShowLocalAxis : MonoBehaviour\r\n{\r\n    [HideInInspector]\r\n    public bool destroyWhenSafe = false;\r\n \r\n    [Range(1f,100f)]\r\n    public float handleLength = 10f;\r\n \r\n    public void OnDrawGizmos()\r\n    {\r\n        Gizmos.matrix = transform.localToWorldMatrix;\r\n        Gizmos.color = Color.blue;\r\n        Gizmos.DrawLine(Vector3.zero, Vector3.forward * handleLength);\r\n        Gizmos.color = Color.red;\r\n        Gizmos.DrawLine(Vector3.zero, Vector3.right * handleLength);\r\n        Gizmos.color = Color.yellow;\r\n        Gizmos.DrawLine(Vector3.zero, Vector3.up* handleLength);\r\n    }\r\n}<\/pre>\n<\/div>\n<div>\n<p>To accomplish safe destruction of component via another component we&#8217;ll need a custom inspector that waits for the proper time to destroy the component. Otherwise, we&#8217;ll get some nasty errors in Unity. The below script does just that. We don&#8217;t care about any special display, but since we used <span style=\"font-family: 'courier new' , 'courier' , monospace;\">HideInInspector<\/span> and Range in <span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span>, we&#8217;ll use\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/Editor.DrawDefaultInspector.html\">base.DrawDefaultInspector()<\/a> <\/span>to show the default view instead of\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">base.OnInspectorGUI()<\/span><span style=\"font-family: inherit;\"> that I mentioned before. So what happens is our custom transform component will set the <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">destroyWhenSafe<\/span><span style=\"font-family: inherit;\"> bool to true, then when the editor&#8217;s state is <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">Repaint<\/span><span style=\"font-family: inherit;\"> we can safely destroy the <\/span><span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span><span style=\"font-family: inherit;\"> component.\u00a0<\/span><\/p>\n<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"ShowLocalAxisInspector.cs\">using UnityEngine;\r\nusing UnityEditor;\r\n \r\n[CustomEditor(typeof(ShowLocalAxis))]\r\npublic class ShowLocalAxisInspector : Editor\r\n{\r\n    public override void OnInspectorGUI()\r\n    {\r\n        base.DrawDefaultInspector();\r\n \r\n        ShowLocalAxis showRotated = (ShowLocalAxis)target;\r\n        if (showRotated.destroyWhenSafe &amp;&amp; Event.current.type == EventType.Repaint)\r\n        {\r\n            DestroyImmediate(showRotated);\r\n            return;\r\n        }\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>Now we have our component all set up, let&#8217;s integrate it with our custom transform component. For this we&#8217;ll make a new method called\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxisComponentToggle()<\/span> and change our <span style=\"font-family: 'courier new' , 'courier' , monospace;\">CustomTranformComponent<\/span>&#8216;s <span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnInspectorGUI() <\/span>to so it calls the method like this:<\/p>\n<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true\" title=\"CustomTransformInspector\">    public override void OnInspectorGUI()\r\n    {\r\n        \/\/We need this for all OnInspectorGUI sub methods\r\n        _transform = (Transform)target;\r\n        StandardTransformInspector();\r\n        QuaternionInspector();\r\n \r\n        ShowLocalAxisComponentToggle();\r\n    }<\/pre>\n<\/div>\n<div>\n<p>In Next up is the\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxisComponentToggle()<\/span>\u00a0method, For this we&#8217;ll need a private bool, <span style=\"font-family: 'courier new' , 'courier' , monospace;\">showLocalAxisToggle<\/span>, that will be used to toggle on\/off the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span> component. And we&#8217;ll need a First, we start off by adding some padding above the rest of the GUI elements with two calls to Unity&#8217;s\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">EditorGUILayout.Space()<\/span> method. Next we attempt to see if there is a\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span>\u00a0component attached to the game object. If there is then we set our\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">showLocalAxisToggle<\/span>\u00a0to\u00a0true and display it\u00a0in the inspector. This time we&#8217;re going to use a horizontal layout (which starts a horizontal section where the GUI elements will be placed) by calling <span style=\"font-family: 'courier new' , 'courier' , monospace;\">EditorGUILayout.BeginHorizontal()<\/span>. Then we use a <span style=\"font-family: 'courier new' , 'courier' , monospace;\">EditorGUILayout.LabelField()<\/span>, start to monitor changes, and display a <span style=\"font-family: 'courier new' , 'courier' , monospace;\">EditorGUILayout.ToggleLeft()<\/span> with a corresponding label of &#8220;on&#8221; or &#8220;off&#8221; based on the existence of the\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span>\u00a0component. If the toggle changes value then we add the component and\u00a0move it up to the second position so that it is right under the transform component. If we&#8217;re toggling the\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span>\u00a0to off then we flag it with\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">destroyWhenSafe<\/span><span style=\"font-family: inherit;\">\u00a0<\/span>and allow\u00a0the\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">ShowLocalAxis<\/span>\u00a0component to destroy itself when it is safe to do so. The full method looks like this:<\/p>\n<\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - ShowLocalAxisToggle\">    private bool showLocalAxisToggle = false;\r\n    private void ShowLocalAxisComponentToggle()\r\n    {\r\n        EditorGUILayout.Space();\r\n        EditorGUILayout.Space();\r\n        ShowLocalAxis showLocalAxis = _transform.gameObject.GetComponent&lt;ShowLocalAxis&gt;();\r\n \r\n       \r\n        if (showLocalAxis == null)\r\n            showLocalAxisToggle = false;\r\n        else\r\n            showLocalAxisToggle = true;\r\n \r\n        EditorGUILayout.BeginHorizontal();\r\n        EditorGUILayout.LabelField(\"Show local rotation handles\", EditorStyles.boldLabel);\r\n        EditorGUI.BeginChangeCheck();\r\n        \/\/ We use GUILayout.Toggle here instead of EditorGUI toggle because they cause horizontal overflow\r\n        showLocalAxisToggle = GUILayout.Toggle(showLocalAxisToggle, (showLocalAxisToggle ? \"on\" : \"off\" ));\r\n        if (EditorGUI.EndChangeCheck())\r\n        {\r\n            if (showLocalAxisToggle == true)\r\n            {\r\n                showLocalAxis = _transform.gameObject.AddComponent&lt;ShowLocalAxis&gt;();\r\n                int componentCount = _transform.GetComponents&lt;Component&gt;().Length;\r\n                for (int i = 1; i &lt; componentCount; i++)\r\n                {\r\n                    UnityEditorInternal.ComponentUtility.MoveComponentUp(showLocalAxis);\r\n                }\r\n            }\r\n            else\r\n            {\r\n                showLocalAxis.destroyWhenSafe = true;\r\n            }\r\n        }\r\n        EditorGUILayout.EndHorizontal();\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div>\n<p>That takes care of showing the local axis. Now we&#8217;ve learned how to create custom inspectors, do some layout, show axis line gizmos, and safely add\/remove a component from another component. In the next section I will show you how to add even more functionality to the transform component. We&#8217;ll set up methods for aligning selected game objects to each other, randomly rotating them, randomly scaling them, and randomly positioning them. Each of which can be very helpful in speeding up level design.<\/p>\n<\/div>\n<h1>Part II: Special Operations<\/h1>\n<hr \/>\n<div>This section is split into subsections for each of the Special Operations. First, I&#8217;m going to show the full code for handling an animated foldout for showing\/hiding the special operations. First, we need to have a class-level <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AnimBool<\/span> object to maintain the state of the foldout, and a static bool to set the foldout states on all custom transform components globally. We set assign the\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">AnimBool<\/span>\u00a0in <span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnEnable()<\/span> which fires when\u00a0a game object is selected in the editor. The states will then be properly set and we&#8217;ll need to add a call to the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">SpecialOperations()<\/span> method in our\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\">OnInspectorGUI()<\/span>\u00a0method like we&#8217;ve done before. For now, you won&#8217;t have the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignmentInspector()<\/span>, <span style=\"font-family: 'courier new' , 'courier' , monospace;\">RandomRotationInspector()<\/span>, or <span style=\"font-family: 'courier new' , 'courier' , monospace;\">RandomPositionInspector()<\/span> methods, so you can just create stubs for them now if you like. But we&#8217;ll cover them in the following sections.<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - Special Operations foldout\">    private AnimBool m_showExtraFields;\r\n    private static bool _showExtraFields;\r\n \r\n    void OnEnable()\r\n    {\r\n        m_showExtraFields = new AnimBool(_showExtraFields);\r\n        m_showExtraFields.valueChanged.AddListener(Repaint);\r\n    }\r\n \r\n    private void SpecialOperations()\r\n    {\r\n        EditorGUILayout.Space();\r\n        EditorGUILayout.Space();\r\n \r\n        m_showExtraFields.target = EditorGUILayout.ToggleLeft(\"Special operations\", m_showExtraFields.target);\r\n        if (EditorGUILayout.BeginFadeGroup(m_showExtraFields.faded))\r\n        {\r\n            AlignmentInspector();\r\n \r\n            EditorGUILayout.Space();\r\n            EditorGUILayout.Space();\r\n \r\n            RandomRotatationInspector();\r\n \r\n            EditorGUILayout.Space();\r\n            EditorGUILayout.Space();\r\n \r\n            RandomScaleInspector();\r\n \r\n            EditorGUILayout.Space();\r\n            EditorGUILayout.Space();\r\n            RandomPositionInspector();\r\n        }\r\n        _showExtraFields = m_showExtraFields.value;\r\n        EditorGUILayout.EndFadeGroup();\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div>\n<h3>Custom Button<\/h3>\n<p>Before we dig in, each of these inspectors will have buttons associated with them. Unity&#8217;s default for an inspector button is to stretch its width to fit the inspector window. I don&#8217;t really like that so I went ahead and created my own button. First I define a <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/GUILayoutOption.html\" target=\"_blank\" rel=\"noopener\">GUILayoutOption<\/a><\/span> to set the \u00a0width of all the buttons to 200 (I found this number after I made all my buttons and could see their width). Then in the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Button()<\/span> method I wrap everything in a horizontal layout, add flexible spaces to the left and right of the button (this centers it), I then get the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">bool<\/span> value from Unity&#8217;s <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/GUILayout.Button.html\" target=\"_blank\" rel=\"noopener\">GUILayout.Button()<\/a><\/span> so I can return it from the new method.<\/p>\n<\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - Custom Button styleing\">    private GUILayoutOption[] buttonOptions = new GUILayoutOption[1] { GUILayout.Width(200f) };\r\n    private bool Button(string label)\r\n    {\r\n        GUILayout.BeginHorizontal();\r\n        GUILayout.FlexibleSpace();\r\n        bool value = GUILayout.Button(label, buttonOptions);\r\n        GUILayout.FlexibleSpace();\r\n        GUILayout.EndHorizontal();\r\n        return value;\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div><\/div>\n<h3>Alignment Inspector<\/h3>\n<div>The Alignment special operation will allow us to select multiple objects and line them up on their X, Y, or Z axis (or any combination of). This can be quite handy when doing level design. Definitely much better than having to figure out your snap interval or manually inputting position values. First thing we&#8217;re going to need is a couple of <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/sbbt4032.aspx?f=255&amp;MSPPError=-2147217396\" target=\"_blank\" rel=\"noopener\">enums<\/a><\/span>. <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignToType<\/span> is just either the last selected GameObject or the first selected GameObject. <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AxisFlag<\/span> is a bit flag enum that allows us to make any combination of X, Y, and\/or Z (the values you see are bits &#8211; i.e. 2 to the power of 0, 1, and 2 respectively). Then we set some default values up for these in <span style=\"font-family: 'courier new' , 'courier' , monospace;\">alignTo<\/span> and <span style=\"font-family: 'courier new' , 'courier' , monospace;\">alignmentAxis<\/span>. Like so:<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - alignment enums\">    public enum AlignToType { lastSelected, firstSelected }\r\n    public enum AxisFlag { X = 1, Y = 2, Z = 4 }\r\n \r\n    public AlignToType alignTo = AlignToType.lastSelected;\r\n    public AxisFlag alignmentAxis = AxisFlag.X;<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div>\n<p>Next up is our method to actually perform the alignment operation, this is called <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignTo()<\/span>. First it gets an array of all of the selected transformas then it determines the index in that array (<span style=\"font-family: 'courier new' , 'courier' , monospace;\">targetIndex<\/span>) of the transform (or GameObject) we&#8217;ll be aligning to. This is index 0 for the first selected and the last index of the array to align to the last selected transform. Then we iterate through all of the selected transforms and set their positions that should be aligned to the position of the selected transform. While doing this for loop, we ensure we skip over the selected transfor, because it makes no sense to move it to itself. Finally, we use <span style=\"font-family: 'courier new' , 'courier' , monospace;\">Undo.RecordObject()<\/span> so that we can reverse these operations.Some of you may be familiar with bitwise operations and may see the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">&amp;<\/span> in the conditions. Others of you are probably wonder what statements like<\/p>\n<pre class=\"lang:c# decode:true \">if ((axis &amp; AxisFlag.X) == AxisFlag.X)<\/pre>\n<p>actually mean. The single <span style=\"font-family: 'courier new' , 'courier' , monospace;\">&amp;<\/span> is a binary AND operator. What this does is it copies the bit to the results <i>IF<\/i> the bit exists in both operands (<span style=\"font-family: 'courier new' , 'courier' , monospace;\">axis<\/span> and <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AxisFlag.X<\/span>). So if axis contains the bit for <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AxisFlax.X<\/span> the result will be <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AxisFlag.X<\/span>. This is why we&#8217;re using powers of 2 for our <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AxisFlag<\/span> enum&#8217;s values. Basics on bitwise operators in C# can be found here at <a href=\"http:\/\/www.tutorialspoint.com\/csharp\/csharp_bitwise_operators.htm\">tutorialspoint.com<\/a>. The full <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignTo()<\/span> method is as follows:<\/p>\n<\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - AlignTo()\">    private void AlignTo(AlignToType to , AxisFlag axis)\r\n    {\r\n        Transform[] selectedTransforms = Selection.transforms;\r\n \r\n        int targetIndex = 0;\r\n        if (to == AlignToType.lastSelected)\r\n            targetIndex = selectedTransforms.Length - 1;\r\n \r\n        for (int i = 0; i &lt; selectedTransforms.Length; i++)\r\n        {\r\n            if (i == targetIndex)\r\n                continue;\r\n \r\n            Vector3 temp = selectedTransforms[i].position;\r\n \r\n            if ((axis &amp; AxisFlag.X) == AxisFlag.X)\r\n                temp.x = selectedTransforms[targetIndex].position.x;\r\n \r\n            if ((axis &amp; AxisFlag.Y) == AxisFlag.Y)\r\n                temp.y = selectedTransforms[targetIndex].position.y;\r\n \r\n            if ((axis &amp; AxisFlag.Z) == AxisFlag.Z)\r\n                temp.z = selectedTransforms[targetIndex].position.z;\r\n \r\n            Undo.RecordObject(\r\n                selectedTransforms[i],\r\n                selectedTransforms[i].name +  \" aligned to \" + selectedTransforms[targetIndex].name);\r\n \r\n            selectedTransforms[i].position = temp;\r\n        }\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<div><\/div>\n<div>Finally, we get to our <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignmentInspector()<\/span> method which will display this special operation in our inspector. We&#8217;re now making use of some enums, so there&#8217;s two new methods for that &#8211; <span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/EditorGUILayout.EnumMaskField.html\" target=\"_blank\" rel=\"noopener\">EditorGUILayout.EnumPopup()<\/a><\/span> and\u00a0<span style=\"font-family: 'courier new' , 'courier' , monospace;\"><a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/EditorGUILayout.EnumMaskField.html\" target=\"_blank\" rel=\"noopener\">EditorGUILayout.EnumMaskField()<\/a><\/span>, The <span style=\"font-family: 'courier new' , 'courier' , monospace;\">EnumPopup<\/span> will allow us to select from a single enum value (our align to first\/last selected) while the <span style=\"font-family: 'courier new' , 'courier' , monospace;\">EnumMaskField<\/span> will allow us to pick from any combination of enum elements (as long as they&#8217;re powers of 2). It&#8217;s also important to note here that these two methods return a generic enum so we must cast them back to our enum type to ensure they&#8217;re correct. The we set up a string to hold our button label if only one game object is selected. We check to see if multiple game objects are selected. If they are we label the button more appropriately and enable the button. Finally we check to see when the button is pressed and if it is we execute <span style=\"font-family: 'courier new' , 'courier' , monospace;\">AlignTo()<\/span>. The following code illustrates this in its entirety:<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CusomtTransformComponent - AlignmentInspector()\">    private void AlignmentInspector()\r\n    {\r\n        EditorGUILayout.LabelField(\"Alignment\", EditorStyles.boldLabel, layoutMaxWidth);\r\n        alignTo = (AlignToType)EditorGUILayout.EnumPopup(\"Align to\", alignTo, layoutMaxWidth);\r\n        alignmentAxis = (AxisFlag)EditorGUILayout.EnumMaskField(\"Axis\", alignmentAxis, layoutMaxWidth);\r\n \r\n        string buttonLabel = \"Select another object to align to\";\r\n        bool enableButton = false;\r\n        Transform[] selectedTransforms = Selection.transforms;\r\n        if (selectedTransforms.Length &gt; 1)\r\n        {\r\n            if (alignTo == AlignToType.lastSelected)\r\n            {\r\n                buttonLabel = \"Align to \" + selectedTransforms[selectedTransforms.Length - 1].name;\r\n            }\r\n            else\r\n            {\r\n                buttonLabel = \"Align to \" + selectedTransforms[0].name;\r\n            }\r\n            enableButton = true;\r\n        }\r\n \r\n        GUI.enabled = enableButton;\r\n        if (Button(buttonLabel))\r\n        {\r\n            AlignTo(alignTo, alignmentAxis);\r\n        }\r\n        GUI.enabled = true;\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<h3>Random Rotation Inspector<\/h3>\n<div>The Random Rotation inspector doesn&#8217;t really cover anything new. In brief we&#8217;re doing many things similar to the Alignment inspector. We set the axis flag(s) for what axis to rotate on, change the button label to indicate if 1 or more transforms are selected, then apply a random rotation (in euler angles) to the appropriate axis. See, things are getting easier!<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CustomTransformComponent - Random Rotation\">    public AxisFlag rotationAxisFlag;\r\n    private void RandomRotatationInspector()\r\n    {\r\n        EditorGUILayout.LabelField(\"Random Rotation\", EditorStyles.boldLabel, layoutMaxWidth);\r\n        rotationAxisFlag = (AxisFlag)EditorGUILayout.EnumMaskField(\"Rotation Axis\", rotationAxisFlag, layoutMaxWidth);\r\n \r\n        Transform[] selectedTransforms = Selection.transforms;\r\n \r\n        string label = \"Rotate \" + _transform.name;\r\n        if (selectedTransforms.Length &gt; 1)\r\n            label = \"Rotate selected\";\r\n \r\n        if (Button(label))\r\n        {\r\n            RandomRotate(rotationAxisFlag , selectedTransforms);\r\n        }\r\n    }\r\n \r\n    private void RandomRotate(AxisFlag axis , Transform[] selected)\r\n    {\r\n        for (int i = 0; i &lt; selected.Length; i++)\r\n        {\r\n            Vector3 temp = selected[i].localEulerAngles;\r\n \r\n            if ((axis &amp; AxisFlag.X) == AxisFlag.X)\r\n                temp.x = RdmDeg();\r\n \r\n            if ((axis &amp; AxisFlag.Y) == AxisFlag.Y)\r\n                temp.y = RdmDeg();\r\n \r\n            if ((axis &amp; AxisFlag.Z) == AxisFlag.Z)\r\n                temp.z = RdmDeg();\r\n \r\n            Undo.RecordObject(_transform, \"random rotate \" + selected[i].name);\r\n            selected[i].localEulerAngles = temp;\r\n        }\r\n    }\r\n \r\n    private float RdmDeg()\r\n    {\r\n        return Random.Range(0f, 360f);\r\n    }<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<h3>Random Scale Inspector and Random Position Inspector<\/h3>\n<div>Last, but not least, are the Random Scale and the Random Position inspectors. These are also pretty easy now that we&#8217;ve gotten through all the drudgery. No new concepts appear here other than using a min and max value for the random value. The reason for this is that we need some bounds for our random value. With rotation, that&#8217;s simple (0-360), but with position and scale&#8230; it could be anything to\u00a0+\/- infinity. So we ask the user to set those values in the inspector (of face the consequences!). The code below completes our custom inspector:<\/div>\n<div><\/div>\n<div>\n<pre class=\"lang:c# decode:true \" title=\"CsutomTransformComponent - Random scale and rotation\">    private AxisFlag scaleAxisFlag;\r\n    private float minScale, maxScale;\r\n    private bool scaleSame = true;\r\n    private void RandomScaleInspector()\r\n    {\r\n        EditorGUILayout.LabelField(\"Random Scale (local)\", EditorStyles.boldLabel, layoutMaxWidth);\r\n \r\n        scaleAxisFlag = (AxisFlag)EditorGUILayout.EnumMaskField(\"Scale Axis\", scaleAxisFlag, layoutMaxWidth);\r\n        scaleSame = EditorGUILayout.ToggleLeft(\"Scale same\", scaleSame, layoutMaxWidth);\r\n \r\n        minScale = EditorGUILayout.FloatField(\"Min:\", minScale, layoutMaxWidth);\r\n        maxScale = EditorGUILayout.FloatField(\"Max\", maxScale, layoutMaxWidth);\r\n \r\n        Transform[] selectedTransforms = Selection.transforms;\r\n        string btnLabel = \"Scale \" + _transform.name;\r\n        if (selectedTransforms.Length &gt; 1)\r\n            btnLabel = \"Scale selection\";\r\n \r\n        if (Button(btnLabel))\r\n        {\r\n            RandomScale(scaleAxisFlag, selectedTransforms, scaleSame);\r\n        }\r\n    }\r\n \r\n    private void RandomScale(AxisFlag axis, Transform[] selected , bool scaleSame)\r\n    {\r\n        for (int i = 0; i &lt; selected.Length; i++)\r\n        {\r\n            Vector3 temp = selected[i].localScale;\r\n            Vector3 random = Vector3.zero;\r\n            if (scaleSame)\r\n            {\r\n                float rdm = Random.Range(minScale, maxScale);\r\n                random.x = rdm;\r\n                random.y = rdm;\r\n                random.z = rdm;\r\n            }\r\n            else\r\n            {\r\n                random.x = Random.Range(minScale, maxScale);\r\n                random.y = Random.Range(minScale, maxScale);\r\n                random.z = Random.Range(minScale, maxScale);\r\n            }\r\n \r\n            if ((axis &amp; AxisFlag.X) == AxisFlag.X)\r\n                temp.x = random.x;\r\n \r\n            if ((axis &amp; AxisFlag.Y) == AxisFlag.Y)\r\n                temp.y = random.y;\r\n \r\n            if ((axis &amp; AxisFlag.Z) == AxisFlag.Z)\r\n                temp.z = random.z;\r\n \r\n            Undo.RecordObject(_transform, \"random scale \" + selected[i].name);\r\n            selected[i].localScale = temp;\r\n        }\r\n    }\r\n \r\n \r\n    private Vector3 minPosition, maxPosition;\r\n    private void RandomPositionInspector()\r\n    {\r\n        EditorGUILayout.LabelField(\"Random Position\", EditorStyles.boldLabel, layoutMaxWidth);\r\n        minPosition = EditorGUILayout.Vector3Field(\"Min\", minPosition, layoutMaxWidth);\r\n        maxPosition = EditorGUILayout.Vector3Field(\"Max\", maxPosition, layoutMaxWidth);\r\n \r\n        Transform[] selectedTransforms = Selection.transforms;\r\n        string btnLabel = \"Move \" + _transform.name;\r\n        if (selectedTransforms.Length &gt; 1)\r\n            btnLabel = \"Move selection\";\r\n \r\n        if (Button(btnLabel))\r\n        {\r\n            RandomPosition(minPosition, maxPosition, selectedTransforms);\r\n        }\r\n    }\r\n \r\n   \r\n \r\n    private void RandomPosition(Vector3 min , Vector3 max, Transform[] t)\r\n    {\r\n        for (int i = 0; i &lt; t.Length; i++)\r\n        {\r\n            Vector3 temp = t[i].position;\r\n            if (!Mathf.Approximately(min.x, max.x))\r\n                temp.x = Random.Range(min.x, max.x);\r\n \r\n            if (!Mathf.Approximately(min.y, max.y))\r\n                temp.y = Random.Range(min.y, max.y);\r\n \r\n            if (!Mathf.Approximately(min.z, max.z))\r\n                temp.z = Random.Range(min.z, max.z);\r\n \r\n            Undo.RecordObject(t[i], \"Random position \" + t[i].name);\r\n            t[i].position = temp;\r\n        }\r\n    }\r\n<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<div><\/div>\n<h3>Final Thoughts (and some homework)<\/h3>\n<div>Ha! Didn&#8217;t think you were going to be given homework, did ya?<\/div>\n<div>All of this was done to provide you with a practical example of customizing Unity&#8217;s inspectors. You can apply these to your own classes, or override inspectors that you don&#8217;t like (or think need more functionality). This is one of the many features that makes Unity powerful, it&#8217;s extendible. Not only can you make these custom inspectors to help you with tasks, but you can also make custom context menus, custom menus, and editor windows. My rule is: if I&#8217;m going to be doing something a lot, then why not have a script do it for me. One example is: I ran into a project with about 60 scenes (yeah&#8230;) each scene had its own camera, like usual. Well, my client wanted to change settings on those cameras. I don&#8217;t want to think how long it would have taken me to go through all of those scenes. And what happens when the client wants to make another adjustment to all the cameras (they did a few times)? Or if I miss something because I was trying to do it fast. Unity editor scripting to the rescue! I spent maybe an hour writing a custom script that would go through every scene and change the main camera to the settings I wanted. Changes now take about 1 minute instead of a couple hours. I sure was glad they were using Unity.<\/div>\n<div><\/div>\n<div>On to the homework!<\/div>\n<div>The Custom Transform Inspector isn&#8217;t quite complete. It needs at least one more thing: an even distribution component. Wouldn&#8217;t it be amazing to select a few objects, align them on an axis and then make them nicely distributed? Yes, it would! Your task is to add on to the custom transform inspector and make this happen! The first person to do this will get a free copy of my <a href=\"https:\/\/www.assetstore.unity3d.com\/en\/#!\/content\/38736\" target=\"_blank\" rel=\"noopener\">Mobile Screenshot Helper<\/a> asset from the Unity Asset Store. Just make the code neat and clean and keep to the same naming conventions Im using in the script.<\/div>\n<div><\/div>\n<div>Here are the full scripts for you to play with:<\/div>\n<div><a href=\"http:\/\/pastebin.com\/C1wc7WpF\">Editor\/CustomTransformComponent.cs<\/a><\/div>\n<div><a href=\"http:\/\/pastebin.com\/rq5xMvh4\">Editor\/ShowLocalAxisInspector.cs<\/a><\/div>\n<div><a href=\"http:\/\/pastebin.com\/dJrBwaUs\">ShowLocalAxis.cs<\/a><\/div>\n<div><\/div>\n<div>As always, thanks for reading!<\/div>\n<div><\/div>\n<div><\/div>\n<div><\/div>\n<div>.<\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10\" class=\"pvc_stats all  \" data-element-id=\"10\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Hi everyone! One of the awesome things about Unity is you can customize the editor to add all sorts of cool functionality. This article will show you how to override Unity&#8217;s transform inspector with a more useful customized version. The Custom Transform Component includes: The ability to view and edit the quaternion rotation (nice for experimenting and learning how quaternions work). The ability to show the local axes in the Scene view even when the object is not selected. Some special operations for aligning to other objects, random rotation, random scale, and random position. Here&#8217;s what the final product will&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/naplandgames.com\/blog\/2016\/08\/27\/unity-3d-tutorial-custom-transform-inspector\/\">Continue reading<span class=\"screen-reader-text\">Unity 3D Tutorial &#8211; Custom Transform Inspector<\/span><\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_10\" class=\"pvc_stats all  \" data-element-id=\"10\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":77,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[7],"a3_pvc":{"activated":true,"total_views":18619,"today_views":0},"_links":{"self":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/10"}],"collection":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":7,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/10\/revisions"}],"predecessor-version":[{"id":321,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/10\/revisions\/321"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/media\/77"}],"wp:attachment":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/media?parent=10"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/categories?post=10"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/tags?post=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}