百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Unity3D引擎 2D地图TileMap 存档 保存地图

cac55 2024-11-15 16:39 30 浏览 0 评论

关注公众号,获取更多干货。

下面是正文:

最近在恶补Unity的一些模块,前几天朋友推荐我看一下Unity2017.2以上才支持的TileMap,他说用这个做2D关卡贼方便,所以我就去看了一眼,的确很棒,包括官方出的Demo也是看一眼基本上就能学会,所以说到这里不得不骄傲一下,Unity现在是越做越牛x,身为Unity的攻城狮我真是感到无比的咳咳咳咳咳…

好了废话不能多说,先说说我为啥要写这篇博客,其实TileMap这个工具是真的很好用,但是有一个问题,一般需要设计2D关卡的游戏,都是需要很多关的,就连给我介绍这个TileMap的朋友都说,他现在在做的游戏才刚刚200关,嗯?才200关?才?

那么问题来了,这个地图是怎么保存的呢,200个Scene?还是做了200个预制体?不过这个我倒是没有问,然后我百度了一下TileMap保存地图,还真没有人写过类似保存TileMap地图、载入TileMap地图的,那索性我就来搞一下吧,虽然这只是第一个版本,但是还是欢迎大家和我一起完善,写的不好的地方请见谅哈。

其实到了这里,不妨会有人问我,这玩意有啥用,其实说没用真没啥用,要说有用的话还特别的有用,就是你把这些东西都弄完,然后让你们的策划学会咋用这个工具,关卡搭建的事情交给ta就好了,一劳永逸。

而且如果你的地形地图需要放在服务器动态加载的话,这个功能就不错啦。

为了防止有人还没用过或者还不是很熟悉TileMap,这里我就贴一个链接,大家可以通过这个前辈的博客,来学习或了解一下TileMap。

通灵召唤术:https://www.jianshu.com/p/d8fe795bf6c7


如果上面那个文章大家都吃透了的话,我就开始讲解我的逻辑啦。

0x00) 导出\保存 地图

class 0x00_1{
	画笔\瓦片 也就是 Tile 我暂时把他定为两大类,Rule Tile 和 Default Tile;
	Rule Tile 就是导入插件后的可自定义的高级画笔,Defaule Tile就是默认的画笔;
	我们需要把这两种画笔区分开来,通过Unity编辑器拖拽,让我的脚本识别你的所有Tile;
	手动编辑Init();
	初始化所有Tile,并将Tile添加到Dictionary中方便后期载入地图使用。
}
class 0x00_2{
	在每一层TileMap上挂载一个ReadTilemap脚本,用来读取地图和保存地图;
}

0x01) 导入\载入 地图

class 0x01_1{
	通过Unity编辑器拖拽,让我的脚本识别所有需要载入地图的TileMap;
}	
class 0x01_2{
	通过TileMap名称,找到对应的地图文件,开始载入地图;
}

0x02) ReadTilemap.cs脚本

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
public class ReadTilemap : MonoBehaviour
{
 /// <summary>
 /// Maps to be saved
 /// </summary>
 private Tilemap tilemap;
 /// <summary>
 /// The boundaries of the map need to be preserved
 /// </summary>
 public BoundsInt area;
 // Start is called before the first frame update
 void Start()
 {
 tilemap = GetComponent<Tilemap>();
 }
 void Update()
 {
 if(Input.GetKeyDown(KeyCode.S))
 {
 ExportMap();
 }
 if (Input.GetKeyDown(KeyCode.C))
 {
 ClearMap();
 }
 }
 public void ExportMap()
 {
 TileBase[] tileArray = tilemap.GetTilesBlock(area);
 print(tilemap.name + " - Area size: " + tileArray.Length);
 int tilecount = 0;
 Dictionary<string, string> data = new Dictionary<string, string>();
 for (int i = area.xMin; i < area.xMax; i++)
 {
 for (int j = area.yMin; j < area.yMax; j++)
 {
 if (tilemap.GetTile(new Vector3Int(i, j, 0)) == null)
 {
 continue;
 }
 print(tilemap.GetTile(new Vector3Int(i, j, 0)).ToString());
 Vector3Int temp = new Vector3Int(i, j, 0);
 data.Add(i + "," + j, tilemap.GetTile(temp).name);
 tilecount++;
 }
 }
 string jsonData = LitJson.JsonMapper.ToJson(data);
 MapsMode._Instance.ExportMap(jsonData, tilemap.name);
 print(tilemap.name + " - The number of tiles in the area : " + tilecount);
 }
 public void ClearMap()
 {
 tilemap.ClearAllTiles();
 }
}

0x03) ReadTilemap.cs脚本使用讲解

class 0x03_1{
	每一个需要保存地图的TileMap都要挂载这个脚本;
	保存地图是会保存多个文件,每个TileMap会保存成一个文件;
}	
class 0x03_2{
	文件路径是Application.dataPath + "/Maps/" + Maps[i].name + ".txt";
	也就是你的Assets路径下的Maps文件夹;
	地图文件的名字就是TileMap的GameObject名字加上.txt;
}	
class 0x03_3{
	这个脚本使用的时候有一个需要注意的地方;
	public BoundsInt area;
	这个值需要手动输入;
	我先将一下这个是干啥用的,其实很简单,这个就是TileMap的边界;
	我是根据这个边界来遍历里面的所有Tile;
}
class 0x03_4{
	area边界的值可以用TileMap给到工具去测量;
}

0x04) MapsMode.cs脚本

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Tilemaps;
public class MapsMode : MonoBehaviour
{
 public static MapsMode _Instance;
 void Awake()
 {
 if (_Instance == null)
 {
 _Instance = this;
 }
 }
 /// <summary>
 /// Rule Tile
 /// </summary>
 public TileBase GrassPlatform;
 public TileBase Waterfall;
 /// <summary>
 /// Default Tile
 /// </summary>
 public TileBase[] EnvironmentProps;
 /// <summary>
 /// All Tile
 /// </summary>
 public Dictionary<string, TileBase> Tiles = new Dictionary<string, TileBase>();
 /// <summary>
 /// All Tile Map
 /// </summary>
 public Tilemap[] Maps;
 void Start()
 {
 Init();
 }
 public void Init()
 {
 Tiles.Add("GrassPlatform-RuleTile", GrassPlatform);
 Tiles.Add("Waterfall-RuleTile", Waterfall);
 for (int i = 0; i < EnvironmentProps.Length; i++)
 {
 Tiles.Add("EnvironmentProps_TileSet_" + i, EnvironmentProps[i]);
 }
 print("Init() is over.");
 }
 void Update()
 {
 if (Input.GetKeyDown(KeyCode.I))
 {
 ImportMap();
 }
 }
 public void ImportMap()
 {
 for (int i = 0; i < Maps.Length; i++)
 {
 FileInfo fi = new FileInfo(Application.dataPath + "/Maps/" + Maps[i].name + ".txt");
 if (fi.Exists)
 {
 StreamReader sr = fi.OpenText();
 string data = sr.ReadToEnd();
 print("ReadData ===> " + data);
 Dictionary<string, string> mapData = LitJson.JsonMapper.ToObject<Dictionary<string, string>>(data) as Dictionary<string, string>;
 foreach (KeyValuePair<string, string> kvp in mapData)
 {
 string dataKey = kvp.Key;
 string dataValue = kvp.Value;
 string[] posData = dataKey.Split(',');
 Vector3Int pos = new Vector3Int(int.Parse(posData[0]), int.Parse(posData[1]), 0);
 TileBase tileData = getTile(dataValue);
 Maps[i].SetTile(pos, tileData);
 print("Create Tile ===> " + pos + " : " + tileData);
 }
 sr.Close();
 sr.Dispose();
 }
 else
 {
 print("ERROR !!! ===> File Not Found.");
 }
 }
 }
 public void ExportMap(string data, string mapName)
 {
 string filePath = Application.dataPath + "/Maps/" + mapName + ".txt";
 print("FilePath: " + Application.dataPath + "/Maps/" + mapName + ".txt");
 FileInfo fi = new FileInfo(filePath);
 if (fi.Exists)
 {
 print("File is Exists,Delete!");
 fi.Delete();
 fi.Refresh();
 }
 StreamWriter sw = fi.CreateText();
 sw.Write(data);
 sw.Flush();
 sw.Close();
 sw.Dispose();
 fi.Refresh();
 }
 public TileBase getTile(string tileName)
 {
 TileBase tile;
 if (Tiles.TryGetValue(tileName,out tile))
 {
 return tile;
 }
 else
 {
 return null;
 }
 }
}

0x05) MapsMode.cs脚本使用讲解

class 0x05_1{
	首选根据不同要求,要将项目中使用到的所有Tile都添加到这个脚本的记录当中;
	Rule TIle 与 默认的 Tile 要区分记录;
	通过Unity拖拽添加后,在Init()函数中初始化,将所有Tile都添加到同一字典中方便查找;
	Rule Tile比较好添加,但是默认的Tile有很多的瓦片,下面教大家一个简便的方法;
}	

class 0x05_2{
	导入Tile后需要手动编辑Init()函数;
	Rule Tile直接Add就OK;
	由于默认的Tile是数组,所以需要循环遍历Add;
}	
class 0x05_3{
	让脚本识别场景中所有的TileMap同0x05_1拖拽即可;
}	

0x06) 测试

class 0x06{
	运行项目,在控制台打印Init() is over.后即可测试;
	按下“S”即可保存地图 - Save;
	按下“C”即可清空地图 - Clear;
	按下“I”即可载入地图 - Import;
}	

0x07) 新建地形运行保存,删除部分地形在运行,先删除所有后再加载

0x08) 加载时添加延时效果


好啦,以上就是我的全部代码啦,这次就不贴工程文件了,毕竟写的不是可以应用到实际项目的,还有好多东西需要扩展。

例如Editor编辑扩展、动态加载Tile、动态加载Tilemap、保存的地图问价加密、加载地图文件时解密

再或者可以做成那种在服务器后台加载地图等等,欢迎大家一起与我共同扩展这个小功能吧。

最后,感谢大家的阅读~

————————————————

版权声明:本文为CSDN博主「Aries.H」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/Aries_H/article/details/101760141

相关推荐

Mac电脑强制删除任何软件方法-含自启动应用

对于打工者来说,进入企业上班使用的电脑大概率是会被监控起来,比如各种流行的数据防泄漏DLP,奇安信天擎,甚至360安全卫士,这些安全软件你想卸载是非常困难的,甚至卸载后它自己又安装回来了,并且还在你不...

Linux基础知识 | 文件与目录大全讲解

1.linux文件权限与目录配置1.文件属性Linux一般将文件可存取的身份分为三个类别,分别是owner/group/others,且三种身份各read/write/execute等权限文...

文件保护不妥协:2025 年 10 款顶级加密工具推荐

数据安全无小事,2025年这10款加密工具凭借独特功能脱颖而出,从个人到企业场景全覆盖,第一款为Ping32,其余为国外英文软件。1.Ping32企业级加密核心工具,支持200+文件格...

省心省力 一个软件搞定系统维护_省心安装在哪里能找到

◆系统类似于我们居住的房间,需要经常打理才能保持清洁、高效。虽然它本身也自带一些清理和优化的工具,但借助于好用的第三方工具来执行这方面的任务,会更让人省心省力。下面笔者就为大家介绍一款集多项功能于一身...

JAVA程序员常用的几个工具类_java程序员一般用什么软件写程序

好的工具做起事来常常事半功倍,下面介绍几个开发中常用到的工具类,收藏一下,也许后面真的会用到。字符串处理:org.apache.commons.lang.StringUtilsisBlank(Char...

手工解决Windows10的若干难题_windows10系统卡顿怎么解决

【电脑报在线】很多朋友已经开始使用Win10,估计还只是测试版本的原因,使用过程中难免会出现一些问题,这里介绍解决一些解决难题的技巧。技巧1:让ProjectSpartan“重归正途”从10074...

System32文件夹千万不能删除,看完这篇你就知道为什么了

C:\Windows\System32目录是Windows操作系统的关键部分,重要的系统文件存储在该目录中。网上的一些恶作剧者可能会告诉你删除它,但你不应该尝试去操作,如果你尝试的话,我们会告诉你会发...

Windows.old 文件夹:系统备份的解析与安全删除指南

Windows.old是Windows系统升级(如Win10升Win11)或重装时,系统自动在C盘创建的备份文件夹,其核心作用是保留旧系统的文件、程序与配置,为“回退旧系统”提供保...

遇到疑难杂症?Windows 10回收站问题巧解决

回收站是Windows10的一个重要组件。然而,我们在使用过程中,可能会遇到一些问题。例如,不论回收站里有没有文件,都显示同一个图标,让人无法判别回收站的空和满的真实情况;没有了像Windows7...

卸载软件怎么彻底删掉?简单几个步骤彻底卸载,电脑小白看过来

日常工作学习生活中,我们需要在安装一些软件程序,但随着软件的更新迭代速度,很多时候我们需要重新下载安装新的程序,这时就需要将旧的一些软件程序进行卸载。但是卸载软件虽然很简单,但是很多小伙伴们表示卸载不...

用不上就删!如何完全卸载OneDrive?

作为Windows10自带的云盘,OneDrive为资料的自动备份和同步提供了方便。然而,从隐私或其他方面考虑,有些人不愿意使用OneDrive。但Windows10本身不提供直接卸载OneDri...

【Linux知识】Linux下快速删除大量文件/文件夹方法

在Linux下,如果需要快速删除大量文件或文件夹,可以使用如下方法:使用rm命令删除文件:可以使用rm命令删除文件,例如:rm-rf/path/to/directory/*这个命令会递...

清理系统不用第三方工具_清理系统垃圾用什么软件

清理优化系统一定要借助于优化工具吗?其实,手动优化系统也没有那么神秘,掌握了方法和技巧,系统清理也是一件简单和随心的事。一方面要为每一个可能产生累赘的文件找到清理的方法,另一方面要寻找能够提高工作效率...

系统小技巧:软件卸载不了?这里办法多

在正常情况下,我们都是通过软件程序组中的卸载图标,或利用控制面板中的“程序和功能”模块来卸载软件的。但有时,我们也会发现利用卸载图标无法卸载软件或者卸载图标干脆丢失找不到了,甚至控制面板中卸载软件的功...

麒麟系统无法删除文件夹_麒麟系统删除文件权限不够

删除文件夹方法例:sudorm-rf文件夹名称。删除文件方法例:sudorm-r文件名包括扩展名。如果没有权限,给文件夹加一下权限再删。加最高权限chmod775文件名加可执行权限...

取消回复欢迎 发表评论: