Custom ScriptableWizard in Unity

When I was approaching making “Replace Tool for Level Designers” I encounter ScriptableWizard. I didn’t know that such a thing existed in Unity! ?

It got me curious as I was planning to make that tool using regular Custom Editor Window, but all of a sudden, there was space to try something new! Unfortunately, I didn’t use ScriptableWizard as it wasn’t suited for what I wanted.

But I think it’s time to revisit it and learn more about it!

The first thing that stroke me was that ScriptableWizard class existed. I didn’t know about it until fairly recently! ?

However my shock didn’t prevent me from learning about it a little. I found out that it can be pretty useful! Especially for building tools as it has a few things already in place. ?

If you want to see what there is to use, I would recommend checking official documentation on ScriptableWizard.

We will use it to build a simple tool to create some folders in your project!

The idea ?

The idea is simple. Create a tool which will create default folders in your project, so YOU don’t have to do it. We will have a bunch of available folders which the user can pick to create.

Also, we will show an error message when the selected folder is already created.

Sound easy? Let’s do it!

Coding ?‍?

The process of creating custom ScriptableWizard is very similar to process of creating custom editor window.

On the beginning, you have to open the window, and then you can provide content of that window. However, unlike in an editor window, in a wizard, Unity will display our public and serialized variables. With that, we don’t need to write OnGUI() to view them, which saves us a little time.

Let’s write some code finally!

using UnityEditor;
using UnityEngine;
using System.IO;

/// <summary>
/// Folder creator wizard.
/// </summary>
public class FolderCreatorWizard : ScriptableWizard
{
    // Flags for folder creation.
    // Animations
    public bool CreateAnimationsFolder;
    // Materials
    public bool CreateMaterialsFolder;
    // Prefabs
    public bool CreatePrefabsFolder;
    // Resources
    public bool CreateResourcesFolder;
    // Scripts
    public bool CreateScriptsFolder;

    /// <summary>
    /// Creating and displaying wizard.
    /// </summary>
    [MenuItem("Tools/Create Default Folders")]
    public static void CreateWizard()
    {
        DisplayWizard<FolderCreatorWizard>("Create Default Folders", "Create");
    }
}

This is enough code to display our wizard window, so let’s see how it looks!

Our new cool wizard.

Looks cool! And we didn’t do much yet! ?

What you can also notice is that you can’t dock the wizard window. But the wizard is meant to do his things and disappear, so it’s not a problem. ?

ScriptableWizard comes with a few methods that we can implement. In our example we need just two of them – OnWizardUpdate() and OnWizardCreate().

The first one runs whenever the window needs to be updated. We can use this method to determine if selected folders already exist and show an error message accordingly.

The second method is called when user click Create button on the bottom of the window. We will use it to create folders that the user picked in the wizard window.

So let’s implement them!

using UnityEditor;
using UnityEngine;
using System.IO;

/// <summary>
/// Folder creator wizard.
/// </summary>
public class FolderCreatorWizard : ScriptableWizard
{
    ...

    /// <summary>
    /// Wizard Update.
    /// Runs when window need to be refreshed.
    /// </summary>
    private void OnWizardUpdate()
    {
        // Shows message what to do.
        helpString = "Select folders to create!";

        // Building error message if any of the selected folder exists.
        errorString = "";

        if (CreateAnimationsFolder && Directory.Exists(Path.Combine(Application.dataPath, Keys.AnimationsFolder)))
        {
            // check is folder exist and maybe set error.
            errorString += string.Format("Folder \"{0}\" already exists!\n", Keys.AnimationsFolder);
        }

        if (CreateMaterialsFolder && Directory.Exists(Path.Combine(Application.dataPath, Keys.MaterialsFolder)))
        {
            // check is folder exist and maybe set error.
            errorString += string.Format("Folder \"{0}\" already exists!\n", Keys.MaterialsFolder);
        }

        if (CreatePrefabsFolder && Directory.Exists(Path.Combine(Application.dataPath, Keys.PrefabsFolder)))
        {
            // check is folder exist and maybe set error.
            errorString += string.Format("Folder \"{0}\" already exists!\n", Keys.PrefabsFolder);
        }

        if (CreateResourcesFolder && Directory.Exists(Path.Combine(Application.dataPath, Keys.ResourcesFolder)))
        {
            // check is folder exist and maybe set error.
            errorString += string.Format("Folder \"{0}\" already exists!\n", Keys.ResourcesFolder);
        }

        if (CreateScriptsFolder && Directory.Exists(Path.Combine(Application.dataPath, Keys.ScriptsFolder)))
        {
            // check is folder exist and maybe set error.
            errorString += string.Format("Folder \"{0}\" already exists!\n", Keys.ScriptsFolder);
        }

        // Set flag to enable Create button.
        isValid = (CreateAnimationsFolder || CreateMaterialsFolder ||
                   CreatePrefabsFolder || CreateResourcesFolder || CreateScriptsFolder)
                    && errorString.Length == 0;
    }

    /// <summary>
    /// Method called on Create button click.
    /// Used here to create selected folder.
    /// </summary>
    private void OnWizardCreate()
    {
        // Creating paths and new folders.

        // Animations
        string path = Path.Combine(Application.dataPath, Keys.AnimationsFolder);
        if (CreateAnimationsFolder && !Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            Debug.LogFormat("Directory created: {0}", path);
        }

        // Materials
        path = Path.Combine(Application.dataPath, Keys.MaterialsFolder);
        if (CreateMaterialsFolder && !Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            Debug.LogFormat("Directory created: {0}", path);
        }

        // Prefabs
        path = Path.Combine(Application.dataPath, Keys.PrefabsFolder);
        if (CreatePrefabsFolder && !Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            Debug.LogFormat("Directory created: {0}", path);
        }

        // Resources
        path = Path.Combine(Application.dataPath, Keys.ResourcesFolder);
        if (CreateResourcesFolder && !Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            Debug.LogFormat("Directory created: {0}", path);
        }

        // Scripts
        path = Path.Combine(Application.dataPath, Keys.ScriptsFolder);
        if (CreateScriptsFolder && !Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
            Debug.LogFormat("Directory created: {0}", path);
        }

        // Refresh Project view to see newly created folders.
        AssetDatabase.Refresh();
    }
}

With this part done, I think we can check our final result!

The result ?

Wizard with error message for existing folders.

I think it might be useful as a setup tool. ?

And with ScriptableWizard there might be even more things to create!

So what do you think about it? Are you planning to use it? Let me know in the comment section below!

If you want to get notified on future content, sign up for the newsletter!

As always, the whole project is available at my public repository. ?

And I hope to see you next time! ?

5 1 vote
Article Rating
Subscribe
Notify of
guest
2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
BartekW
BartekW
3 years ago

Great job, helped a lot 🙂

Danny
Danny
2 years ago

Never even knew about this! Looks like it could be very powerful and useful!

2
0
Would love your thoughts, please comment.x
()
x