重製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了,後面都是同樣,有三個字符串。
看下解析的代碼:api

 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的輸出,和圖中的單位位置一致的數組

相關文章
相關標籤/搜索