Unity 讲一讲导入的图片自动变成Sprite和自动生成切换场景菜单

五个月之后,我终于想起来了我还有个博客。(要不是双十一花了太多钱,我可能还不会静下心来更一下【狗头】)

今天来讲讲两个功能
1.导入的图片自动转成Sprite类型,免去了每次新导入一张图就要改一下类型的繁琐操作。
2.新创建的场景可以直接在菜单栏的树状目录下显示。免去了新建了临时场景再想变回去时找起来贼麻烦的问题。

首先,讲一个Unity的API AssetPostprocessor
这是一个编辑器类。主要做的就是在你导入资源之后或之前可以来处理一下这些资源。
https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html

好了,开始解决第一个问题。
当你导入一张图片时,如下
在这里插入图片描述
在这里插入图片描述
图片时Default格式的。你的Image组件并不能使用这样的图片。你需要把它换成Sprite(2D and UI)
虽然说你可以选中好几个图片,一起来修改他们的类型。但是吧,我就是觉得很麻烦。
这时候,刚刚提到的AssetPostprocessor的用处就来了

在Editor目录下新建一个类,加入如下代码:

using UnityEditor;
using UnityEngine;

public class AssetPostManager : AssetPostprocessor
{
    void OnPostprocessTexture(Texture texture)
    {
        if (assetPath.StartsWith("Assets/Resources/Image"))
        {
            TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
            if ((importer != null) && (importer.textureType != TextureImporterType.Sprite))
            {
                importer.textureType = TextureImporterType.Sprite;
                importer.SaveAndReimport();
            }
        }
    }
}

这段代码,应该很好理解的了。
先判断一下路径(对于我的项目来说,prefab的图片都是放在这里的,所以我就只修改这个目录下的图片类型)。
接着判断一下,如果不是Sprite就改成Sprite。这个类型判断最好加上,因为可能会影响九宫格的数据。
最后一定要SaveAndReimport()一下,才能看到被修改了。

好了,这玩意没啥值得继续说的了。开始说第二个问题。
当你在调一些模型时,喜欢ctrl+N来创建一个新的未保存场景来改,当你改完了之后,你得回到默认开始的场景来进行实际的跑游戏来看效果。这时候你就要满世界的找你需要的场景,而且当你双击了之后,你的选中资源也变了,你又得满世界找刚刚调好的资源。
这时候,你是不是十分希望有这么一个菜单:
在这里插入图片描述

在这里插入图片描述
可以动态的生成一个菜单来快捷切换场景。

可能你的第一反应是:“我写一堆MenuItem不就行了”。
虽然这句话很有道理,但是你得想一想。一来,你是不是每新加一个场景就要在这里写一下。二来,一般其他场景都是美术那边需要的,他们应该不会来写这个代码吧。

所以对于需求来说,自动化开始有点用处的。
但是你可能有疑问了,Unity的编辑器属性还支持这种动态数量的MenuItem的吗?
我特意去查了一下,有位老哥回答如下:
在这里插入图片描述
明确指出了只支持Added和Removed,并不支持Adding和Removing。这个理解下来就是说,只有Unity认为DLL需要变的时候,才会重新编译这些C#文件。如果你导入了一个非C#代码的话,他不会做任何修改。

那这岂不是就不能做了吗?
但是文章我都写了,肯定是有办法啊。毕竟正经路子没有,但是架不住IO大法好啊。

闲话扯完,开搞!
这时候有要涉及到刚刚说的AssetPostprocessor类。
其中有这么一个方法,就是当你导入新的资源时,必定会走OnPreprocessAsset这个方法。
那就好搞了,先上代码:

using System.IO;
using UnityEditor;
using UnityEngine;

public class AssetPostManager : AssetPostprocessor
{
    void OnPreprocessAsset()
    {
        if (assetPath.StartsWith("Assets/Scene"))
        {
            CreateSceneSelectMenuFile();
        }
    }

    private void CreateSceneSelectMenuFile()
    {
        string fileStr = "using UnityEditor;\nusing UnityEngine;\nusing UnityEditor.SceneManagement;\n\npublic class SceneSelectMenu\n{{\n{0}}}";
        string[] sceneNames = Directory.GetFiles(Application.dataPath + "/Scene");
        string funcStr = "";
        string funcTemplateStr =
            "    [MenuItem(\"场景切换/打开{0}Scene\")]\n" +
            "    public static void Enter{0}Scene()\n" +
            "    {{\n" +
            "        if (Application.isPlaying) return;\n" +
            "        EditorSceneManager.OpenScene(\"Assets/Scene/{0}.unity\");\n" +
            "    }}\n\n";
        for (int index = 0; index < sceneNames.Length; index++)
        {
            string fileName = sceneNames[index].Substring(sceneNames[index].LastIndexOf("\\") + 1);
            if (fileName.EndsWith(".unity"))
            {
                string sceneName = fileName.Split('.')[0];
                funcStr += string.Format(funcTemplateStr, sceneName);
            }
        }
        fileStr = string.Format(fileStr, funcStr);

        StreamWriter writer = new StreamWriter(Application.dataPath + "/Script/Editor/DevTools/SceneSelectMenu.cs");
        writer.Write(fileStr);
        writer.Close();

        AssetDatabase.ImportAsset("Assets/Script", ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceSynchronousImport);
    }
}

也是简单易懂是吧。
我的场景都放在Assets/Scene目录下,所以我就只针对放在这个目录下的文件。
先写好一个文件需要的基本内容,fileStr。以及一个MenuItem代码块的模板,funcTemplateStr。
接下来就遍历场景目录下的文件。嗯,只需要以.unity为后缀名的场景文件名。把这些内容套进fileStr中。
然后就是用StreamWriter来写入文件。这里有两件事要记住:一个是经常忘记的Close()。另一个就是,因为这个文件是会覆盖的写入的,所以最好不要把其他东西写到这个文件里。(别问我为什么不检查是否不存在再增加,我懒~)
最后记得要导入刷新一下资源。不然你还得先鼠标点到unity外面再点回来,就很墨迹了。

瞅一眼生成好的文件:

using UnityEditor;
using UnityEngine;
using UnityEditor.SceneManagement;

public class SceneSelectMenu
{
    [MenuItem("场景切换/打开MainCityScene")]
    public static void EnterMainCityScene()
    {
        if (Application.isPlaying) return;
        EditorSceneManager.OpenScene("Assets/Scene/MainCity.unity");
    }

    [MenuItem("场景切换/打开MazeScene")]
    public static void EnterMazeScene()
    {
        if (Application.isPlaying) return;
        EditorSceneManager.OpenScene("Assets/Scene/Maze.unity");
    }

    [MenuItem("场景切换/打开StartScene")]
    public static void EnterStartScene()
    {
        if (Application.isPlaying) return;
        EditorSceneManager.OpenScene("Assets/Scene/Start.unity");
    }

}

针不戳~

哦对了,有两件事要说一下。
1.只有导入的文件才会走OnPreprocessAsset这个方法,所以只删除一个场景这样的操作是不会执行的。可以通过OnPostprocessAllAssets这个方法来做处理。(我懒,就没有搞)
2.场景名不要带有空格。新创建的场景名默认是“New Scene”,可能会有一下报错,不过没关系,继续改就好了。(如果改了也不好,那就要么修改一下,有空格的文件不生成,或者去掉空格,或者重写一下创建Scene的方法)。

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值