系列教程:

  1. 地图编辑器开发(一)加载地图
  2. 地图编辑器开发(二)编辑地图
  3. 地图编辑器开发(三)测试阻挡
  4. 地图编辑器开发(四)导出阻挡信息
  5. 地图编辑器开发(五)导出地图资源

前一节把测试功能加上了,地图信息编辑好,测试通过之后,需要导出到游戏中。这节来看数据的导出。主要包括以下几个功能点:

  • 导出地图信息
  • 地图数据压缩
  • 读取地图数据

导出地图信息

数据内容

在导出地图信息之后,把数据格式定义好,必备数据有两个:阻挡遮罩信息和格子尺寸,其他的数据可以按需添加。

getExportData() {return {size: [this.oriW, this.oriH],cell: [this.CELL_W, this.CELL_H],block: this.blockInfoList,};
},

size 保存的整个地图的尺寸,block时阻挡和遮罩信息,是一个二维数组

导出

在工具栏添加一个导出按钮,点击之后导出数据,如图:

导出的格式我这里用的 json,用通用数据格式方便数据的交换。
cocos creator 打包之后是跨平台的,不同的平台数据导出方式有很大差异;因为平时都是用浏览器开发调试,因此只做了在浏览器里面的导出。基本思路是模拟点击链接下载文件,流程:

  1. 动态创建一个隐藏的链接
  2. 自动调用a标签点击方法
  3. 设置下载数据
  4. 点击之后移除A标签
saveForWebBrowser(json, filename) {if (!cc.sys.isBrowser) {return;}// 创建a标签let downloadLink = document.createElement("a");downloadLink.download = filename;downloadLink.innerHTML = "Download File";downloadLink.style.display = "none";// 设置下载内容let JsonString = JSON.stringify(json);let textFileAsBlob = new Blob([JsonString]);downloadLink.href = window.URL.createObjectURL(textFileAsBlob);downloadLink.onclick = () => {// 移除a标签document.body.removeChild(downloadLink);};document.body.appendChild(downloadLink);// 模拟点击a标签downloadLink.click();
}

点击导出按钮,会弹出另存为的弹窗,其中默认文件名字是程序中设置的 filename。



导出之后可以看到,数据30k+,挺大的,其中主要是格子的状态的二维数组,按图上的尺寸,总共有:7920/80 * 7160 / 40 = 17721 个数组元素,需要进行压缩。

地图数据压缩

数据的压缩我试过好几种方式,都介绍一下。总的来看有两种思路:第一种是将数据转化成字符串,然后在对字符串进行压缩;第二种是压缩二维数组的元素。

方案一:压缩字符串

转字符串

在进行字符串压缩之前,先把二维数组转换成字符串。将二维数组转成一维数组,然后将每个元素都变成字符串。

compressString(matrix) {// 将状态转换成一行制字符串let info = "";for (let i = 0; i < matrix.length; i++) {info += matrix[i].join("");}return info;},

压缩出来的数据大致是这样的结构:

然后就是要对这个字符串进行压缩。

合并连续相同字符

这里面有很多重复的0,1,2,很容易想到的一种压缩方式是合并重复的字符,比如 16个连续的 “0000000000000000”,合并为 “[0,16]”。

compressSame(info) {// 合并连续相同字符串,比如 "00000000" => "[0,8]"let same = "";let cur = info[0];let cnt = 1;for (let i = 1; i < info.length; i++) {if (info[i] === cur) {cnt += 1;} else {same += this.getCompressSameItem(cur, cnt);cur = info[i];cnt = 1;}}same += this.getCompressSameItem(cur, cnt);return same;
},

这种方式适合阻挡和遮罩都很少时,比如什么都不编辑,可以得到最大程度的压缩:

这种情况过于理想,统计了正式地图中字符出现的比例,大概是: “0”:“1”:“2” = 2:2:1,因此并不是很适合。

64进制压缩

转换成二进制

字符串中有很多的01,可以联想到二进制,如果只有01的话,可以用尽可能大的进制表示,这样一个字符就能表示更多的位数。但是,问题是其中出现了2,要怎么解决?可能用两位二进制表示一个状态,比如:00,01,10 分别表示 0, 1,2;这样字符串长度变成了原来的两倍,比如原来的字符是 120,变成二进制之后则是 011000,因此还需要做进一步的处理。

compressBase2(matrix) {// 将状态转换成一行二进制字符串let info = "";let st;for (let i = 0; i < matrix.length; i++) {for (let j = 0; j < matrix[i].length; j++) {st = matrix[i][j];if (st === 1) {st = "01";} else if (st === 2) {st = "10";} else {st = "00";}info += st;}}return info;
},
转换成64进制

要将二进制转成64进制显示,需要先定义好64进制显示的字符串,我这里定义的是:0-9,a-z,A-Z,+,/,然后就是将每6位(64是2的6次方)二进制,转换成1位64进制。具体转换代码如下:

const BASE64 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/";compressBase64(info) {// 将二进制字符串转换成64进制字符串let bin, idx, base64 = "";for (let i = 0; i < info.length; i += 6) {bin = info.substr(i, 6);idx = parseInt(bin, 2);if (isNaN(idx) || idx >= BASE64.length) {console.error("error input binary");return;}base64 += BASE64[idx];}return base64;
},

这样转换下来:block * 2 /6 = block/3,可以将字符串压缩到原来的 1/3 长度。

方案二:压缩数组元素

类似上面将字符串转换成二进制字符串,把整数0,1,2转成一个整数的2位 ,比如1,2,0,其二进制为01,10和00,合并成一个数即为 011000,就是整数24。要想用整数的每2位表示一个状态码,需要了解 JavaScript 中的位操作和数字的表示。

JavaScript Number 遵守 IEEE 754 规范。一个数占 64 bit = 1bit 符号位 + 11bit 指数 + 52bit 尾数,因此位运算最大可利用 52bit。但是所有按位运算都以 32 位二进制数执行。在执行位运算之前,JavaScript 将数字转换为 32 位有符号整数。执行按位操作后,结果将转换回 64 位 JavaScript 数。

那么状态码为 0, 1, 2,可用 2bit 表示,一个 32bit 整数可表示 16 个状态码。可以将数组元素个数压缩到原来的 1/16,听起来就很诱人。

compressNumber(matrix) {// 初始化新数组let matrix_new = [];let len = Math.floor(matrix.length * matrix[0].length / VALID_BIT);for (let idx_new = 0; idx_new < len; idx_new++) {matrix_new[idx_new] = 0;}// 用一个 32bit 整数表示 16 个状态码let idx, idx_new, bit;for (let x = 0; x < matrix.length; x++) {for (let y = 0; y < matrix[x].length; y++) {idx = x * matrix[x].length + y;idx_new = Math.floor(idx / VALID_BIT);bit = idx % VALID_BIT * 2;matrix_new[idx_new] = matrix_new[idx_new] | matrix[x][y] << bit;}}return matrix_new;
},

压缩之后的内容如下:

压缩前后对比:


我尝试了以上几种压缩方式,仅供参考,具体使用哪种,可以酌情考虑。

读取地图数据

每次重新打开都需要全部重新编辑,不能显示上次编辑的内容,这明现是不合理的,因此需要从之前导出的内容中恢复数据。因为我这里的是最后一种压缩方式,只实现了一种恢复方式。

// 从压缩内容中获取该坐标的原始值
getOriVal(info, x, y) {// info 是文件中json的数据,xy 为格子坐标let cnt_h = Math.ceil(info.size[1]/info.cell[1]);let idx = x * cnt_h + y;let idx_new = Math.floor(idx / VALID_BIT);let st_new = info.block[idx_new];let bit = idx % VALID_BIT * 2;let st = st_new >> bit & 3return st;
},

地图尺寸一般是屏幕尺寸的几本甚至几十倍上百倍,若一次性加载耗费时间很长,游戏在进入场景之前会卡很久,后续还需要加一个切图功能,将地图切成小尺寸的很多块,然后逐块加载。网页比较难实现切图,可能会考虑其他工具。做好之后,放在下一篇中分享出来。

地图编辑器开发(四)相关推荐

  1. 地图编辑器开发(五)

    系列教程: 地图编辑器开发(一)加载地图 地图编辑器开发(二)编辑地图 地图编辑器开发(三)测试阻挡 地图编辑器开发(四)导出阻挡信息 地图编辑器开发(五)导出地图资源 上一节篇尾提到,地图要切成小图 ...

  2. 地图编辑器开发(三)

    系列教程: 地图编辑器开发(一)加载地图 地图编辑器开发(二)编辑地图 地图编辑器开发(三)测试阻挡 地图编辑器开发(四)导出阻挡信息 地图编辑器开发(五)导出地图资源 上一节已经把地图信息编辑做好了 ...

  3. Unity3d开发——保卫萝卜学习笔记一地图编辑器开发

    一直在学习,几乎边学边忘,再也不想打王者农药了,现在打卡学习持续写博客,现在在开发学习保卫萝卜,这篇文章关于地图编辑器的开发,在项目中不能是无限个场景,用读取xml文件的方法可以说是能实现无限关卡,同 ...

  4. 梦幻之旅--地图编辑器开发

    首先,我的地图编辑器是十分简单的,但是网上一个像样的例子也没有,很是无奈,或许是我没有找到吧,不喜欢的勿拍.接下来进入正题.我的地图就比较简单,就是简单的1和0.1表示可走,0表示不可走.接下来先看看 ...

  5. 开发地图编辑器_使用地图编辑器开发地图

    存在XML映射以将源XML文档转换为目标XML文档. 映射编辑器获取在"映射编辑器"中创建的映射,并生成XSL文件以在运行时执行实际的XML转换. 在WebSphere Integ ...

  6. SRPG游戏开发(七)第三章 绘制地图 - 四 初步完善地图编辑器(Map Graph)

    返回目录 第三章 绘制地图 四       初步完善地图编辑器(Map Graph) 到目前为止我们可以开心的绘制我们的地图了,但有不少小问题.一直开心忘我的绘制地图,却不知道地图已经绘制了多大,还要 ...

  7. Android游戏开发之地图编辑器的使用以及绘制地图 (四)

    雨松MOMO带你走进游戏开发的世界之地图编辑器的使用以及绘制地图 雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong ...

  8. Tiled有java版本吗_【Cocos2d-X开发学习笔记】开发工具之Tiled地图编辑器的使用

    Cocos2D-X支持Tiled地图编辑器生成的地图数据文件.Tiled地图编辑器是一个以广泛使用为目标的地图编辑html 器,它使用简单而且能够轻松地在不一样的引擎中使用.目前最新版本使用Qt框架进 ...

  9. 游戏开发:Html5版宝可梦 Pokémon 游戏制作与设计思路分享(二)地图编辑器

    经过不懈的努力,终于迎来了更新,还会继续更新后续内容. 可能会加一些魔改的功能和玩法--^ ^ 大家可以一起讨论有趣思路 更新已完成的功能: 1.地图编辑器 2.角色移动碰撞检测 . 新实现的功能和大 ...

  10. 从零开始做3D地图编辑器 基于QT与OGRE

    第一章 基础知识 注:文章里面有不少个人见解,欢迎大家一起互相讨论.希望高人能给予相应理解与意见建议. 在实际3D游戏开发中,编辑器是极其重要的一个部分,一个优秀健壮的编辑器,可以使项目事半功倍,而相 ...

最新文章

  1. 2013福建高职单招计算机类专业,福建省2013高职单招计算机类试题及答案.doc
  2. jackson 反序列化string_Java 中使用Jackson反序列化
  3. 怎么用python编简单游戏_用Python实现一个简单的算术游戏详解
  4. 邓公数据结构C++语言版学习笔记1
  5. xp 4g内存补丁_32位操作系统导致电脑可用内存不足4G
  6. 简述linux常见的安全措施,六个常用的Linux安全基本措施
  7. 计算机网络实训室建设设备,计算机网络技术综合实训室建设方案.doc
  8. iOS UITextView和UITextViewDelegate
  9. [转]MySQL游标特性
  10. Origin | 比例弦图 (Chord Diagram) | 比例弦图与弦图的区别
  11. 2022最新高级java面试题
  12. 根据点云及其对应的四元数与GPS计算出其相对坐标系的经纬坐标(matlab)
  13. 传统企业如何精准获客?搭上这趟高科技顺风车
  14. Flutter地图系列(七)—— 高德地图记录运动轨迹
  15. warning: statement has no effect [-Wunused-value]
  16. STM32F4结合ESP8266上传信息到one_net(中国移动物联网云台)的总结(含客户端查询)
  17. enum 泛型 java_Java Enum作为Enum中的泛型类型
  18. 超导量子计算机原型机,科技前沿 | 超导量子计算原型机“祖冲之号”有多强?...
  19. 基于AM335X的EDMA 驱动程序开发
  20. 【大数据之路5-1】数据仓库工具 Hive

热门文章

  1. sqlserver2008清理数据库日志文件
  2. android电视不能root权限,有谁知道安卓电视root权限获取方法?
  3. 18个基于Web的代码开发编辑器
  4. c语言头文件下载大全,求C语言头文件下载?
  5. 学制两年的计算机考研院校,研究生学制三年合适还是两年实用
  6. python numpy安装失败_python 安装 numpy 教程及错误总结
  7. asa清空配置_思科ASA防火墙基本配置
  8. ROS2机器人笔记20-08-15
  9. Flash 用FLASH遮罩效果做图片切换效果
  10. 机器人动力学与控制_快速搭建“机器人动力学-参数辨识-轨迹规划-运动控制”的完整框架...