重制AdvanceWars第一步 -- 搞定地图

首先来聊下高级战争吧
Advance Wars,由任天堂旗下的Intelligent Systems开发的战棋游戏。
初作诞生于GBA上,后来继续跟进了高战2黑洞崛,而后在下一代掌机DS上也出了三代续作高战DS,以及后来不太一样的毁灭日。
本人的高中时代正值GBA横行天下的时候,那时候最喜欢的事情就是晚上躲在宿舍厕所偷偷玩GBA(不熄灯)。有时候还和小伙伴联机打GT2赛车马里奥等等,而高战...这种时间吃货能和小伙伴联机一把就实在太珍贵了。
鉴于高战这种类型的硬核战棋在日本地区不受欢迎,估计以后是不会再出续作了。不过成为程序员的一个好处就是,自己做做这种游戏还是可以的。
除去了战棋类游戏漫长的回合太拖时间这种共有的硬伤之外,无需练级无需养成,兵种相克,个性鲜明的CO和强大的CO Power,高战绝对的硬核战棋,好游戏呀。
高战的核心玩法就是下棋,那么最重要的就是棋盘,也就是地图的制作。
作为一个穷屌程序员,我是没有资金投入买美术的,所以先去抠点图来。
抠图的方法有很多,其实老外很多网站都有很多这些古老游戏的资源。开始的时候我选择了通过GBA模拟器VisualBoy来抠图,方法是百度来的。
抠了一堆类似下面的图片之后,实在是不耐烦了。

还是先做点功能吧,比如在Unity里面拖个地图出来。然而......
Tile的大小、接合、不同地形的过渡....这要做一个地图编辑器太痛苦了。尤其是不同地形的过渡。比如海水和平地之间,九宫格的接壤就有八个边,还有登陆用的浅滩怎么办?海水里面还有礁石tile...道路的转向、交汇,哦天呐,这种东西不是那个年代几乎所有瓷砖游戏都有的吗?不如去找找工具吧!
于是被安利到一个工具:TiledMapEditor。百度一下就找到了官网,还是个开源的工具,下载是免费的只是会引诱用户捐点小钱。真是好东西。
具体怎么被安利的请转移这里看:https://www.zhihu.com/question/25876314
可是我不会用,也没有瓷砖贴图...一穷二白。
此时一个神器从天而降,被基友安利得知一个大洋彼岸的高战死忠有制作这个高级战争专用地图编辑器!
链接: http://pan.baidu.com/s/1qYf9d2O 密码: g2gr

啊!牛逼!
刷刷,编辑完毕,导出保存~~等等!保存之后的地图文件怎么读呢?天呐,还有一堵墙,别说看E文了,连网站都打不开啊!
在获取不到更多的资料的情况下,面对着这个导出后的*.aws文件发呆,还能怎么办,读取试试看啦。
第一步,打开文件,我直接拖拽到了手头上最强大的工具VisualStudio2013里,然后出现下图这样的一堆十六进制:

当然,除了开头,其他人类是看不了的。慢慢分析,开头是文件的标识,是个字符串,很简单,每个文件都一样,是固定的。后面开始就不一样了,最后的结尾部分还是字符串。
那么解决格式问题的关键就是处理中间的那串。
这种文件是不可能再做加密之类的事情的,所以,好的消息是只要创建一个新的地图,不断比对,就能够知道文件的格式。
于是我创建了一个新的地图,保存,用VS打开。发现中间出现了一大片的0000和FFFF,因为地图是空的,很明显,这些地方就是地图上的单位填充点。
一张2D的地图,可以看成是一个二维数组,保存文件里面必然有这个二维数组在一维上的展开。
继续分析,高战的地图不像RPG,RPG通常分三层:地形建筑和单位,而高战上没有地形和建筑的分层必要,根据编辑器设计地图时候的方式可以看出应该是分为两层,一层是地形和建筑物,二层是移动单位。
然后看地图的大小,我创建了10x11和20x21的地图,发现0000和FFFF的数量放大了,如果上面分层的猜测没错,那么0000和FFFF分别就是每一层。同时改变的还有第11和第12字节,肉眼一看就知道这两个字节分别是地图的长度和宽度了。再数一下0000的数量和FFFF的数量,发现是一样的,而且正好是长*宽的倍数,也就是棋格的倍数,正好是棋格数*2Byte,也就是一个int16代表了一个地图单位。
那么格式就很明了啦~
前面10个字节是固定字符串标题,11是width,12是height,用byte来做长宽也就是说地图不可能大过255*255嘛。13暂时不明,不过后来分析出是坏境相关的设定(普通草地、沙漠、雪地)。接下来根据width*height读取地形单位,每两个字节就是一个单位,读完之后就是移动作战单位同样的数量也是2个字节一个。剩下的是地图信息。

从图中可以看出来地图信息是个字符串,但是中间夹杂着一些不是字符串的东西。这部分的信息是地图制作者加上去的,所以字符串的长度不像标题固定10字节,是会变得。
而划分字符串很简单通常都是两种方法:分隔符分隔,或是头部声明长度。这里用肉眼就能看出来是头部声明的长度了,头部有四个字节不能转字符串,但是算一下十进制正好就是字符串的长度,OK了,后面都是一样,有三个字符串。
看下解析的代码:

 1             string path = null;
 2             if (args.Length == 0)
 3             {
 4                 Debug.WriteLine("请输入地图文件路径:");
 5                 path = Console.ReadLine().Trim(‘\"‘);
 6             }
 7             else
 8             {
 9                 path = args[0];
10             }
11             var data = File.ReadAllBytes(path);
12             Debug.WriteLine("开始解析...");
13             Debug.WriteLine("------------------------------------");
14             int offset = 0;
15             string capition = Encoding.ASCII.GetString(data, offset, 10);
16             Debug.WriteLine("caption:{0}", capition, 1);
17             offset += 10;
18             int width = data[offset];
19             offset += 1;
20             int height = data[offset];
21             offset += 1;
22             Debug.WriteLine("width:{0}, height:{1}", width, height);
23             int tileset = data[offset];
24             offset += 1;
25             Debug.WriteLine("tileset:{0}", tileset);
26
27             //terrain
28             for (int i = 0; i < width*height; i++)
29             {
30                 short terrain = BitConverter.ToInt16(data, offset);
31                 offset += 2;
32                 //if (i < 10)
33                 {
34                     Debug.WriteLine("terrain:\t{0:X4}\t{0}", terrain);
35                 }
36             }
37             //unit
38             for (int i = 0; i < width * height; i++)
39             {
40                 short unit = BitConverter.ToInt16(data, offset);
41                 offset += 2;
42                 if (i < 10)
43                 {
44                     //Debug.WriteLine("unit:\t{0:X4}\t{0}", unit);
45                 }
46             }
47             //info
48             int mapnameLength = BitConverter.ToInt32(data, offset);
49             offset += 4;
50             string mapname = Encoding.ASCII.GetString(data, offset, mapnameLength);
51             offset += mapnameLength;
52             Debug.WriteLine("mapname:{0}", mapname, 1);
53
54             int authorLength = BitConverter.ToInt32(data, offset);
55             offset += 4;
56             string author = Encoding.ASCII.GetString(data, offset, authorLength);
57             offset += authorLength;
58             Debug.WriteLine("author:{0}", author, 1);
59
60             int descriptionLength = BitConverter.ToInt32(data, offset);
61             offset += 4;
62             string description = Encoding.ASCII.GetString(data, offset, descriptionLength);
63             offset += descriptionLength;
64             Debug.WriteLine("description:{0}", description, 1);
65
66             Debug.WriteLine("------------------------------------");
67             Debug.WriteLine("解析完毕!");

地图文件的格式就这么解决了,然后就是看每一个单位对应的编号了。
其实地形的编辑和最后贴图是不一样的,比如海水和陆地的接壤处拐弯处,其实地形只有海水和陆地之分,而贴图就会有四个弯角和纵向横向六种贴图。而贴图只要看看就好了,实际程序中需要参与计算的是海水/陆地的加成。马路桥梁管道等等都是一样。也就是说其实编号只分地形,不管最后在地图上的贴图是怎样。
下面整理出的就是建筑物表

地形表就更简单了,不区分阵营了。
这样,导出的aws文件配合地图png截屏就可以轻松地开发新棋盘啦~ 拿来主义真牛逼!
最后,检测下成果:

看unit的输出,和图中的单位位置一致的

时间: 2024-12-28 10:46:57

重制AdvanceWars第一步 -- 搞定地图的相关文章

iOS开发三步搞定百度推送

iOS开发三步搞定百度推送 百度推送很简单,准备工作:在百度云推送平台注册应用,上传证书. 步骤一: 百度云推送平台 http://push.baidu.com/sdk/push_client_sdk_for_ios  在这里下载iOS端SDK包,如下图: 把SDK包里面的下图文件夹拖到你的工程中,如下图,第一步就这么简单. 步骤二: 在工程中AppDelegate.m中的- (BOOL)application:(UIApplication *)application didFinishLaun

10步搞定App内测发布(蒲公英内测平台)

10步搞定App内测发布(蒲公英内测平台) (写作不易,转载请注明出处,谢谢!) App内测是必不可少的一个环节,重中之重! 有两种方法:一.把每台手机的插到开发人员的电脑上跑一边(不推荐):二.通过第三方分发平台(推荐),可以把自己的App发布到第三方的平台上,供内部员工下载,就不需要每台机子都到开发人员的电脑上跑一遍! 现在博主(最近看博客,博主都这样称呼自己)就来谈谈第二种方式,平台使用蒲公英平台: 1.开发者账号,Must: 2.要测试的iPhone.iPad真机的UDID填写到Deve

redha7.2配置静态网卡(三步搞定)

三步搞定: 编辑网卡配置文件:vi /etc/sysconfig/network-scripts/ifcfg-eno16777736(也可能是eth0或eth1或者eth+任何数字) 当前是DHCP,如果要使用静态IP修改: BOOTPROTO=static                #声明IP地址获得的途径 ONBOOT=yes                          #开启自动启用网络连接 增加: IPADDR=192.168.1.1              #设置IP地址(

SmaterWeatherApi---签名加密和数据访问--简单粗暴一步搞定

使用中国天气网接口的朋友们,大家(还有我)辛苦了 有兴趣的可以去了解一下http://smart.weather.com.cn/wzfw/smart/weatherapi.shtml 年初的时候停用了之前的接口,改为申请使用,于是发个了申请邮件,中间各种曲折...一万字.. 总算是申请下来了,不过接口文档啊,看的我累觉不爱,文档上只有php版的kay生成方法,我在androi上使用,那些加密方法不知道用java如何实现 一怒之下,就写个php版的吧,本来是只想写个生成key的接口的,后来想了想

四步搞定NiosII工程路径改变(转)

四步搞定NiosII工程路径改变 (2014-08-03 16:41:01) 转载▼http://blog.sina.com.cn/s/blog_bff0927b0102uy30.html 标签: nios 路径改变 setting.bsp 分类: 开发工具 在NiosII的开发过程中,路径改变会带来一系列问题:比如当我们在PC上某个路径下新建一个工程Nios_Prj(含QuartusII工程.Qsys模块和NiosII工程)后,假设其路径为C:\Nios_Prj,如果将工程路径改为D:\Nio

教你破解网页上各种限制(禁止鼠标右击复制等等)一步搞定!

有的网页防止别人直接复制盗取网页内容,设置了复制限制韩国的一些博客网站经常有这样的限制~现在我来教大家怎么用一步破解,不需要在浏览器里设置,一步搞定(博主建议:复制他人内容请注明来源,尊重他们劳动成果!) 来源: http://www.harleygwak.com/日志/教你破解网页上各种限制(禁止鼠标右击复制等等/方法:只要在浏览器地址栏输入以下内容就可以了. javascript:alert(document.onselectstart = document.onbeforecopy = d

android4步搞定自定义dialog

第一步,drawable新建一个圆角的背景xml dialog.xml <?xml version="1.0" encoding="utf-8"?> <!-- 用户注册红色按钮 --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"><!-- andr

Spring Boot 集成 Ehcache 缓存,三步搞定!

本次内容主要介绍基于Ehcache 3.0来快速实现Spring Boot应用程序的数据缓存功能.在Spring Boot应用程序中,我们可以通过Spring Caching来快速搞定数据缓存. 接下来我们将介绍如何在三步之内搞定 Spring Boot 缓存. 1. 创建一个Spring Boot工程 你所创建的Spring Boot应用程序的maven依赖文件至少应该是下面的样子: <?xml version="1.0" encoding="UTF-8"?

一步一步搞定Python3.6编码问题

Python中的编码问题很蛋疼,我们遇到这类问题有时候会使用下面几个步骤处理该问题: 1:这么低级问题,别问同事了太丢人,赶紧百度: 2:卧槽,出了一堆广告,骂个娘,赶紧找相关解决问题方式: 3:尼玛,终于搞定,原来这么简单,赶紧搞定其它工作,晚上回头在查原因: 4:傻B单位每天加班,到家都11点了,赶紧洗洗睡了:等会,先来局王者农药...... 5:编码问题早就忘了: 6:过了几天又出现编码错误,,从第1步开始重新来过. 今天我们就花一局王者农药时间搞定Python3.6的编码问题. 搞清楚编