Unity一鍵自動將多個FBX檔案生成AB包+又一些小玩意

qq_51147038發表於2020-12-12

今天閒來無事,便寫了這個部落格,大家感興趣可以看看
首先,由於FBX是外部檔案,並不能直接進行處理,所以我的思路是現將FBX檔案製作成預製體,然後再打成AB包。
首先我們先在Assets工程目錄下建立一個Editor資料夾,再新建一個指令碼,我們將它取名為“MyCreateAB”,記住,一定要把這個指令碼放在Editor目錄下,只有這樣Unity才能夠將其識別為編輯器擴充套件指令碼。
在這裡插入圖片描述

雙擊開啟指令碼進行一些小更改,先引用UnityEditor,System.IO,然後再繼承自EditorWindow

using UnityEditor;
using System.IO;
public class MyCreateAB :EditorWindow

接下來再是擴充套件程式碼

//編輯器擴充套件
    [MenuItem("My Tools/CreateAB")]
    public static void CreateAB()
    {
        GetWindow<MyCreateAB>(true, "打包工具");
    }
    string filePath;
    private void OnGUI()
    {
        GUILayout.Label("資源路徑");
        filePath = GUILayout.TextField(filePath);
        if (GUILayout.Button("開始打包"))
        {
            CopyDirectory(filePath);
        }
    }

在這裡我們在編輯器上新增了一個"My Tools"選項,然後在下面新增了一個"CreateAB"按鈕
在這裡插入圖片描述

點選這個按鈕便會開啟一個視窗,而視窗內容我們就在OnGU裡面進行編寫I,我寫的開啟之後就會是下面這樣
在這裡插入圖片描述
接下來便是重頭戲了,關於邏輯的編寫,首先我們直接將資源複製到我們工程的Resources目錄下

    public static void CopyDirectory(string filePath)
    {
        //將資源路徑下的檔案複製到工程Resources目錄下
        //建立Resources目錄
        if (!Directory.Exists(Application.dataPath + "/Resources"))
        {
            Directory.CreateDirectory(Application.dataPath + "/Resources");
        }
        DirectoryInfo mainInfo = new DirectoryInfo(filePath);
        DirectoryInfo[] infos= mainInfo.GetDirectories();
        for (int i = 0; i < infos.Length; i++)
        {
            //沒有資料夾便建立檔案
            if (!Directory.Exists(Application.dataPath+ "/Resources/" + infos[i].Name))
            {
                Directory.CreateDirectory(Application.dataPath + "/Resources/" + infos[i].Name);
            }
            FileInfo[] files = infos[i].GetFiles();
            for (int j = 0; j < files.Length; j++)
            {
                //沒有檔案就複製過來
                if (!File.Exists(Application.dataPath + "/Resources/" + infos[i].Name + "/" + files[j].Name))
                {
                    File.Copy(filePath + "/" + infos[i].Name + "/" + files[j].Name, Application.dataPath + "/Resources/" + infos[i].Name + "/" + files[j].Name);
                }
            }
        }
        //這裡需要重新整理一下
        AssetDatabase.Refresh();
        //複製完成
        BuildAB();
    }

複製完成之後,我們再考慮如何將之製作成為AB包,而Unity官方早就為我們準備好了在編輯器模式下仍舊可以對物體進行處理的Api了

    public static void BuildAB()
    {
        //開始打包,先把streamingAssetsPath目錄建立出來
        if (!Directory.Exists(Application.streamingAssetsPath))
        {
            Directory.CreateDirectory(Application.streamingAssetsPath);
        }
        DirectoryInfo info = new DirectoryInfo(Application.dataPath + "/Resources");
        DirectoryInfo[] infos = info.GetDirectories();
        for (int i = 0; i < infos.Length; i++)
        {
            FileInfo[] fileInfos= infos[i].GetFiles();
            for (int j = 0; j < fileInfos.Length; j++)
            {
                //遍歷每個資料夾下的檔案,如果是FBX檔案,就通過編輯器例項化出來再生成預製體
                if (fileInfos[j].Extension == ".FBX")
                {
                    string modelName= fileInfos[j].Name.Replace(".FBX", "");
                    GameObject model = Resources.Load<GameObject>(infos[i].Name+"/"+modelName);
                    GameObject modelGame= PrefabUtility.InstantiatePrefab(model) as GameObject;
                    PrefabUtility.SaveAsPrefabAsset(modelGame,Application.dataPath+"/Resources/"+modelName+".prefab");
                    //這裡要注意,只能是相對路徑,完整路徑不行(即通過Application.dataPath不行)
                    AssetImporter importer = AssetImporter.GetAtPath("Assets/Resources/"+modelName+ ".prefab");
                    //設定包名,字尾名
                    importer.assetBundleName = modelName;
                    importer.assetBundleVariant = "zxy";
                    DestroyImmediate(modelGame);
                }
            }
        }
        //打包
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        DeleteResources();
    }

打包完成之後我們再將Resources目錄清空一下就完成了

    public static void DeleteResources()
    {
        //清理Resources目錄
        DirectoryInfo info = new DirectoryInfo(Application.dataPath + "/Resources");
        info.Delete(true);
        AssetDatabase.Refresh();
    }

執行到這裡,我們的AB包也就全部打包完成了。

用這個功能時需要注意的是,資原始檔的路徑格式一定要正確,FBX檔案以及它所附帶的圖片資源一定要放到同一個資料夾下,然後再將此資料夾包裹到一個外層資料夾才行,當然,這個外層資料夾下可以有多個包含FBX檔案以及圖片的資料夾,反正都會一起打包的!
當然你也可以對我的指令碼進行更改,那樣你就可以隨便怎麼做了。

接下來讓我們再寫一個玩意,讓這個功能可以變得更簡單!
首先直接在桌面新建一個txt文字檔案,然後再將其字尾名更改為".bat"(三巨頭?),右鍵選擇編輯,寫入一下內容:

rem 我的打包工具
@echo off
echo 啟動 Unity.exe 請稍後…
echo 開始操作
“F:\Unity\2019.4.15f1c1\Editor\Unity.exe” -batchmode -projectPath G:\NewTest -executeMethod MyCreateAB.CreateAB
echo 操作完成,按任意鍵退出…
Pause
taskkill /f /im unity.exe

這裡你需要更改兩處
第一個是 “F:\Unity\2019.4.15f1c1\Editor\Unity.exe” ,這個是你所使用的Unity版本的源程式路徑(右鍵>屬性可檢視)
第二個是 “G:\NewTest” ,這個是你的工程路徑
至於最後的 MyCreateAB.CreateAB 都話,只要你跟我寫的一樣就沒問題,其實就是 名稱空間.方法名。。。
寫好之後直接雙擊看看有什麼效果吧!
最後的最後,貌似版本過低時無法使用這個功能。。。

附上完整指令碼

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
//一鍵將多個FBX檔案打成AB包
public class MyCreateAB :EditorWindow
{
    //編輯器擴充套件
    [MenuItem("My Tools/CreateAB")]
    public static void CreateAB()
    {
        GetWindow<MyCreateAB>(true, "打包工具");
    }
    string filePath;
    private void OnGUI()
    {
        GUILayout.Label("資源路徑");
        filePath = GUILayout.TextField(filePath);
        if (GUILayout.Button("開始打包"))
        {
            CopyDirectory(filePath);
        }
    }
    public static void CopyDirectory(string filePath)
    {
        //將資源路徑下的檔案複製到工程Resources目錄下
        //建立Resources目錄
        if (!Directory.Exists(Application.dataPath + "/Resources"))
        {
            Directory.CreateDirectory(Application.dataPath + "/Resources");
        }
        DirectoryInfo mainInfo = new DirectoryInfo(filePath);
        DirectoryInfo[] infos= mainInfo.GetDirectories();
        for (int i = 0; i < infos.Length; i++)
        {
            //沒有資料夾便建立檔案
            if (!Directory.Exists(Application.dataPath+ "/Resources/" + infos[i].Name))
            {
                Directory.CreateDirectory(Application.dataPath + "/Resources/" + infos[i].Name);
            }
            FileInfo[] files = infos[i].GetFiles();
            for (int j = 0; j < files.Length; j++)
            {
                //沒有檔案就複製過來
                if (!File.Exists(Application.dataPath + "/Resources/" + infos[i].Name + "/" + files[j].Name))
                {
                    File.Copy(filePath + "/" + infos[i].Name + "/" + files[j].Name, Application.dataPath + "/Resources/" + infos[i].Name + "/" + files[j].Name);
                }
            }
        }
        //這裡需要重新整理一下
        AssetDatabase.Refresh();
        //複製完成
        BuildAB();
    }
    public static void BuildAB()
    {
        //開始打包,先把streamingAssetsPath目錄建立出來
        if (!Directory.Exists(Application.streamingAssetsPath))
        {
            Directory.CreateDirectory(Application.streamingAssetsPath);
        }
        DirectoryInfo info = new DirectoryInfo(Application.dataPath + "/Resources");
        DirectoryInfo[] infos = info.GetDirectories();
        for (int i = 0; i < infos.Length; i++)
        {
            FileInfo[] fileInfos= infos[i].GetFiles();
            for (int j = 0; j < fileInfos.Length; j++)
            {
                //遍歷每個資料夾下的檔案,如果是FBX檔案,就通過編輯器例項化出來再生成預製體
                if (fileInfos[j].Extension == ".FBX")
                {
                    string modelName= fileInfos[j].Name.Replace(".FBX", "");
                    GameObject model = Resources.Load<GameObject>(infos[i].Name+"/"+modelName);
                    GameObject modelGame= PrefabUtility.InstantiatePrefab(model) as GameObject;
                    PrefabUtility.SaveAsPrefabAsset(modelGame,Application.dataPath+"/Resources/"+modelName+".prefab");
                    //這裡要注意,只能是相對路徑,完整路徑不行(即通過Application.dataPath不行)
                    AssetImporter importer = AssetImporter.GetAtPath("Assets/Resources/"+modelName+ ".prefab");
                    //設定包名,字尾名
                    importer.assetBundleName = modelName;
                    importer.assetBundleVariant = "zxy";
                    DestroyImmediate(modelGame);
                }
            }
        }
        //打包
        BuildPipeline.BuildAssetBundles(Application.streamingAssetsPath, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows);
        DeleteResources();
    }
    public static void DeleteResources()
    {
        //清理Resources目錄
        DirectoryInfo info = new DirectoryInfo(Application.dataPath + "/Resources");
        info.Delete(true);
        AssetDatabase.Refresh();
    }
}

相關文章