前言
在游戲制作中,我們的許多數(shù)據(jù)都是需要從文件里面讀取麸塞,比如常用的裝備數(shù)據(jù)秃臣,怪物數(shù)據(jù),關卡數(shù)據(jù)等等哪工,所以如何從文件中讀取這些數(shù)據(jù)就變得尤為重要奥此,因為將游戲數(shù)據(jù)放入文件中弧哎,會大大提高我們制作和調(diào)整游戲的效率,所以本例中我們來看看Unity中如何通過CSV文件來讀取游戲數(shù)據(jù)
你將學到什么得院?
- 使用Numbers制作CSV數(shù)據(jù)文件
- Unity基礎的文件讀取
- 通過行數(shù)和列數(shù)獲得指定的數(shù)據(jù)
一傻铣、制作CSV文件
一般情況下章贞,制作游戲數(shù)據(jù)會用到表格軟件祥绞,windows下常用Excel,而Mac下常用Numbers鸭限,而這兩種軟件都可以導出我們本例所需要的文件——CSV文件
首先我們打開Numbers蜕径,新建一個文件
然后輸入我們需要的內(nèi)容,如下:
這就簡單的制作了一個裝備數(shù)據(jù)表败京,每件裝備我們假設它有5個屬性:
- id:裝備ID兜喻,具有唯一性
- name:裝備的名字
- level:裝備等級
- attack:裝備增加的攻擊
- def:裝備增加的防御
數(shù)據(jù)填寫完之后,我們就可以選擇文件->導出到->CSV…
然后在彈出的對話框赡麦,直接點擊下一步:
然后在接下來的對話框中朴皆,選擇文件名和保存路徑:
導出后,我們找到myTest.csv文件泛粹,打開可以看到:
我們可以看到我們剛剛制作的表格數(shù)據(jù)都被以文本的方式保存下來了遂铡,并且使用了“,”號來進行分割,而CSV的中文翻譯就是逗號分隔值晶姊。但是我們會發(fā)現(xiàn)一個問題扒接,為什么后面會多了那么多逗號呢?那是因為我們導出的時候沒有將空的單元格刪除掉
所以我們導出CSV文件是们衙,記得要刪除掉那些空的單元格钾怔,如下圖:
然后我們再導出一次,并打開導出的文件查看蒙挑,就會發(fā)現(xiàn)那些多與的逗號沒有了
二宗侦、讀取CSV文件
有了CSV文件后,下一步就是將它放入Unity中忆蚀,并讓Unity讀取里面的數(shù)據(jù)矾利,首先我們新建一個Unity工程,然后將我們剛剛創(chuàng)建的CSV文件放入Unity的資源目錄下蜓谋,本例中我們選擇放入在*Asset->Res文件夾下面(Res文件夾需要大家自己創(chuàng)建)
然后我們新建一個名為CSV的腳本梦皮,打開進行編輯,輸入一下代碼:
- 首先桃焕,如果我們要使用Unity的讀取文件的方法剑肯,需要在開頭引入System.IO的命名空間,這樣編輯器才會識別讀取文件的一些方法
- 然后我們還需要使用List<T>類型的變量观堂,所以還要引入System.Collections.Generic的命名空間
- 然后這個CSV類是我們自己定義的一個靜態(tài)類让网,不需要繼承MonoBehaviour類呀忧,所以我們把繼承MonoBehaviour類的語句刪除掉
- 接著我們定義了csv和m_ArrayData兩個成員變量,第一個用來實現(xiàn)單例模式溃睹,第二個用來保存從文件讀取的內(nèi)容
- 然后使用單例模式來生產(chǎn)這個類的實例而账,以后需要使用這個類的方法我們就通過GetInstance來獲取這個類的實例
- 接著我們在構造函數(shù)CSV()中,初始化m_ArrayData
- 然后我們定義了loadFile方法因篇,有兩個參數(shù)泞辐,第一個是路徑名,第二個是文件名竞滓,通過路徑名+文件名我們就可以指定我需要讀取的文件了
- 接著看看loadFile這個方法里面到底做了什么事情咐吼?首先每次讀取文件前,我們清空一下m_ArrayData商佑,以免數(shù)據(jù)沖突
- 然后我們定義了一個StreamReader類型的變量sr锯茄,用他來保存文件讀取后的最原始的數(shù)據(jù)
- 然后我們使用try{} catch{}語句,來捕獲程序異常茶没,這個邏輯和if語句有點想肌幽,如果我們文件讀取不成功,就會運行catch里面的語句抓半,在后他打印一句話來通知我文件沒有找到喂急,在try{}里面使用OpenText方法來打開我們的myTest.csv文件
- 接著我們定義了一個line,用來臨時保存sr里面的每一行數(shù)據(jù)
- 然后使用一個while循環(huán)琅关,把sr里面的數(shù)據(jù)按照一行來切割煮岁,全部放入m_ArrayData中
- 最后使用close和Dispose函數(shù)將sr進行關閉和銷毀
寫完代碼,保存一下涣易,然后我們在創(chuàng)建中新建一個空的GameObject画机,命名為FileController,并且為掛載一個新的腳本文件FileController新症,用來控制文件的讀取步氏。
然后打開FileController腳本,輸入下面的代碼:
- 首先我們在Start函數(shù)中徒爹,通過CSV的實例調(diào)用loadFile方法來讀取我們的myTest里面的內(nèi)容荚醒,loadFile方法有兩個參數(shù),一個是路徑名隆嗅,一個是文件名稱界阁,關于路徑名的一些注意事項,會在后面的擴展閱讀里面介紹胖喳,這里只要理解我們通過路徑名+文件名就可以指定需要讀取的文件了
- 然后我通過for循環(huán)泡躯,將m_ArrayData里所有的內(nèi)容打印在程序后臺中
寫完代碼,保存一下,然后回到Unity編輯器较剃,運行游戲咕别,可以在后臺打印中看到如下數(shù)據(jù):
可以看到,現(xiàn)在我們已經(jīng)可以讀取到文件里面的內(nèi)容了写穴,并且是可以分解每一行的內(nèi)容分別是什么惰拱,但是這樣的解析程度還遠遠不夠,不能為我們所用啊送,假設我們游戲中需要生成一件裝備布衣偿短,我們需要通過文件獲得布衣的每一個屬性,如布衣的等級删掀,增加的防御值等屬性翔冀,我們就需要將每一個數(shù)據(jù)單獨提取出來导街,所以我們需要可以指定獲得某一個單元格里面的數(shù)據(jù)才行披泪,下面就來看看怎么實現(xiàn)
三、根據(jù)行數(shù)和列數(shù)來指定獲取數(shù)據(jù)
現(xiàn)在我們的m_ArrayData里面存放的是一行的數(shù)據(jù)搬瑰,也就是說其實m_ArrayData[0]就是取我們第一行的數(shù)據(jù)款票,m_ArrayData[1]就是取我們第二行的數(shù)據(jù),那么接下來我們只需要再進行一下解析泽论,將每一行的數(shù)據(jù)按照列數(shù)來拆解艾少,這樣我們就可以通過行數(shù)+列數(shù)來確定指定數(shù)據(jù)了,先直接上代碼:
- 由于這次我們需要將每一行的數(shù)據(jù)按照列數(shù)來拆解翼悴,那么m_ArrayData里面裝的元素就不再是string了缚够,而是一個string數(shù)值,所以我們這邊需要修改m_ArrayData的類型為List<string[]>
- 然后我們新增一個方法getString鹦赎,它有兩個參數(shù)谍椅,row是行數(shù),col是列數(shù)古话,方法返回指定行數(shù)和列數(shù)的數(shù)據(jù)雏吭,數(shù)據(jù)類型是string
- 同時我們還增加一個方法getInt,它也有兩個參數(shù)陪踩,row是行數(shù)杖们,col是列數(shù),方法返回指定行數(shù)和列數(shù)的數(shù)據(jù)肩狂,數(shù)據(jù)類型是int摘完,所以最后調(diào)用了int.Parse方法將string轉(zhuǎn)換成int類型
- 最后我們修改while循環(huán)中的講數(shù)據(jù)添加到m_ArrayData的語句,這里我們調(diào)用Split方法傻谁,將數(shù)據(jù)以 “,” 作為分隔符孝治,切割數(shù)據(jù)
寫完代碼,保存一下,然后我打開FileController腳本荆秦,修改代碼如下:
- 首先讀取文件的語句和之前一樣
- 接著我們調(diào)用getString方法打印行數(shù)為1篱竭,列數(shù)為1的數(shù)據(jù)
- 最后我們調(diào)用getInt方法打印行數(shù)為1,列數(shù)2的數(shù)據(jù)
寫完代碼步绸,保存一下掺逼,大家可以先思考一下,上面打印的兩個數(shù)據(jù)分別是上面內(nèi)容瓤介,然后在運行游戲吕喘,檢查一下實際結果是否和你想象的一樣
擴展閱讀
前面我們提到過,關于文件路徑的存放位置刑桑,在本例中我們使用了Application.dataPath來指定路徑位置僚楞,關于路徑有4個類型:
- Application.dataPath:該路徑指向我們Unity編輯器的Asset文件夾
- Application.persistentDataPath:該路徑指向iOS和Android的沙盒路徑
- Application.streamingAssetsPath:streamingAsset文件夾路徑,在任何平臺都可以通過這個路徑讀取到文件夾里的內(nèi)容
- Application.temporaryCachePath:臨時數(shù)據(jù)文件路徑
關于這4種路徑的詳細地址景东,大家可以試著在Unity里面用Debug.Log語句將其打印出來邻梆,看到完整的路徑會便于理解