推薦閱讀
CSDN主頁
GitHub開源地址
Unity3D插件分享
簡書地址
我的個人博客
QQ群:1040082875
一、前言
有小伙伴跟我說,公司現在需要解析JSON,但是百度的解析JSON的又各種各樣,我都看懵了,有沒有好一點的解析方案,然后我就將我這篇文章推送給了他【Unity3D日常】Unity寫Json數據,以及在Unity讀取、解析Json數據。
過了一晚上,又跟我說,不行啊,雖然只要解析JSON了,但是步驟還是不太理解,怎么保存值呀,怎么賦值呀,都不會。
我說,那你把文檔發給我,把需求跟我說一下,我整理一篇文章,讓小伙們下次遇到這個問題知道總體流程了。
二、需求分析
需求
要從文檔中讀取所有的地鐵線路和每條線路的站點,然后可以點擊不同的線路切換顯示不同的站點。
流程步驟
數據文檔→讀取數據→解析數據→保存數據
分析
(1)要有線路和站點的對應關系數據文檔,這個已經有了:
(2)讀取數據
讀取數據沒啥好說的,無論是json文件還是xml文件還是txt文件
使用File FileStream SteamReader StreamWriter 讀取文件 都可以
每種寫法都能百度出來
(3)解析數據
解析數據,方式也很多,以JSON為類,可以使用插件,也可以使用Unity自帶的JSON解析類
插件:LitJSON解析、Newtonsoft.Json.dll
Unity自帶解析JSON的類:JsonUtility
用那個都可以。
如果是txt數據,那么就要分析每一行的數據,如何切分,然后進行保存,比如:
1 1號線 103 蘋果園 1 1號線 104 古城 1 1號線 105 八角游樂園 1 1號線 106 八寶山 1 1號線 107 玉泉路 1 1號線 108 五棵松 1 1號線 109 萬壽路 1 1號線 110 公主墳 1 1號線 111 軍事博物館 1 1號線 112 木樨地 1 1號線 113 南禮士路
這段數據,最后是\r\n表示跳到下一行,中間以空格切分也就是\t
那么就可以先用\r\n切分每一行,然后用\t切換每一列,這樣就將數據分析出來了。
(4)保存數據
最后一步,是保存,JSON解析完之后,需要保存到特定的跟JSON解析后匹配的類中,比如:
{ "name":"小明", "age":20, "interests":["sing","run"] }
那么,解析的類也要有這幾個值,而且要一一對應,不能有錯,包括字母大小寫:
[System.Serializable] public class ModelTest { public string name; public int age; public string[] interests; }
那么,接收到的JSON數據怕生成類的時候出錯怎么辦,這時候就可以使用JSON數據轉實體的功能:
https://www.json.cn/json/json2csharp.html
一鍵生成實體類,媽媽再也不用擔心我出錯了。
然后,用這個實體去接收解析好的JSON數據就可以了:
ModelTest obj = JsonUtility.FromJson(jsonTest);
jsonTest是JSON數據,ModelTest就是跟JSON數據匹配的實體。
那如果是txt一行一行讀取的數據呢,比如:
1 1號線 103 蘋果園 1 1號線 104 古城 1 1號線 105 八角游樂園 1 1號線 106 八寶山 1 1號線 107 玉泉路 1 1號線 108 五棵松 1 1號線 109 萬壽路 1 1號線 110 公主墳 1 1號線 111 軍事博物館 1 1號線 112 木樨地 1 1號線 113 南禮士路
這個,就需要分析結構,然后使用數組或者List或者字典去保存了。
這個是一條地鐵線,包含多個站點,每個站點有多個屬性,可以使用自定義類,然后使用List去接收這個數據,比如:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ReadData : MonoBehaviour { List Stations; void Start() { } } public struct StationInfo { public int lineid; //線路編號 public string linename; //線路名稱 public string stationid; //車站編號 public string stationname; //車站名稱 }
三、實現
3-1 讀取數據
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; public class ReadData : MonoBehaviour { List Stations; string Content; void Start() { //讀取數據 ReadFileData(); } void ReadFileData() { string pathstations = Application.streamingAssetsPath + "/Stations_2018.txt"; using (StreamReader SR = new StreamReader(pathstations)) { //將所有的數據從文件以流形式保存到 Content Content = SR.ReadToEnd(); SR.Close(); SR.Dispose(); } } } public struct StationInfo { public int lineid; //線路編號 public string linename; //線路名稱 public string stationid; //車站編號 public string stationname; //車站名稱 }
3-2 解析數據
//解析數據 List ParseStations() { if (!string.IsNullOrEmpty(Content)) { List info = new List(); string[] strarray = Content.Split(new char[] { '\r', '\n' }, System.StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < strarray.Length; i++) { string[] Columns = strarray[i].Split(new char[] { '\t' }, System.StringSplitOptions.RemoveEmptyEntries); StationInfo stationInfo = new StationInfo(); stationInfo.lineid = int.Parse(Columns[0]); stationInfo.linename = Columns[1]; stationInfo.stationid = Columns[2]; stationInfo.stationname = Columns[3]; info.Add(stationInfo); } return info; } return null; }
3-3 保存數據
//保存數據 Stations = ParseStations();//線路編號 線路名稱 車站編號 車站名稱
完整代碼:
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; public class ReadData : MonoBehaviour { List Stations; string Content; void Start() { //讀取數據 ReadFileData(); } void ReadFileData() { string pathstations = Application.streamingAssetsPath + "/Stations_2018.txt"; using (StreamReader SR = new StreamReader(pathstations)) { //將所有的數據從文件以流形式保存到 Content Content = SR.ReadToEnd(); SR.Close(); SR.Dispose(); //保存數據 Stations = ParseStations();//線路編號 線路名稱 車站編號 車站名稱 } } //解析數據 List ParseStations() { if (!string.IsNullOrEmpty(Content)) { List info = new List(); string[] strarray = Content.Split(new char[] { '\r', '\n' }, System.StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < strarray.Length; i++) { string[] Columns = strarray[i].Split(new char[] { '\t' }, System.StringSplitOptions.RemoveEmptyEntries); StationInfo stationInfo = new StationInfo(); stationInfo.lineid = int.Parse(Columns[0]); stationInfo.linename = Columns[1]; stationInfo.stationid = Columns[2]; stationInfo.stationname = Columns[3]; info.Add(stationInfo); } return info; } return null; } } public struct StationInfo { public int lineid; //線路編號 public string linename; //線路名稱 public string stationid; //車站編號 public string stationname; //車站名稱 }
3-4 生成地鐵線
先擺個UI:
將這兩個按鈕分別做成預制體,命名為MetroLinePar、MetroSitePar,放到Resources文件夾下面:
編寫代碼:
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.UI; public class ReadData : MonoBehaviour { List Stations; string Content; public GameObject MetroLinePanel; private GameObject MetroLinePar; public GameObject MetroSitePanel; private GameObject MetroSitePar; void Start() { //讀取數據 ReadFileData(); MetroLinePar = Resources.Load("MetroLinePar"); MetroLinePar = Resources.Load("MetroSitePar"); //生成UI CreateUI(); } void CreateUI() { //找出所有地鐵線 Dictionary MetroLine = new Dictionary(); for (int i = 0; i < Stations.Count; i++) { if (!MetroLine.ContainsKey(Stations[i].lineid)) { MetroLine.Add(Stations[i].lineid, Stations[i].linename); } } //生成地鐵線 foreach (var item in MetroLine) { GameObject MetroLineItem = Instantiate(MetroLinePar, Vector3.zero, Quaternion.identity, MetroLinePanel.transform); MetroLineItem.GetComponentInChildren().text = item.Value; } } void ReadFileData() { string pathstations = Application.streamingAssetsPath + "/Stations_2018.txt"; using (StreamReader SR = new StreamReader(pathstations)) { //將所有的數據從文件以流形式保存到 Content Content = SR.ReadToEnd(); SR.Close(); SR.Dispose(); //保存數據 Stations = ParseStations();//線路編號 線路名稱 車站編號 車站名稱 } } //解析數據 List ParseStations() { if (!string.IsNullOrEmpty(Content)) { List info = new List(); string[] strarray = Content.Split(new char[] { '\r', '\n' }, System.StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < strarray.Length; i++) { string[] Columns = strarray[i].Split(new char[] { '\t' }, System.StringSplitOptions.RemoveEmptyEntries); StationInfo stationInfo = new StationInfo(); stationInfo.lineid = int.Parse(Columns[0]); stationInfo.linename = Columns[1]; stationInfo.stationid = Columns[2]; stationInfo.stationname = Columns[3]; info.Add(stationInfo); } return info; } return null; } } public struct StationInfo { public int lineid; //線路編號 public string linename; //線路名稱 public string stationid; //車站編號 public string stationname; //車站名稱 }
運行:
所有的地鐵線有,下面就需要將每條地鐵線的每個站點對應起來。
3-5 生成站點
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; using UnityEngine.UI; public class ReadData : MonoBehaviour { List Stations; string Content; public GameObject MetroLinePanel; private GameObject MetroLinePar; public GameObject MetroSitePanel; private GameObject MetroSitePar; void Start() { //讀取數據 ReadFileData(); MetroLinePar = Resources.Load("MetroLinePar"); MetroSitePar = Resources.Load("MetroSitePar"); //生成UI CreateMetroLine(); } void CreateMetroLine() { //找出所有地鐵線 Dictionary MetroLine = new Dictionary(); for (int i = 0; i < Stations.Count; i++) { if (!MetroLine.ContainsKey(Stations[i].lineid)) { MetroLine.Add(Stations[i].lineid, Stations[i].linename); } } //生成地鐵線 foreach (var item in MetroLine) { GameObject MetroLineItem = Instantiate(MetroLinePar, Vector3.zero, Quaternion.identity, MetroLinePanel.transform); MetroLineItem.GetComponentInChildren().text = item.Value; //生成站點 MetroLineItem.GetComponent().onClick.AddListener(()=> CreateMetroSite(item.Key)); } } void CreateMetroSite(int _MetroLine) { //找到傳遞過來的地鐵線包含的所有站點 List MetroSite = new List(); for (int i = 0; i < Stations.Count; i++) { if (Stations[i].lineid == _MetroLine) { MetroSite.Add(Stations[i]); } } //清理原來的站點 foreach (Transform transform in MetroSitePanel.transform) { Destroy(transform.gameObject); } //生成站點 foreach (var item in MetroSite) { GameObject MetroLineSiteItem = Instantiate(MetroSitePar, Vector3.zero, Quaternion.identity, MetroSitePanel.transform); MetroLineSiteItem.GetComponentInChildren().text = item.stationname; } } void ReadFileData() { string pathstations = Application.streamingAssetsPath + "/Stations_2018.txt"; using (StreamReader SR = new StreamReader(pathstations)) { //將所有的數據從文件以流形式保存到 Content Content = SR.ReadToEnd(); SR.Close(); SR.Dispose(); //保存數據 Stations = ParseStations();//線路編號 線路名稱 車站編號 車站名稱 } } //解析數據 List ParseStations() { if (!string.IsNullOrEmpty(Content)) { List info = new List(); string[] strarray = Content.Split(new char[] { '\r', '\n' }, System.StringSplitOptions.RemoveEmptyEntries); for (int i = 1; i < strarray.Length; i++) { string[] Columns = strarray[i].Split(new char[] { '\t' }, System.StringSplitOptions.RemoveEmptyEntries); StationInfo stationInfo = new StationInfo(); stationInfo.lineid = int.Parse(Columns[0]); stationInfo.linename = Columns[1]; stationInfo.stationid = Columns[2]; stationInfo.stationname = Columns[3]; info.Add(stationInfo); } return info; } return null; } } public struct StationInfo { public int lineid; //線路編號 public string linename; //線路名稱 public string stationid; //車站編號 public string stationname; //車站名稱 }
效果如圖:
有兩個小問題:
1)1號線顯示兩次,這是因為場景中的預制體沒有隱藏
2)在生成的時候,讓程序默認顯示1號線的站點,這樣合理一些。
void Start() { //讀取數據 ReadFileData(); MetroLinePar = Resources.Load("MetroLinePar"); MetroSitePar = Resources.Load("MetroSitePar"); //生成UI CreateMetroLine(); //默認生成一號線的站點 CreateMetroSite(1); }
效果圖:
好,結束了。
四、后言
這個數據讀取顯示的整個步驟就完成了,萬變不離其宗:
數據文檔→讀取數據→解析數據→保存數據→使用數據
明白了這幾個步驟,剩下的難點就在于分析結構,然后如何保存數據,才能讓自己去使用數據的時候方便一些。
比如,我想要保存所有的地鐵線和地鐵線的信息,那么就可以新建一個自定義類跟數據對應,然后使用List去保存數據,這樣在后面的生成地鐵線和地鐵站點的時候就方便了許多。
這個實例演示的是如何從txt中讀取數據,但是其他比如JSON、XML也是適用的,只是解析數據、保存數據的時候略微有些差別。
還有一點,就是List、字典、Resources、 StreamingAssets、Instantiate實例化,這些基本知識的運行要熟練。 `
Git unity
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。