最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

用Unity還原星露谷物語(yǔ)(2):種地篇(數(shù)據(jù)讀寫+TileMap)

2020-12-25 20:38 作者:皮皮關(guān)做游戲  | 我要投稿

本文作者 :對(duì)馬騎馬使用炎拳


大家好,我是想對(duì) 使用炎拳的炎拳,上一篇星露谷中我完成了人物的移動(dòng)并搭建了一個(gè)簡(jiǎn)單的界面,這篇就來瞅瞅星露谷的地是怎么種的。

首先看看游戲中的種地的過程:

大致上完成一次耕種,需要這幾個(gè)步驟:選中鋤頭—開墾一塊地—選擇種子種下—澆水;同時(shí)種子會(huì)隨時(shí)間的流逝成長(zhǎng),長(zhǎng)到有葉片后人物走過,會(huì)觸發(fā)一個(gè)莊稼動(dòng)一下的動(dòng)畫~

所以這里我要做的功能就清晰了,先整個(gè)莊稼的預(yù)制體,其中包含所需的圖片文字素材,然后點(diǎn)擊一下土地就在那位置生成一個(gè),大功告成啦!

才怪~

考慮到星露谷的物品繁多,如果用預(yù)制體來制作每個(gè)單獨(dú)的物品,就太笨拙了;同時(shí)每個(gè)物品有自己的描述和各種屬性,對(duì)應(yīng)的Sprites也可以通過其地址實(shí)時(shí)讀取,所以我希望能通過表格來填寫這些物品的固有屬性,這些數(shù)據(jù)屬于靜態(tài)數(shù)據(jù)。

同時(shí)種子,魚,這些物品使用時(shí)會(huì)有數(shù)量的增減,而斧頭,鋤頭這些道具則可以進(jìn)行升級(jí),數(shù)量,等級(jí)這些數(shù)據(jù)屬于動(dòng)態(tài)數(shù)據(jù),經(jīng)常改變,游戲結(jié)束也需要保存下來。

所以最后我的方案是:物品的名字,描述,Sprites地址等靜態(tài)數(shù)據(jù)通過表格獲得,表格的讀取使用EPPlus插件實(shí)現(xiàn);物品的數(shù)量,等級(jí)等動(dòng)態(tài)數(shù)據(jù),以json文件的方式保存,這里我使用了LitJson來實(shí)現(xiàn)。

首先寫個(gè)物品的基礎(chǔ)類,再在表格中填上對(duì)應(yīng)的靜態(tài)數(shù)據(jù):

public class ItemInfo

{

??? //動(dòng)態(tài)數(shù)據(jù),從json中獲取

??? public int Id;

??? public int amount;

??? public ItemQuality itemQuality;

??? public bool isSelected;

?

?

??? //靜態(tài)數(shù)據(jù)

??? public string name;

??? public string description;

??? public string []icons;//表格中圖片名字的集合

??? public ItemType itemType;

??? public Tool tool;

??? public int growTime;

?

?

??? /// 構(gòu)造函數(shù)僅構(gòu)造靜態(tài)數(shù)據(jù),通過表格id獲取

??? public ItemInfo(int BaseDataid )

??? {

??????? this.name = GetBaseData.instance.baseInfo[BaseDataid].name ;

??????? this.description = GetBaseData.instance.baseInfo[BaseDataid].description;

??????? this.icons = GetBaseData.instance.baseInfo[BaseDataid].icons;

??????? this.itemType = GetBaseData.instance.baseInfo[BaseDataid].itemType;

??????? this.tool = GetBaseData.instance.baseInfo[BaseDataid].tool;

??????? this.growTime = GetBaseData.instance.baseInfo[BaseDataid].growTime ;

??? }

}

?

表格的讀取我使用EPPlus插件,使用方法很簡(jiǎn)單,網(wǎng)上找到對(duì)應(yīng)dll文件到工程,調(diào)用這兩個(gè)指令集:

using OfficeOpenXml;

using System.IO;

?

靜態(tài)數(shù)據(jù)讀?。?/p>

??? public void GetExcelData()

??? {

??????? string FilePath = Application.dataPath + "/Resources/ItemData/BaseData.xlsx";

??????? Debug.Log("路徑" + FilePath);

??????? FileInfo fileInfo = new FileInfo(FilePath);

??????? if (fileInfo.Length == 0)

??????? {

??????????? Debug.Log("Excel文件不存在");

???????? ???return;

??????? }

?

??????? using (ExcelPackage excel = new ExcelPackage(fileInfo))

??????? {

??????????? ExcelWorksheet worksheet = excel.Workbook.Worksheets[1];

?

??????????? int maxRow_Data = worksheet.Dimension.End.Row; //行

??????????? int maxColumn_Data = worksheet.Dimension.End.Column; //列

??????????? int Id = 0;

?

??????????? //從第二行開始讀取數(shù)據(jù)

??????????? for (int i = 2; i <= maxRow_Data; i++)

??????????? {

??????????????? BaseMessage info? = new BaseMessage();

??????????????? string name=null;

??????????????? for (int j = 1; j <= maxColumn_Data; j++)

??????????????? {

??????????????????? switch (j)

??????????????????? {

??????????????????????? case 1:

??????????????????????????? info.name = worksheet.Cells[i, j].Value.ToString();

??????????????????????????? Debug.Log("名字" + name);

??????????????????????????? break;

??????????????????????? case 2:

??????????????????????????? info.description = worksheet.Cells[i, j].Value.ToString();

??????????????????????????? break;

??????????? ????????????case 3:

??????????????????????????? string temp = worksheet.Cells[i, j].Value.ToString();

??????????????????????????? info.icons = temp.Split(',');

??????????????????????????? break;

??????????????????????? case 4:

??????????????????????????? string temp2 = worksheet.Cells[i, j].Value.ToString();

??????????????????????????? info.itemType = (ItemType)int.Parse(temp2);

??????????????????????????? break;

??????????????????????? case 5:

??????????????????????????? string temp5 = worksheet.Cells[i, j].Value.ToString();

??????????????????????????? info.tool = (Tool)int.Parse(temp5);

??????????????????????????? break;

??????????????????????? case 6:

??????????????????????????? string temp6 = worksheet.Cells[i, j].Value.ToString();

???????????????????? ???????info.growTime= int.Parse(temp6);

??????????????????????????? break;

??????????????????????? default:

??????????????????????????? break;

??????????????????? }

??????????????? }

??????????????? baseInfo.Add(Id , info);

??????????????? Id++;

????????? ??}

??????? }//關(guān)閉表格

??? }

?

物品的Sprite單獨(dú)寫了個(gè)方法,方便直接通過名字讀?。?/p>

??? public string SpritesPath = "Sprites";

??? private Sprite[] sprites;

??? private Dictionary<string, object> spritesDictionary = new Dictionary<string, object>();

??? // 加載所有精靈圖

??? public void LoadAllSprites()

??? {

??????? sprites = Resources.LoadAll<Sprite>(SpritesPath);

??????? if (sprites.Length == 0)

??????? {

??????????? Debug.Log("精靈圖沒讀到");

??????? }

??????? for (int i = 0; i < sprites.Length; i++)

??????? {

??????????? spritesDictionary.Add(sprites[i].name, sprites[i]);

??????? }

??? }

?

??? // 直接通過名字獲得sprite

??? public Sprite ReadSpritesByString (string name)

??? {

??????? if (name == null)

??????????? Debug.Log("名字為空不存在");

??????? Sprite a = null;

??????? foreach (KeyValuePair<string, object> pair in spritesDictionary)

??????? {

??????????? // Debug.Log(pair.Key + " " + pair.Value);

??????????? if (pair.Key.ToString() == name)

??????????? {

????????????? a = pair.Value as Sprite;

??????????? }

??????? }

??????? return a;

??? }

?

然后新建一個(gè)動(dòng)態(tài)數(shù)據(jù)類和專門存放List<動(dòng)態(tài)數(shù)據(jù)>的類,方便json讀寫:

public class DynamicData

{

??? public int jsonId;//動(dòng)態(tài)數(shù)據(jù)ID

??? public int baseId;//對(duì)應(yīng)的靜態(tài)數(shù)據(jù)ID

??? public int amount;

??? public bool isSelected;

}

?

public class DynamicList

{

??? public List<DynamicData> dyDatas=new List<DynamicData>();

}

?

LitJson的使用方法和EPPlus一樣,導(dǎo)入文件后,調(diào)用這兩個(gè)指令集:

Json數(shù)據(jù)讀寫:

??? //存儲(chǔ)背包動(dòng)態(tài)數(shù)據(jù)

??? public void SaveBagData()

??? {

??????? string json = JsonMapper.ToJson(Bagmanager.instance.dynamicList);

???????

??????? //路徑下的文件不存在就新建個(gè)

??????? if (!File.Exists(path))

??????????? File.Create(path ).Close();

???????

??????? //選擇覆蓋模式,每次寫入數(shù)據(jù)會(huì)清除上次數(shù)據(jù)

??????? using (StreamWriter sw = new StreamWriter(new FileStream(path , FileMode.Truncate)))

??????? {

??????????? sw.Write(json);

??????? }

??? }

?

??? //讀取背包數(shù)據(jù)

??? public void ReadBagData()

??? {

??????? //檢查文件是否存在

??????? if (!File.Exists(path))

??????????? return;

?

??????? using (StreamReader sr = new StreamReader(new FileStream(path, FileMode.Open)))

??????? {

??????????? string json = sr.ReadToEnd();

??????????? DynamicList tempList = new DynamicList();

??????????? tempList = JsonMapper.ToObject<DynamicList>(json);

??????????? Bagmanager.instance.dynamicList = tempList;

??????? }

??????? Bagmanager.instance.RefreshBagData();

??? }

?

完成了背包物品的動(dòng)靜態(tài)數(shù)據(jù)讀取后 ,還要讓數(shù)據(jù)到背包的UI面板上展示,這里就可以新建一個(gè)模板預(yù)制體了,同時(shí)這里再新建一個(gè)腳本負(fù)責(zé)在游戲開始時(shí),將相應(yīng)的數(shù)據(jù)填入到預(yù)制體,并在面板上生成,這里就不詳細(xì)說了:



物品系統(tǒng)和背包有個(gè)雛形了,接下來看看土地咋整,首先需要對(duì)每一塊土地單獨(dú)進(jìn)行操作,所以需要一個(gè)規(guī)律的網(wǎng)格狀的土地,這里我自然而然就想到了Tilemap(瓦片地圖)系統(tǒng),故名思意,就是用一塊一塊瓦片搭建起來的地圖,簡(jiǎn)直就是為星露谷量身而做的系統(tǒng)??!起飛!

然而實(shí)際上使用還是遇到了很多問題,開始我以為Tile類就是組成Tilemap的每個(gè)圖塊,但查看了定義才發(fā)現(xiàn)Tile本質(zhì)還是一個(gè)繼承了ScriptableObject的,類似 unity 材質(zhì)或紋理資源的文件。(使用過Tilemap的朋友知道,使用前的第一步就是在Tile palette中導(dǎo)入Sprite生成Tile文件)所以直接對(duì)單個(gè)Tile文件操作,進(jìn)而改變游戲中的圖塊是不可取的,本末倒置了。

好在Unity還是很貼心的提供了方法來對(duì)每個(gè)單元格進(jìn)行操作,你可以獲取Tilemap的每個(gè)圖塊的坐標(biāo),然后進(jìn)行Tile的更換:

這里對(duì)Tilemap不熟的朋友可能有點(diǎn)懵,你可以瞅瞅這個(gè)視頻來了解下這個(gè)功能,賊好用:

簡(jiǎn)明UNITY教程】TileMap瓦片地圖的詳細(xì)使用方法

接下來開始實(shí)現(xiàn)土地,這里我創(chuàng)建了兩層Tilemap,第一層展示土地狀態(tài)(比如澆水土地會(huì)濕一塊),第二層展示物品,每次使用對(duì)應(yīng)的Tile都要手動(dòng)將sprite拖到Tile palette中生成還是挺麻煩的,這里同樣寫了個(gè)根據(jù)Sprite名生成Tile 的方法:

? //判定在Tilemap文件夾下否存在該名稱的tile文件,不存在就創(chuàng)建新的并保存下來

?

??? public Tile CheckTileExits(string name)

??? {

??????? string tempPath = string.Format("{0}{1}", "Tilemap/", name);

??????? string Path = string.Format("{0}{1}{2}", "/Resources/Tilemap/", name, ".asset");

??????? string Lastpath = Application.dataPath + Path;

??????? if (!File.Exists(Lastpath))

??????? {

??????????? CreateExampleAsset(name);

??????????? Tile land1 = (Tile)Resources.Load(tempPath);

??????????? return land1;

??????? }

??????? Tile land2 = (Tile)Resources.Load(tempPath);

??? ????return land2;

??? }

?

??? // 根據(jù)精靈圖名字創(chuàng)建tile

??? public void CreateExampleAsset(string name)

??? {

??????? string Path = "Assets/Resources/Tilemap/";

??????? Tile exampleAsset = Tile.CreateInstance<Tile>();

??????? exampleAsset.sprite = Bagmanager.instance.ReadSpritesByString(name);

??????? string temp = string.Format("{0}{1}{2}", Path, name, ".asset");

??????? AssetDatabase.CreateAsset(exampleAsset, temp);

??????? AssetDatabase.Refresh();

??? }

?

然后新建一個(gè)土地類:

public enum LandType

{

??? Unkown, normal, reclaimed, seeded, watered, planted

}

?

public class Land

{

??? public int Id;

??

??? //當(dāng)前土地狀態(tài)

??? public LandType landType;

?

??? //每一塊土地的坐標(biāo)(對(duì)應(yīng)Tilemap中的圖塊坐標(biāo))

??? public Vector3Int LandPos;

?

??? //需要展示的圖片集合

??? public string [] icons ;

?

??? //種子所需的成長(zhǎng)時(shí)間

??? public int growTime;

?

??? //種子一開始種下的時(shí)間

??? public int startTime;

?

??? //種子實(shí)際成長(zhǎng)時(shí)間

??? public float actualTime;

}

?

土地?cái)?shù)據(jù)的讀寫操作和物品的差不多,這里也不過多贅述,接下來解決操作問題,這里先不管動(dòng)畫,解決主要問題(其實(shí)就是懶),星露谷中允許對(duì)人物周圍的8個(gè)圖塊進(jìn)行各種操作,所以我們需要人物自身的坐標(biāo),土地已經(jīng)網(wǎng)格化了,所以人物自身的坐標(biāo)也需要轉(zhuǎn)換土地對(duì)應(yīng)的坐標(biāo)(這里要以人物的腳為中心點(diǎn)):

public Vector3Int[] GetHumanAround()

??? {

??????? Vector3Int temp = GetCurPos();

??????? Vector3Int[] temps = new Vector3Int[8];

??????? temps[0] = new Vector3Int(temp.x-1, temp.y+1,0);

??????? temps[1] = new Vector3Int(temp.x, temp.y+1,0);

??????? temps[2] = new Vector3Int(temp.x+1, temp.y+1,0);

??????? temps[3] = new Vector3Int(temp.x-1, temp.y,0);

???????

??????? temps[4] = new Vector3Int(temp.x+1, temp.y,0);

??????? temps[5] = new Vector3Int(temp.x-1, temp.y-1,0);

??????? temps[6] = new Vector3Int(temp.x, temp.y-1,0);

??????? temps[7] = new Vector3Int(temp.x + 1, temp.y - 1, 0);

??????? return temps;

??????

??? }

?

同時(shí)鼠標(biāo)坐標(biāo)也轉(zhuǎn)換為Int型,在指定圖塊進(jìn)行操作,滿足條件即可執(zhí)行~

最后值得一提的是時(shí)間和每個(gè)圖塊被人物碰到的小動(dòng)畫,這兩個(gè)部分我都用協(xié)程完成,雖然用協(xié)程記錄時(shí)間會(huì)有誤差,但星露谷并不是對(duì)時(shí)間要求很精確的游戲:

時(shí)間:

? void Start()

??? {

??????? StartCoroutine(TimeIncrease());

??? }

?

// 10s記錄一次時(shí)間,也順便刷新右上角的時(shí)間面板(10s相當(dāng)于星露谷的10分鐘)

? public IEnumerator TimeIncrease()

??? {

??????? while (true)

??????? {

??????????? while (gameTime.time <= 1200)

??????????? {

??????????????? gameTime.time += 10f;

??????????????? rotate.z = rotate.z + 0.15f;

?

??????????????? yield return new WaitForSeconds(10f);

??????????????? RotatePoint.Rotate(rotate);

??????????????? dayText.text = string.Format("{0}{1}", gameTime.day.ToString(), "日");

??????????????? hour = (int)(gameTime.time / 60);

??????????????? minute = (int)(gameTime.time - hour * 60);

??????????????? string tempTime = string.Format("{0}{1}{2}", hour.ToString(), ":", minute.ToString());

??????????????? minuteText.text = tempTime;

???????????? }

??????????? DayEnd();

??????? }

?}

?

每個(gè)圖塊的動(dòng)畫這里有點(diǎn)麻煩,Unity將每個(gè)圖塊的transform數(shù)據(jù)封裝到了一個(gè)4x4的矩陣中嗎,所以需要額外做一次矩陣轉(zhuǎn)換,再調(diào)用這個(gè)方法完成這個(gè)小動(dòng)畫:

??? //判斷是否碰到了種子

??? public void TouchCrop()

??? {

??????? Vector3Int tempPos1 = GetCurPos();

??????? Matrix4x4 curTrans=new Matrix4x4();

??????? foreach (var key in LandManager.instance.seededPos.Keys)

??????? {

??????????? if (LandManager.instance.seededPos[key] == tempPos1)

??????????? {

??????????????? curTrans = LandPanel.level2.GetTransformMatrix(LandManager.instance.lands.land2[key].LandPos);

?????????????? if (direction == Direction.Left || direction == Direction.DownLeft || direction == Direction.UpLeft)

??????????????? {

?????????????????? StartCoroutine(LeftShake(0.5f, curTrans, key));

????????? ??????}

??????????????? else

??????????????? {

?????????????????? StartCoroutine(RightShake(0.5f, curTrans, key));

??????????????? }

??????????????? break;

??????????? }

??????? }

??? }

?

??? // 莊稼左抖動(dòng)

??? public IEnumerator? LeftShake(float duration,Matrix4x4 curTrans,int key)

??? {

??????? Vector3 temp = new Vector3(0, 0, 0);

??????? float elapsed = 0f;

?

??????? while (elapsed < duration)

??????????? {

??????????????? if (elapsed < duration / 2)

??????????????? {

??????????????????? temp = temp + (leftAngel / duration) * Time.deltaTime * 2;

??????????????????? Quaternion temp_rotation = Quaternion.Euler(temp);

??????????????????? curTrans.SetTRS(curTrans.GetPostion(), temp_rotation, new Vector3(1, 1, 1));

??????????????????? LandPanel.level2.SetTransformMatrix(LandManager.instance.lands.land2[key].LandPos, curTrans);

??????????????? }

??????????????? else if(elapsed < duration)

??????????????? {

??????????????????? temp= temp- (leftAngel / duration) * Time.deltaTime * 2;

????????????? ??????Quaternion temp_rotation = Quaternion.Euler(temp);

??????????????????? curTrans.SetTRS(curTrans.GetPostion(), temp_rotation, new Vector3(1, 1, 1));

??????????????????? LandPanel.level2.SetTransformMatrix(LandManager.instance.lands.land2[key].LandPos, curTrans);

??????????????? }

??????????? elapsed += Time.deltaTime;

??????????? yield return 0;

??????? }

??? }

?

最后展示下目前的施工進(jìn)度,星露谷還未完結(jié),暫時(shí)先不放這個(gè)還未圓滿的工程了~


最后感謝知乎? @絮醬醬的EPPlus的小教程,永遠(yuǎn)滴神:馬三小伙兒寫的Litjson擴(kuò)展(Litjson原版不支持Vector3Int類型數(shù)據(jù))和_阿松先生的矩陣轉(zhuǎn)換工具類,感謝大佬們的工作,讓俺節(jié)省了很多的功夫~


貼上馬三小伙兒和阿松先生的原帖地址:

【Unity游戲開發(fā)】跟著馬三一起魔改LitJson

https://cloud.tencent.com/developer/article/1608178

【Unity矩陣知識(shí)】之Matrix4x4矩陣變換詳細(xì)實(shí)例

https://blog.csdn.net/aaa583004321/article/details/81948780?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param


歡迎加入游戲開發(fā)群歡樂攪基:1082025059

對(duì)游戲開發(fā)感興趣的童鞋可戳這里進(jìn)一步了解:levelpp.com/

我們的公眾號(hào):“皮皮關(guān)"

B站:“皮皮關(guān)做游戲”

用Unity還原星露谷物語(yǔ)(2):種地篇(數(shù)據(jù)讀寫+TileMap)的評(píng)論 (共 條)

使用qq登录你需要登录后才可以评论。
松滋市| 三明市| 阆中市| 班戈县| 台东县| 安福县| 岢岚县| 五华县| 卢氏县| 明水县| 分宜县| 肇庆市| 郧西县| 定日县| 汉沽区| 沙坪坝区| 五河县| 雷山县| 博爱县| 寿阳县| 习水县| 平凉市| 武汉市| 彰化市| 阳新县| 蒙山县| 河北区| 永清县| 襄樊市| 宕昌县| 新沂市| 五台县| 鄂州市| 清原| 彰化县| 湟中县| 喀喇沁旗| 当阳市| 台州市| 奎屯市| 定襄县|