Unity3d 使用代码在脚本周边目录下创建文件夹

需求

Unity3d编辑器脚本时而不时会有数据持久化需求,换句话说就是写入数据、保存配置的需求,怎么保存数据先不谈,但我们都知道,想要自己写的工具不污染整个工程的结构,往往我们需要将配置文件(生成的新文件)跟工具脚本整一起,或上一个目录,或同级目录,或同级下的子目录。
于是,“在指定脚本的周边目录下动态创建文件夹”的需求就这样应运而生啦!

代码

简单的描述完这个需求的使用场景,下面我们直接上代码:

using System.IO;
using System.Linq;
#if UNITY_EDITOR
using ADB = UnityEditor.AssetDatabase;
#endif

public static class FolderMaker
{

    /// 
    /// 编辑器下使用,给定一个类的对象,在这个类的同级目录下创建文件夹并返回路径
    /// 
    /// 
    /// 对象
    /// 指定要创建的文件夹的名称
    /// 文件夹的相对路径,相对于Assets文件夹
    public static string Creat(T script, string subPath) where T : UnityEngine.Object //class  
    {
        string newPath = "";
#if UNITY_EDITOR
        string path = ADB.FindAssets("t:Script")
            .Where(v => Path.GetFileNameWithoutExtension(ADB.GUIDToAssetPath(v)) == script.GetType().Name)
            .Select(id => ADB.GUIDToAssetPath(id))
            .FirstOrDefault()
            .ToString();
        //newPath = path.Remove(path.LastIndexOf("/") + 1, Path.GetFileName(path).Length) + subPath; 
        newPath =Path.Combine( Path.GetDirectoryName(path) ,subPath);

        if (!ADB.IsValidFolder(newPath))
        {
            newPath = ADB.GUIDToAssetPath(ADB.CreateFolder(path, subPath));
        }
#endif
        return newPath;
    }
}
    /// 
    /// 编辑器下使用,给定一个类型,在这个类的周边目录下创建文件夹并返回路径
    /// 
    /// 对象
    /// 指定要创建的文件夹的名称
    /// 文件夹的相对路径,相对于Assets文件夹
    public static string Creat(Type script, string subPath)
    {
#if UNITY_EDITOR
        string path = ADB.FindAssets("t:Script")
            .Where(v => Path.GetFileNameWithoutExtension(ADB.GUIDToAssetPath(v)) == script.Name)
            .Select(id => ADB.GUIDToAssetPath(id))
            .FirstOrDefault()
            .ToString();
        path = Path.GetDirectoryName(path);  //去除文件名
        path = Path.GetFullPath(path + "/" + subPath); //整合到完整路径,使用"/../" 回退到上一目录
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
#endif
        return path;
    }

Tips:

  1. using的使用:AssetDatabase 这个类用的简直不要太频繁,使用using ADB = UnityEditor.AssetDatabase;给他取个别名“ADB”。
  2. 预编译指令的使用:预编译指令是必不可少的,如果这个脚本处于Editor文件夹下,继承MonoBehavior的类将无法访问。挪出来就挺不错,但此时如不使用预编译指令,打包便会报错~
  3. 泛型的使用:泛型的使用使得逻辑复用,同时也能类型安全,where T:UnityEngine.Object 限制了使用环境是Unity,如果限制仅仅为 class ,嗯,随便一个字符串就能打发第一个参数,当然运行也就得不到我们想要的结果,报错呢,也肯定是要报的了。
  4. 实现思路,就是轮番使用UnityEditor下的API,查找到这个脚本,拿到脚本所在的目录拼接并创建新的目录。

2019年1月11日 补充:

  • 可以看到笔者在上面提供的代码块中又重载了这个方法,通过这个重载,现在不提供实例也能获取路径啦。
  • 另外,IO操作大幅回归System.IO的API,主要是为了解决2个问题:
    1. 得到上一个文件夹路径 ,使用File.GetFullPath(path),只要在传的参数中拼接 “../” 就能得到上一级目录,拼接多个就能回退多步。
    2. 递归创建文件夹,只需给定一个路径就好。

使用方法:↓

//返回脚本所在的目录的上两级,然后创建2个文件夹
  var path =FolderMaker.Creat(typeof(TagEnumGenarator),@"/../../aa/Bb") + "/EnumTag.cs";

2019年1月18日 补充

    /// 
    /// 编辑器下使用,给定一个类型,在这个类的周边目录下创建文件夹并返回路径
    /// 
    /// 对象
    /// 指定要创建的文件夹的名称
    /// 文件夹的相对路径,相对于Assets文件夹
    public static string Creat(MonoBehaviour script, string subPath)
    {
#if UNITY_EDITOR
        MonoScript m_Script = MonoScript.FromMonoBehaviour(script); //更新 使用UnityEditor API 
        string path = AssetDatabase.GetAssetPath(m_Script);
        path = Path.GetDirectoryName(path);  //去除文件名
        path = Path.GetFullPath(path + "/" + subPath); //整合到完整路径,使用"/../" 回退到上一目录
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
#endif
        return path;
    }

很多时候,Unity 要的是相对于Assets 文件夹的相对路径,加一句就行了,顺便改下方法名,感觉这个方法名与功能才是真的对口

    /// 
    /// 编辑器下使用,给定一个类型,在这个类的周边目录下创建文件夹并返回相对路径
    /// 
    /// ScriptableObject 对象
    /// 指定要创建的文件夹的名称
    /// 文件夹的相对路径,相对于Assets文件夹
    public static string AllocateLocalPath(ScriptableObject script, string subPath)
    {
#if UNITY_EDITOR
        MonoScript m_Script = MonoScript.FromScriptableObject(script); //更新 使用UnityEditor API 
        string path = AssetDatabase.GetAssetPath(m_Script);
        path = Path.GetDirectoryName(path);  //去除文件名
        path = Path.GetFullPath(path + "/" + subPath); //整合到完整路径,使用"/../" 回退到上一目录
        if (!Directory.Exists(path))
        {
            Directory.CreateDirectory(path);
        }
        path = path.Substring(path.IndexOf("Assets"));
#endif
        return path;
    }

Tips:

  • 在Unity编辑器,脚本文件也是一个资源,并且是一个文本资源,由MonoScript表示,通过 UnityEditor.MonoScript.FromMonoBehaviour(MonoBehaviour script)拿到。
  • Unity编辑器模式下,有一套资源管理体系,UnityEditor.AssetDatabase.GetAssetPath(Object assetObject)就可以拿到脚本资源的路径。
  • 从对上述提及的方法签名的描述可知,传入 MonoScript 实例就能得到脚本路径啦。

使用

使用没什么要说的,调用一下这个方法就好了,譬如:

using UnityEngine;
public class Car : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Debug.Log(FolderMaker.Creat(this,"HAHA"+Random.Range(1,150)));
        }
    }
}

但是需要了解的是,尽管这个返回的路径是相对值,但很够用呀,如果想要完整路径的,加上这句就好了:


Unity3d 使用代码在脚本周边目录下创建文件夹_第1张图片

动画

  1. 在上面的动画中,每一次点击鼠标左键便会创建一个文件夹,文件夹名称以“HAHA”开头加上一串随机数。
  2. 另外,笔者在Unity播放状态拖拽并移动了Car这个脚本的位置,但事实上不建议大家这么做。
  3. 其实,这个解决方案只是为了实现编辑器脚本配置文件自动跟随而作,动图演示的貌似用处不大。

总结

这是一个简单的笔记,希望遇到有需要的人~

→ QFrameWork ←

你可能感兴趣的:(Unity3d 使用代码在脚本周边目录下创建文件夹)