Unity预设序列化的自动化方案

转载http://baizihan.me/2017/02/asset-helper/

预设

在Unity中,我们会将重复使用的资源做成预设(Prefab)。预设上可以挂载脚本并在Aspector面板中指定可序列化的值便于配置。

在实际操作过程中,我们的脚本上需要配置的部分可能常常需要指定一些固定的组件。加入有这样的一个脚本:

image

像这样,rigBody和capsuleCollider如果在游戏运行时获取会有些消耗,而在Editor模式下又需要我们每次从Hierarchy面板拖动到Aspector面板来指定费时费力。而这一切我们可以通过脚本自动完成。我们在Monster脚本上添加如下接口:

public void DoSerialized()
{
	rigBody = GetComponent<Rigidbody>();
	capsuleCollider = GetComponent<CapsuleCollider>();
}

Apply

Unity提供了在预设Apply时对该预设进行操作的Attribute:InitializeOnLoadMethod

我们在Editor目录下创建一个脚本AssetHelper,实现该接口:

static void StartInitializeOnLoadMethod()
{
    // 注册Apply时的回调
    PrefabUtility.prefabInstanceUpdated = delegate(GameObject instance)
    {
        if(instance)
        SaveMonsterPrefab(instance);
    };
}    

static void SaveMonsterPrefab(GameObject instance)
{
    string prefabPath = AssetDatabase.GetAssetPath(PrefabUtility.GetPrefabParent(instance));
    if(!IsMonsterPrefab(prefabPath))
        return;

    Debug.LogFormat("SaveMonsterPrefab Path = {0}", prefabPath);
    Monster comp = instance.GetComponent<Monster>();
    if (null == comp)
    {
        string msg = string.Format("{0} 缺少Monster组件", prefabPath);
        EditorUtility.DisplayDialog("Apply a Monster prefab!", msg, "OK");
        return;
    }

    comp.DoSerialized();
}


static bool IsMonsterPrefab(string path){
    if(path.Contains(MONSTER_FOLDER) && Path.GetExtension(path) == ".prefab")
        return true;

    return false;
}

以后创建Prefab的时候就可以直接添加一个Monster脚本,按一下Apply就行了。

保存

Apply的方法有个明显的缺点,那就是Prefab的改动有时候不会拖到Hierarchy中,而是直接修改,然后Ctrl+S保存,从而没有Apply过程。不用担心,即便这样Unity也有解决方案。

我们将AssetHelper类继承UnityEditor.AssetModificationProcessor类,并实现OnWillSaveAssets方法。这样就可以在资源保存时对资源做操作。实现细节如下:

static string[] OnWillSaveAssets(string[] paths){
    SaveMonsterPrefabs(paths);
    return paths;
}

static void SaveMonsterPrefabs(string[] paths)
{
    foreach (string path in paths)
    {
        if(!IsMonsterPrefab(path))
            continue;

        Debug.LogFormat("SaveMonsterPrefabs {0}", path);

        GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(path, typeof(GameObject));
        if(prefab == null)
        {
            Debug.LogWarning(string.Format("Can not load prefab {0}", path));
            continue;
        }

        GameObject go = UnityEngine.Object.Instantiate(prefab) as GameObject;
        Monster comp = go.GetComponent<Monster>();
        if (null == comp)
        {
            Debug.LogWarning(string.Format("{0} 缺少Monster组件", path));
            continue;
        }

        comp.DoSerialized();
        PrefabUtility.ReplacePrefab(go, prefab);
        UnityEngine.Object.DestroyImmediate(go);
    }
}

这样一来对资源的修改都会做序列化了。

后记

本文所有源代码依然放在我的Github上,有兴趣的朋友可以下来自行参考。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值