Oninspectorgui



Hi everyone, this is my first post. I’m excited to be able to share knowledge regarding what I’ve learned while using unity. I’ve decided to write my first blog post about how to create a custom drop down field for a custom inspector. There are a few ways you can do this. You could use the OnInspectorGUI attribute like so, and maybe spice it up with some groups. Public class MyComponent: MonoBehaviour SerializeField, BoxGroup('Split/Some Settings') private int a, b, c; OnInspectorGUI PropertyOrder(-10), HorizontalGroup('Split', 100) private void ShowImage. As mentioned in a previous article, OnInspectorGUI is the function that is responsible for drawing out the inspector interface for the object. Hence, if you were to look at the Inspector after setting this up, you would see that nothing has changed.

  1. Sirenix Odin Inspector
  2. Oninspectorgui Target
  3. Oninspectorgui
  4. Oninspectorgui Unity
  5. Unity Custom Inspector
  6. Oninspectorgui Button

Over the course of development, I’m constantly finding cool features of Unity and c# that I never new existed. I’ve found some that are really useful, so I’m going to start sharing them regularly here. This week’s requires some prior knowledge. Definitely read up on ScriptableObjects and custom editors if you are unfamiliar. Without further ado:

Making a inspector for any ScriptableObject

Did you know any class deriving from ScriptableObject can be serialized and rendered in a custom Editor with a just a few lines of code? As it turns out, it is really easy:

And that’s pretty much (almost) it! Some stuff you should know:

  • In this example, myEditor.OnInspectorGUI() must be called in your EditorWindow or custom Editor’s OnInspectorGUI() method.
  • Editor.CreateEditor() only needs to be called once, so you can absolutely call it once and cache the result. However, there is a catch: Editor.CreateEditor() throws an error when you call it from OnEnable. You will have to call it in your editor’s OnInspectorGUI() method, and if you want to be efficient you’ll have to use a boolean to make sure it is only called once.

Below is a full code example. In it, we’ll instance a ScriptableObject in a Monobehaviour. We’ll then write a custom inspector that will display the variables in the Monobehaviour, including those in the ScriptableObject:

ExampleScriptableObject.cs

This will be the ScriptableObject we want to display in the inspector. It has two variables, scriptableObjectFloat and scriptableObjectInt, that will display in the inspector once we get the rest of our code working.

ExampleMonobehaviour.cs

This is the Monobehaviour that we will build a custom inspector for. It has a variable called “exampleMonobehaviourString” that will be displayed in the inspector alongside the variables contained in the ScriptableObject we made, which is instanced in this class as “exampleScriptableObject”.

ExampleMonobehaviourEditor.cs

Finally, the class that does the work! This class caches an editor in line 29 and draws it in line 41. This displays our ScriptableObject’s variables alongside those of ExampleMonobehaviour. It’s surprisingly useful! Here’s what it looks like in practice:

Very nice, isn’t it! Monobehaviour variables and ScriptableObject variables all displayed neatly in the inspector.

And that’s it! Leave your questions and comments down below!

Cheers,

-Mark

Creating games can be difficult and time consuming. You have to code all kinds of systems, add and modify art and sound, and of course design levels.

As a programmer, I often found myself overlooking level design, and forgetting just how time consuming and frustrating it could be.

But I also know that as a programmer, there are things I can do to make it easier for myself (and any designers working on the games).

Today, I’ll show you one very useful technique you can use to drastically reduce the timespent on design work, while making it a much morefun process.

The Example – Spawn Points

Enemies are a very common thing in video games, and in a large number of them, enemies are created/spawn throughout the game.

The GameObject spawning them could be simple, instantiating an enemy on a set interval.

Before I show you my technique, let me show you how I used to create them.

Version 1 – A simple transform (very bad)

When I first started placing spawn points in a game, I did it by simply placing a transform. The screenshot below is actually a step beyond what I used to do, because in this one I’ve actually enabled the Icon so you can see it.

Sirenix Odin Inspector

If you haven’t used the Icons before, the selection dialog is just to the left of the Active checkbox in the inspector.

I quickly moved on from just placing a transform though because it got really hard to tell exactly where the spawn point was in the world. If the transform is below the ground, I wouldn’t be able to tell without moving the camera all around. The same goes for a spawn point that’s in a building, hovering over the ground, etc.

Version 2 – Using a cube (less bad)

The next evolution of my spawn points involved cubes. Creating spawn points with a cube renderer mostlyresolved the issue with not being able to easily see the position in the scene.

To make this work though, I needed my spawn points to disable the renderer in their Awake() call so I didn’t have random boxes showing in the world when the game was being played.

It also didn’t really solve the issue of spawning enemies on the ground, so I’d have to make my spawners do a raycast downward to the ground to get their spawn point before popping out an enemy.

I’d try to place the boxes just a bit over the ground, but found that I wasted a lot of time lining things up right, testing, making minor movements, testing, etc.

In addition to that, it felt ugly, but I used this technique for a very long time….

Version 3 – Custom Editors

After using the previous methods for way too long, I finally came up with a solution that solved my previous problems and made buildinglevels muchfaster.

As you can see in the image, Version 3 looks drastically different. There are coloredspheres with lines attaching them. There’s text over them instead of in an Icon, and that text has a lot of info to it.

Before I show you how it’s done, let me explain what it is you’re seeing.

The Greenspheres show actual spawn points for this game. These are points where enemies will be instantiated.

The Bluespheres are waypoints. Enemies spawn at the green spheres then walk to the blue ones.

The lines between them show which waypoints belong to each spawnpoint.

What’s that Text?

The text over the spawn point shows a few things. Let’s examine the top left spawn point.

Oninspectorgui

Intro 10:25-0:28Spawn 2 [1/3]after 5(8s)

Intro 1 – This is the name of the wave/area this spawn point belongs to. In this case, it’s the first introductory wave the player gets when they start the game.

0:25-0:28 – Here you see the time in the wave that this spawn point will be active. This spawn point is active for a very short time, starting 25seconds into the wave and ending only 3 seconds later.

Spawn 2 [1/3] – This tells us how many enemies will spawn from this point. It’s going to spawn 2 zombies, one every three seconds (the [1/3] shows the count and interval). The first one will spawn immediately, and the second after 3 seconds.

after 5 – This part isn’t visible on all spawn points, only on spawn points that delay their start. You can see that in the Hierarchy, this spawn point is under a gameobject that enables after 20 seconds. Each spawnpoint in a timer can have an additional delay added to them to avoid a large list of timers in the hierarchy. The 5 second delay is what makes this spawner start at 0:25 instead of 0:20.

(8s) – The last thing you see just shows how long this spawnpoint is enabled. For this one, after 8 seconds it will auto disable itself. This is just time of the last spawn minus the time the spawn point becomes enabled (28 – 20 in this case).

Snapping to the Terrain or Navmesh

One final benefit of this system that I want to show before getting into code is the ability to have your spawn points and waypoints automatically snap to the terrain or navmesh. In the example below, you can see that when I move this waypoint around it will automatically find its place on the ground as soon as I release it.

This saves a ton of time and resolves that entire issue of lining things up. Don’t do these things manually, have the editor do it for you.

How It Works

To make my custom spawn points work like they do, I take advantage of two great features in Unity, Gizmos and Custom Inspectors.

Both parts do about half of the work required to get the full functionality.

Let’s start with this snippet from my EnemySpawner.cs script

The first thing we do here is get the Wave parent of this spawner. This is the GameObject that all spawners and timers will be under for a specific wave or area of the game.

In the example above, you saw the green part “Intro 1“. That part was just the name of the wave we find right here.

Line 6 takes this wave name and formats uses string.Format to split the wave name from the current spawners name, which is why “Intro 1” is above the spawning details.

On Line 8, we check to see if the wave this gizmo is for is currently selected. We then use that to determine if we want a green spawner gizmo or a gray one. I do this so we can easily tell which spawners are related. All spawners in a wave will be colored at the same time, and all the ones from other waves will just show up as gray.

Line 12draws the sphere using Gizmos.DrawSphere, in whichever color we’ve chosen.

Lines 14-15 will draw the final textabove the sphere if the spawner is in the selected wave.

The OnDrawGizmos code is pretty short, and on it’s own it does a bit of really useful stuff, but there’s a lot missing. It does show the spheres, and it places the name above the sphere with the wave name as a prefix, but there’s a lot morewewant to happen.

For example the label from line 15 has a lot of useful info, and we pull that from the name, but we don’t want to manually enter that info, we want it auto generated and updated whenever we change things.

Overriding ToString()

To generate the name, with all the useful data, we override the ToString method of our EnemySpawner class.

If you’ve never overridden the ToString method, you may want to check out this description for a simpler sample of how it works https://msdn.microsoft.com/en-us/library/ms173154.aspx

Every object in c# implements the ToString method that you can override (the default return value for most objects is the name of the class/type).

In this example, we’re building up the rest of the label text. While I won’t go into the details of each line, the end result of this method looks like this

Oninspectorgui Target

:

The Custom Editor

To tie this all together, we use a custom editor for the EnemySpawner.

Before you see the bigger parts of the script, let’s start with the initial attribute that tells Unity this classis a customeditor.

The CustomEditor attribute allows you to tell the engine which MonoBehaviour you want the editor to be used for. This is specified by giving it the type of the MonoBehaviour. In this example it’s typeof(EnemySpawner).

Also remember to add the using UnityEditor statement and make the baseclass for your custom editor be of typeEditor“.

The Editor class has one important method you need to override. Check out this expanded version of the script and the OnInspectorGUI method that’s being overridden.

This method is called every frame in the editor while the Inspector window is visible and the object is selected. If the Inspector is not visible, or is showing some other game object, this code won’t be called.

Code Breakdown

The first thing we do in this OnInspectorGUI method is cache the component we’re working with.

Oninspectorgui

On line 12, we assign the target gameobject to the _enemySpawner variable.

The variable target is defined by the editor class and specifies the gameobject this editor is showing currently

Line 13 calls the base editor class version of OnInspectorGUI so it can handle anything that we’re not dealing with. This is required because we’re overriding the behavior of OnInspectorGUI.

Lines 14-19 are a single method call to create a range slider that will fill the min and max movement speed. I do this just to enforce the idea that the max must be greater than the minimum. As a benefit, it also makes the value a little easier to visualize.

Lines 21-24 are there to add waypoints to the spawners. I won’t cover in detail how they work, but these buttons essentially add a child object that will be used as a waypoint. If it’s a random waypoint, my navigation code will select one at random, if it’s static, the enemies will path around them in order. These also have their own gizmo and custom editor code to make them show up as blue in the scene view.

Oninspectorgui

Line 28 just calls a method to disable any left over colliders or renderers on the spawner. Generally there aren’t any, but sometimes one gets created with a cube or sphere and I want to make sure that’s disabled right away. I could just remove them here too, but disabling does the same job and feels safer.

Line 30 does one of the most important parts. It calls the method to stick the spawner to the ground. Sticking the spawner down is done by a raycast from the spawners current position aimed downward. We get the hit point and update the spawners position.

Line 33 wraps it all up by updating the spawners name. It uses the overridden ToString() method we created above to determine the objects new name.

Auto Naming in Action

Oninspectorgui Unity

Important Note

Unity Custom Inspector

For a custom editor to work, you need to place the script in a sub-folder named “Editor“. This sub-folder can be anywhere in your project, and you can have multiple Editor folders, but only scripts in an Editor folder will work.

Oninspectorgui Button

Related