實際的遊戲開發中,其實有至關一部分靜態數據是能夠放在客戶端的,因此勢必會產生要動態讀取這些文件的需求,好比csv(其實就是文本文件),xml等等。我相信你們不論是用win仍是用mac來作unity3d的開發,都必定要先在editor中去實現基本的功能,在具體到各個移動平臺上去調試。因此做爲要讀取外部文件的第一步,顯然咱們要先在editor也就是pc上實現這個功能。html
下面給各位舉一個讀取xml的例子,也是我在之前的一篇文章《本身動手之使用反射和泛型,動態讀取XML建立類實例並賦值》中使用過的,動態讀取一個xml文件並動態生成一個類。android
下面是咱們用來作例子的xml文件,Test.xml:緩存
<?xml version="1.0" encoding="UTF-8"?> <test> <name>chenjd</name> <blog>http://www.cnblogs.com/murongxiaopifu/</blog> <organization>Fanyoy</organization> <age>25</age> </test>
咱們就能夠很任性的把這個文件隨便丟在一個地方,只要你能指定對它的地址。例如我還把它放在那篇文章中的地址Assets/xml-to-egg/xml-to-egg-test/文件夾下(的確很任性)app
下面咱們實如今PC上讀取這個文件內容的代碼:post
//讀取xml測試 using UnityEngine; using System.Collections; using EggToolkit; using System.Xml.Linq; public class Test : MonoBehaviour { // Use this for initialization void Start () { XElement result = LoadXML("Assets/xml-to-egg/xml-to-egg-test/Test.xml");//任性的地址 Debug.Log(result.ToString()); } // Update is called once per frame void Update () { } private XElement LoadXML(string path) { XElement xml = XElement.Load(path); return xml; } }
結果以下:測試
結果是讀取成功了。可是你覺得到這一步就成功了,那就錯了。由於這樣的代碼到移動端是行不通的,至少2處能夠被罵sb:ui
以上用紅色標出的問題,即是小匹夫想到的可能出現的問題,也是下文要討論的內容。那麼咱們首先來看看資源路徑在各個平臺上的不一樣之處吧。this
想要讀取一個文件,天然首先要找到這個文件,下面小匹夫首先會總結一下unity3d中存在的各個地址,以後再總結一下各個地址在各個移動平臺中的對應位置。加密
Application.dataPath | 此屬性用於返回程序的數據文件所在文件夾的路徑。例如在Editor中就是Assets了。 |
Application.streamingAssetsPath | 此屬性用於返回流數據的緩存目錄,返回路徑爲相對路徑,適合設置一些外部數據文件的路徑。 |
Application.persistentDataPath | 此屬性用於返回一個持久化數據存儲目錄的路徑,能夠在此路徑下存儲一些持久化的數據文件。 |
Application.temporaryCachePath | 此屬性用於返回一個臨時數據的緩存目錄。 |
Application.dataPath | /data/app/xxx.xxx.xxx.apk |
Application.streamingAssetsPath | jar:file:///data/app/xxx.xxx.xxx.apk/!/assets |
Application.persistentDataPath | /data/data/xxx.xxx.xxx/files |
Application.temporaryCachePath | /data/data/xxx.xxx.xxx/cache |
Application.dataPath | Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data |
Application.streamingAssetsPath | Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw |
Application.persistentDataPath | Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents |
Application.temporaryCachePath | Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches |
從上面的3張表格,咱們能夠看到 dataPath和streamingAssetsPath的路徑位置通常是相對程序的安裝目錄位置,而persistentDataPath和temporaryCachePath的路徑位置通常是相對所在系統的固定位置。那麼如今明確了unity3d中各個地址在不一樣平臺上的含義,下一個問題就來了,也就是我打包以後的資源要怎麼和這些地址對應上呢?要知道在pc的editor裏默認的資源文件存放的路徑就是Assets啊,爲什麼又會派生出那麼多路徑呢?那麼就帶着這個疑問,和小匹夫一塊兒進行下文的內容吧。url
小匹夫遇到過的大致就是以下幾種了,Resources、StreamingAssets、AssetBundle、PersistentDataPath,下面簡單分析一下。
是做爲一個Unity3D的保留文件夾出現的,也就是若是你新建的文件夾的名字叫Resources,那麼裏面的內容在打包時都會被無條件的打到發佈包中。它的特色簡單總結一下就是:
要說到StreamingAssets,其實和Resources仍是蠻像的。一樣做爲一個只讀的Unity3D的保留文件夾出現。不過二者也有很大的區別,那就是Resources文件夾中的內容在打包時會被壓縮和加密。而StreamingAsset文件夾中的內容則會原封不動的打入包中,所以StreamingAssets主要用來存放一些二進制文件。下面也一樣作一個簡單的總結:
關於AssetBundle的介紹已經有不少了。簡而言之就是把prefab或者二進制文件封裝成AssetBundle文件(也是一種二進制)。可是也有硬傷,就是在移動端沒法更新腳本。下面簡單的總結下:
看上去它只是個路徑呀,可爲何要把它從路徑裏面單獨拿出來介紹呢?由於它的確蠻特殊的,這個路徑下是可讀寫。並且在IOS上就是應用程序的沙盒,可是在Android能夠是程序的沙盒,也能夠是sdcard。而且在Android打包的時候,ProjectSetting頁面有一個選項Write Access,能夠設置它的路徑是沙盒仍是sdcard。下面一樣簡單的總結一下:
好啦,小匹夫介紹到這裏,各位看官們是否是也都清楚了一些呢?那麼下面咱們就開始最後一步了,也就是如何在移動平臺如何讀取外部文件。
上文小匹夫之因此要介紹Resources、StreamingAssets、AssetBundle、PersistentDataPath這四個東東,就是由於讀取外部資源的操做所涉及到的東西無外乎這幾種。既然是用Unity3D來開發遊戲,那麼天然要使用Unity3D規定的操做方式,而不是咱們在PC上很原始的那種操做方式來操做咯。不然就會像本文一開始所演示的那樣,寫出移動端沒法使用的很傻的代碼來。
下面小匹夫就分別實現一下利用Resources、StreamingAssets、AssetBundle來讀取的過程。
首先咱們新建一個Resources目錄,而且將上面咱們用到的Test.xml複製一份到這個文件夾中。如圖:
而後咱們經過Resources的讀取方法來讀取Test.xml的內容。而且調用GUI將xml的內容繪製出來。
//用Resources讀取xml using UnityEngine; using System.Collections; using EggToolkit; using System.Xml.Linq; using System.Xml; public class Test : MonoBehaviour { private string _result; // Use this for initialization void Start () { LoadXML("Test"); } // Update is called once per frame void Update () { } private void LoadXML(string path) { _result = Resources.Load(path).ToString(); XmlDocument doc = new XmlDocument(); doc.LoadXml(_result); } void OnGUI() { GUIStyle titleStyle = new GUIStyle(); titleStyle.fontSize = 20; titleStyle.normal.textColor = new Color(46f/256f, 163f/256f, 256f/256f, 256f/256f); GUI.Label(new Rect(400, 10, 500, 200), _result,titleStyle); } }
結果如圖:
OK,Resources讀取外部資源目標達成!!
下面咱們繼續,此次則是使用StreamingAssets來操做。
同Resources同樣,咱們要新建一個StreamingAssets的文件夾來存放咱們的Test.xml文件。如圖:
不過前文已經說了,StreamingAssets文件夾內的東西並不會被壓縮和加密,而是放進去什麼就是什麼,因此通常是要放二進制文件的,這裏小匹夫僅僅作一個演示,各位在實際操做中切記不要直接把數據文件放到這個目錄中打包。
using UnityEngine; using System.Collections; using EggToolkit; using System.Xml.Linq; using System.Xml; using System.IO; public class Test : MonoBehaviour { private string _result; // Use this for initialization void Start () { StartCoroutine(LoadXML()); } // Update is called once per frame void Update () { } /// <summary> /// 如前文所述,streamingAssets只能使用www來讀取, /// 若是不是使用www來讀取的同窗,就不要問爲啥讀不到streamingAssets下的內容了。 /// 這裏還可使用persistenDataPath來保存從streamingassets那裏讀到內容。 /// </summary> IEnumerator LoadXML() { string sPath= Application.streamingAssetsPath + "/Test.xml"; WWW www = new WWW(sPath); yield return www; _result = www.text; } void OnGUI() { GUIStyle titleStyle = new GUIStyle(); titleStyle.fontSize = 20; titleStyle.normal.textColor = new Color(46f/256f, 163f/256f, 256f/256f, 256f/256f); GUI.Label(new Rect(400, 10, 500, 200), _result,titleStyle); } }
結果如圖:
OK,StreamingAssets讀取外部資源目標達成!!
下面咱們繼續,最後則是使用AssetBundle來操做。
來到AssetBundle,這裏就和上面兩個不同了。首先咱們要把咱們的文件Test.xml打成AssetBundle文件,因爲小匹夫使用的是小米3做爲測試機,因此AssetBundle的平臺選擇爲Andorid。
如圖,咱們建立了一個AssetBundle文件,並命名爲TextXML。而且按照二進制文件放入StreamingAssets文件夾中的慣例,將這個AssetBundle文件放入StreamingAssets文件夾。
那麼下面就是從AssetBudle中讀取Test.xml的內容咯。直接上代碼:
//從AssetBundle中讀取xml using EggToolkit; using System.Xml.Linq; using System.Xml; using System.IO; public class Test : MonoBehaviour { private string _result; // Use this for initialization void Start () { LoadXML(); } // Update is called once per frame void Update () { } void LoadXML() { AssetBundle AssetBundleCsv = new AssetBundle(); //讀取放入StreamingAssets文件夾中的bundle文件 string str = Application.streamingAssetsPath + "/" + "TestXML.bundle"; WWW www = new WWW(str); www = WWW.LoadFromCacheOrDownload(str, 0); AssetBundleCsv = www.assetBundle; string path = "Test"; TextAsset test = AssetBundleCsv.Load(path, typeof(TextAsset)) as TextAsset; _result = test.ToString(); } void OnGUI() { GUIStyle titleStyle = new GUIStyle(); titleStyle.fontSize = 20; titleStyle.normal.textColor = new Color(46f/256f, 163f/256f, 256f/256f, 256f/256f); GUI.Label(new Rect(400, 10, 500, 200), _result,titleStyle); } }
結果如圖:
OK,AssetBundle讀取外部資源目標也達成了!!
在此統一回答一下在評論和qq上有同窗提出的一個問題:安卓上Application.persistentDataPath的內容貌似不是匹夫你表裏的那個呀?在本文的評論裏小匹夫已經回覆過了,其實文中也說過
可是在Android能夠是程序的沙盒,也能夠是sdcard。而且在Android打包的時候,ProjectSetting頁面有一個選項Write Access,能夠設置它的路徑是沙盒仍是sdcard。
下面上圖好啦: