<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[Ondrej Paska Blog]]></provider_name><provider_url><![CDATA[https://fishtrone.wordpress.com]]></provider_url><author_name><![CDATA[Ondrej Paska]]></author_name><author_url><![CDATA[https://fishtrone.wordpress.com/author/randalfien/]]></author_url><title><![CDATA[Custom Unity Inspectors and Conditional&nbsp;Compilation]]></title><type><![CDATA[link]]></type><html><![CDATA[<p>Custom inspectors in Unity are very handy to show and edit data on your behaviors and scriptable objects. To create custom inspectors in Unity you need to create a new class and extend <em>Editor</em> from the <em>UnityEditor</em> namespace. To tell Unity for which class the inspector is for, use the <em>CustomEditor</em> attribute.</p>
<p>A very simple custom Inspector for a class called <em>TestBehaviour</em> can look like this:</p>
<p><!-- HTML generated using hilite.me --></p>
<div style="background:#ffffff;overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">
<pre style="margin:0;line-height:125%;"><span style="color:#336699;">[CustomEditor(typeof(TestBehaviour))]</span>
<span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">class</span> <span style="color:#bb0066;font-weight:bold;">TestBehaviourInspector</span> : Editor
{
    <span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">override</span> <span style="color:#008800;font-weight:bold;">void</span> <span style="color:#0066bb;font-weight:bold;">OnInspectorGUI</span>()
    {
        TestBehaviour myTarget = (TestBehaviour)target;
        myTarget.Variable1 = EditorGUILayout.IntField(<span style="color:#dd2200;background-color:#fff0f0;">"Level"</span>, Mathf.RoundToInt(myTarget.Variable1/<span style="color:#0000dd;font-weight:bold;">2f</span>)*<span style="color:#0000dd;font-weight:bold;">2</span>);        
        EditorGUILayout.LabelField(<span style="color:#dd2200;background-color:#fff0f0;">"Level"</span>, myTarget.Variable1.ToString());
    }
}
</pre>
</div>
<p>&#8211;</p>
<p>Sometimes it is useful to create custom inspectors even for built-in components like the Transform. For example for a 2D game we might exclude the 3D rotation options and the z axis for position and scale, to make it easier to use by artists and content creators.</p>
<p>The DrawDefaultInspector() method will draw all the default inspector editors for your target. Using this for the Transform component will look like this.<img loading="lazy" data-attachment-id="49" data-permalink="https://fishtrone.wordpress.com/2019/05/11/custom-unity-inspectors-and-conditional-compilation/snap/" data-orig-file="https://fishtrone.files.wordpress.com/2019/05/snap.png" data-orig-size="347,150" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="snap" data-image-description="" data-image-caption="" data-medium-file="https://fishtrone.files.wordpress.com/2019/05/snap.png?w=300" data-large-file="https://fishtrone.files.wordpress.com/2019/05/snap.png?w=347" class="alignnone size-full wp-image-49" src="https://fishtrone.files.wordpress.com/2019/05/snap.png?w=347&#038;h=150" alt="snap" width="347" height="150" srcset="https://fishtrone.files.wordpress.com/2019/05/snap.png 347w, https://fishtrone.files.wordpress.com/2019/05/snap.png?w=150&amp;h=65 150w, https://fishtrone.files.wordpress.com/2019/05/snap.png?w=300&amp;h=130 300w" sizes="(max-width: 347px) 100vw, 347px" /></p>
<p>You can see that it looks quite different from the standard transform inspector which shows the Euler angles instead of the quaternions (the internal representation of rotation).</p>
<p>To create a simplified 2D inspector we can show just X and Y for position and use a single slider for the Z axis rotation in Euler angles. I also added a button for rounding the position to integer values.</p>
<div style="background:#ffffff;overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">
<pre style="margin:0;line-height:125%;"><span style="color:#336699;">[CustomEditor(typeof(Transform))]</span>
<span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">class</span> <span style="color:#bb0066;font-weight:bold;">TransformInspector</span> : Editor
{
    <span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">override</span> <span style="color:#008800;font-weight:bold;">void</span> <span style="color:#0066bb;font-weight:bold;">OnInspectorGUI</span>()
    {
        Transform myTarget = (Transform)target;


        myTarget.position = EditorGUILayout.Vector2Field(<span style="color:#dd2200;background-color:#fff0f0;">"Position"</span>, myTarget.position);
        myTarget.rotation = Quaternion.Euler(<span style="color:#0000dd;font-weight:bold;">0</span>, <span style="color:#0000dd;font-weight:bold;">0</span>, 
            EditorGUILayout.Slider(<span style="color:#dd2200;background-color:#fff0f0;">"Rotation"</span>, myTarget.localRotation.eulerAngles.z, <span style="color:#0000dd;font-weight:bold;">0</span>, <span style="color:#0000dd;font-weight:bold;">365</span>)
            );

        <span style="color:#008800;font-weight:bold;">if</span> (GUILayout.Button(<span style="color:#dd2200;background-color:#fff0f0;">"Round Position"</span>))
        {
            myTarget.position = <span style="color:#008800;font-weight:bold;">new</span> Vector3(
                    Mathf.Round(myTarget.position.x),
                    Mathf.Round(myTarget.position.y),
                    Mathf.Round(myTarget.position.z)
                );
        }
    } 
}
</pre>
</div>
<p>&#8211;</p>
<p>This will look like this:</p>
<p><img loading="lazy" data-attachment-id="50" data-permalink="https://fishtrone.wordpress.com/2019/05/11/custom-unity-inspectors-and-conditional-compilation/snap2/" data-orig-file="https://fishtrone.files.wordpress.com/2019/05/snap2.png" data-orig-size="426,87" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="snap2" data-image-description="" data-image-caption="" data-medium-file="https://fishtrone.files.wordpress.com/2019/05/snap2.png?w=300" data-large-file="https://fishtrone.files.wordpress.com/2019/05/snap2.png?w=426" class="alignnone size-full wp-image-50" src="https://fishtrone.files.wordpress.com/2019/05/snap2.png?w=426&#038;h=87" alt="snap2" width="426" height="87" srcset="https://fishtrone.files.wordpress.com/2019/05/snap2.png 426w, https://fishtrone.files.wordpress.com/2019/05/snap2.png?w=150&amp;h=31 150w, https://fishtrone.files.wordpress.com/2019/05/snap2.png?w=300&amp;h=61 300w" sizes="(max-width: 426px) 100vw, 426px" /></p>
<p>It might be useful to go back to the standard inspector sometimes. That&#8217;s when conditional compilation comes in.</p>
<p>We can use <em>#if FlagName</em> in our code to tell the compiler to only compile the following code if the Flag is set. There are some flags automatically provided by Unity like the <em>UNITY_EDITOR</em> flag which can be used to only include code for use within the editor. We can set our own flags in Player Settings under <strong>Configuration/Scripting Define Symbols</strong>. More conveniently we can set these flags from code.</p>
<p><!-- HTML generated using hilite.me --></p>
<div style="background:#ffffff;overflow:auto;width:auto;border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;">
<pre style="margin:0;line-height:125%;"><span style="color:#008800;font-weight:bold;">using</span> <span style="color:#bb0066;font-weight:bold;">System.Collections.Generic</span>;
<span style="color:#008800;font-weight:bold;">using</span> <span style="color:#bb0066;font-weight:bold;">System.Linq</span>;
<span style="color:#008800;font-weight:bold;">using</span> <span style="color:#bb0066;font-weight:bold;">UnityEditor</span>;

<span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">static</span> <span style="color:#008800;font-weight:bold;">class</span> <span style="color:#bb0066;font-weight:bold;">TestMenuItem</span>
{
    <span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">const</span> <span style="color:#888888;font-weight:bold;">string</span> Flag = <span style="color:#dd2200;background-color:#fff0f0;">"USE_CUSTOM_INSPECTORS"</span>;

<span style="color:#cc0000;font-weight:bold;">#if !USE_CUSTOM_INSPECTORS    </span>
<span style="color:#336699;">    [MenuItem("MyTools/Custom Inspectors On")]</span>
    <span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">static</span> <span style="color:#008800;font-weight:bold;">void</span> <span style="color:#0066bb;font-weight:bold;">CustomInspectorsOn</span>()
    {
        RefreshCompilationFlag(<span style="color:#008800;font-weight:bold;">true</span>);
    }
<span style="color:#cc0000;font-weight:bold;">#else    </span>
<span style="color:#336699;">    [MenuItem("MyTools/Custom Inspectors Off")]</span>
    <span style="color:#008800;font-weight:bold;">public</span> <span style="color:#008800;font-weight:bold;">static</span> <span style="color:#008800;font-weight:bold;">void</span> <span style="color:#0066bb;font-weight:bold;">CustomInspectorsOff</span>()
    {
        RefreshCompilationFlag(<span style="color:#008800;font-weight:bold;">false</span>);
    }
<span style="color:#cc0000;font-weight:bold;">#endif</span>
    
    <span style="color:#888888;">/**</span>
<span style="color:#888888;">     * Edits the custom symbols defined in Project settings. Triggers a recompile.</span>
<span style="color:#888888;">     */</span>
    <span style="color:#008800;font-weight:bold;">private</span> <span style="color:#008800;font-weight:bold;">static</span> <span style="color:#008800;font-weight:bold;">void</span> <span style="color:#0066bb;font-weight:bold;">RefreshCompilationFlag</span>(<span style="color:#888888;font-weight:bold;">bool</span> <span style="color:#008800;font-weight:bold;">value</span>)
    {
        <span style="color:#888888;font-weight:bold;">string</span> definesString = <span style="color:#7f7e28;">PlayerSettings</span>.GetScriptingDefineSymbolsForGroup(EditorUserBuildSettings.selectedBuildTargetGroup);
        
        List&lt;<span style="color:#888888;font-weight:bold;">string</span>&gt; allDefines = definesString.Split(<span style="color:#dd2200;background-color:#fff0f0;">';'</span>).ToList();
            
        <span style="color:#008800;font-weight:bold;">if</span> (allDefines.Contains(Flag) &amp;&amp; !<span style="color:#008800;font-weight:bold;">value</span>)
        {
            allDefines.Remove(Flag);
        }
        <span style="color:#008800;font-weight:bold;">else</span> <span style="color:#0066bb;font-weight:bold;">if</span> (!allDefines.Contains(Flag) &amp;&amp; <span style="color:#008800;font-weight:bold;">value</span>)
        {
            allDefines.Add(Flag);
        }
           
        <span style="color:#7f7e28;">PlayerSettings</span>.SetScriptingDefineSymbolsForGroup(
            EditorUserBuildSettings.selectedBuildTargetGroup,
            <span style="color:#888888;font-weight:bold;">string</span>.Join(<span style="color:#dd2200;background-color:#fff0f0;">";"</span>, allDefines.ToArray()));
    }
}
</pre>
</div>
<p>&#8211;</p>
<p>What this code does it creates a custom menu items that allow us to turn this specific compile flag On and Off. What&#8217;s neat is that we use the same flag to only show the relevant one (only showing On when the flag is Off and vice versa).</p>
<p><img loading="lazy" data-attachment-id="51" data-permalink="https://fishtrone.wordpress.com/2019/05/11/custom-unity-inspectors-and-conditional-compilation/png-txt/" data-orig-file="https://fishtrone.files.wordpress.com/2019/05/png.txt_.png" data-orig-size="373,93" data-comments-opened="1" data-image-meta="{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}" data-image-title="png.txt" data-image-description="" data-image-caption="" data-medium-file="https://fishtrone.files.wordpress.com/2019/05/png.txt_.png?w=300" data-large-file="https://fishtrone.files.wordpress.com/2019/05/png.txt_.png?w=373" class="alignnone size-full wp-image-51" src="https://fishtrone.files.wordpress.com/2019/05/png.txt_.png?w=373&#038;h=93" alt="png.txt" width="373" height="93" srcset="https://fishtrone.files.wordpress.com/2019/05/png.txt_.png 373w, https://fishtrone.files.wordpress.com/2019/05/png.txt_.png?w=150&amp;h=37 150w, https://fishtrone.files.wordpress.com/2019/05/png.txt_.png?w=300&amp;h=75 300w" sizes="(max-width: 373px) 100vw, 373px" /></p>
<p>This blog post is the first part of a series about Unity editor scripting based on a lecture I gave to gamedev students at <a href="https://www.facebook.com/gamedev.cuni.cz/" target="_blank" rel="noopener">gamedev.cuni.cz</a> .</p>
<p>The source code along with other resources can be found at <a href="https://github.com/randalfien/unity-editor-scripting-tips">github.com/randalfien/unity-editor-scripting-tips</a></p>
<p>&nbsp;</p>
]]></html><thumbnail_url><![CDATA[https://fishtrone.files.wordpress.com/2019/05/snap.png?fit=440%2C330]]></thumbnail_url><thumbnail_width><![CDATA[347]]></thumbnail_width><thumbnail_height><![CDATA[150]]></thumbnail_height></oembed>