五个月之后,我终于想起来了我还有个博客。(要不是双十一花了太多钱,我可能还不会静下心来更一下【狗头】)
今天来讲讲两个功能
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的方法)。