用Javascript開發《三國志曹操傳》-零部件開發(四)-用地圖塊拼成大地圖


小時候我們玩過拼圖游戲,是用自己的手去拼的。今天我們來研究研究用javascript來拼圖。同樣是拼圖,但用js拼圖要比用手拼圖麻煩多了,因此以后我要把它優化成引擎。

 

一、前言

以上是一段導語,話不扯遠,對《三國志曹操傳》熟悉的玩家知道,《三國志曹操傳》的地圖是由小地圖塊拼成的,那要實現它就和導語說得一樣:很麻煩。不過即使麻煩也是一門技術,因此在此分享給大家,希望大家喜歡。

前幾章的位置:

用Javascript開發《三國志曹操傳》-零部件開發(三)-人物對話中,仿打字機輸出文字

http://www.cnblogs.com/ducle/archive/2012/09/15/2686532.html

用Javascript開發《三國志曹操傳》-零部件開發(二)-讓目標人物移動

http://www.cnblogs.com/ducle/archive/2012/09/08/2677127.html

用Javascript開發《三國志曹操傳》-零部件開發(一)-讓靜態人物動起來

http://www.cnblogs.com/ducle/archive/2012/09/02/2667481.html

 

二、代碼講解

今天我要換換講解方式,先不給代碼,我們先來想想原理。現在,假如你有一幅圖片,把它裁開成若干份,並打亂。現在如果讓你用js把他們組織起來,如何做呢?先不說圖的順序,首先來看把它們弄在一起就很難了。這時我減少難度,給你幾個選擇:

A.用margin慢慢調        B.用數組把它們排列好        C.放棄

在這道題中,選A是很不明智的,選C就代表你也拿不定主意。看來選B是最好的。既然都告訴大家用數組,那就先上代碼吧。免得消磨大家興致。

js代碼:

  1 /*
  2  *Prompt:
  3  *If you want to add hurdle, find string: "{{Add hurdle above." and "{{After add hurdle, add the hurdle to the vector above." please.
  4  *If you want to add or change type of grid, find string: "{{Add new grid above.".
  5  *If you want to change position of map, please find string: "{{Change map margin above.".
  6  *If the icon of crid is changed, you have to change the size of icon. Find "{{Change icon size above." to change size.
  7 */
  8 
  9 //Map of hurdle or military or resource.
 10 var vView = [];
 11 
 12 /*Remarks:
 13  *L: land *S: sea *R: river *W: swamp *A: lawn *B: bridge *H: house *h: hospital *w: warehouse *b: bourse *M: military academy *m: military factories
 14  *r: research Center *P: port *D: dock *s: Shipyard
 15 */
 16 var mScene = {
 17                 'L': ['./land.png', '陸地']
 18                 , 'S': ['./sea.png', '河流']
 19                 , 'T': ['./tree.png', '樹木']
 20                 , 'B': ['./bridge.png', '橋']
 21                 , 'C': ['./beach.png', '沙灘']
 22             };
 23 //{{Add new grid above.
 24 
 25 var mCurrent = {
 26                     Margin: {
 27                         left: -1
 28                         , top: -1
 29                         , right: -1
 30                         , bottom: -1
 31                     }
 32                     , Position: {
 33                         X: -1
 34                         , Y: -1
 35                     }
 36                     , Type: 'NONE'
 37 
 38                 };
 39 var mTitle = {};
 40 
 41 var sHurdleONE = 
 42         'S,S,S,S,S,S,S,S,S,S,S'
 43         + ';T,L,T,T,T,T,S,S,S,S,T'
 44         + ';T,L,L,T,S,S,S,S,S,L,T'
 45         + ';T,L,L,L,C,C,C,S,S,T,S'
 46         + ';T,L,L,L,C,C,C,B,B,L,T'
 47         + ';T,L,L,C,C,C,C,S,S,L,T'
 48         + ';T,L,L,C,C,T,S,S,L,L,T'
 49         ;
 50 //{{Add hurdle above.
 51 
 52 var vHurdles = [sHurdleONE];
 53 //{{After add hurdle, add the hurdle to the vector above.
 54 
 55 function _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin)
 56 {
 57     var mCoordMember = {
 58                             left: nWidthBasic
 59                             , top: nHeightBasic
 60                             , right: nWidthBasic + nPicWidth
 61                             , bottom: nHeightBasic + nPicHeight
 62                         };
 63     var mPositionMember = {
 64                             X: (mCoordMember.left - mMargin.x) / nPicWidth
 65                             , Y: (mCoordMember.top - mMargin.y) / nPicHeight
 66                         };
 67     var mItem = {
 68                     Coord: mCoordMember
 69                     , Position: mPositionMember
 70                     , Type: cType
 71                 };
 72 
 73     return mItem;
 74 }
 75 
 76 function _loadHurdle(sHurdle)
 77 {
 78     var nBasic = 0;
 79     var nWidthBasic = nBasic;            //margin-left.
 80     var nHeightBasic = 0;                //margin-top.
 81     
 82     //{{Change map margin above.
 83 
 84     var nPicWidth = 45;        //Picture width is nBasic.
 85     var nPicHeight = 45;        //Picturn height is nHeightBasic.
 86     //{{Change icon size above.
 87     
 88     var nSub;
 89     var nRow;
 90     var nCol;
 91 
 92     var v = sHurdle.split(';');
 93     var vRec = [];
 94 
 95     for(nSub = 0; nSub < v.length; nSub++){
 96         var vCrid = v[nSub].split(',');
 97         vRec[vRec.length] = vCrid;
 98     }
 99 
100     for(nRow = 0; nRow < vRec.length; nRow++){
101         var vCol = vRec[nRow];
102 
103         for(nCol = 0; nCol < vCol.length; nCol++){
104             var cType = vCol[nCol];
105             var mMargin = {x: nBasic, y: nBasic};
106 
107             vView[vView.length] = _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin);
108 
109             nWidthBasic += nPicWidth;
110         }
111 
112         nHeightBasic += nPicHeight;
113         nWidthBasic = nBasic;
114     }
115 }
116 
117 
118 
119 //Show map with vector 'vView'.
120 function _showMap(sID)
121 {
122     var xDiv=document.getElementById(sID);
123 
124     var xGrid;
125     var xImg;
126 
127 
128     var nTop = 0;
129 
130     var nSub;
131     var sIdPrefix = 'ID_IMG_NUM_';
132     var sIdGrid = 'ID_A_NUM_';
133     for(nSub = 0; nSub < vView.length; nSub++){
134         var mGrid = vView[nSub];
135 
136         if(mGrid){
137             var xMargin = mGrid.Coord;
138             var cType = mGrid.Type;
139             var xProper = mScene[cType];
140             
141             if(xProper){
142                 xGrid = document.createElement('a');
143                 xImg = document.createElement('img');
144 
145                 xImg.style.position = 'absolute';
146                 xImg.style.marginLeft = xMargin.left;
147                 xImg.style.marginTop = xMargin.top;
148                 
149                 xImg.src = xProper[0];
150 
151                 xImg.style.border = '0px solid #000000';
152                 xImg.id = sIdPrefix + nSub;
153 
154                 xImg.style.width = 45;
155                 xImg.style.height = 45;
156     
157                 xImg.style.display = 'block';
158                 
159                 xGrid.onclick = function(e){
160                     var xCurrentGrid = e.target;
161                     var sId = xCurrentGrid.id;
162                     var nIdAsSub = parseInt(sId.substring(sIdPrefix.length, sId.length));
163 
164                     mCurrent = vView[nIdAsSub];
165                     if(!mCurrent){
166                         alert("Error 0004.");
167                     }
168                 };
169                 xGrid.title = xProper[1] + '(' + parseInt(mGrid.Position.X) + ', ' + parseInt(mGrid.Position.Y+2) + ')';
170                 xGrid.id = sIdGrid + nSub;
171 
172                 xGrid.appendChild(xImg);
173 
174                 xDiv.appendChild(xGrid);
175             }else{
176                 alert("Error: 0003.");
177             }
178         }else{
179             alert("Error: 0002.");
180         }
181     }
182 }
183 
184 //Show map of hurdle.
185 function _showHurdle(nHurdle)
186 {
187     if(vHurdles[nHurdle - 1]){
188         _loadHurdle(vHurdles[nHurdle - 1]);
189         _showMap('ID_DIV_BATTLEFIELD');
190     }else{
191         alert("Error: 0001.");
192     }
193 }
194     
195     

看看,這點程序就用了195行,而且這還是一張地圖,看來還很有點麻煩哦。沒關系,慢慢解釋。

首先還是把素材放在這里,當然也可以去我的相冊下載下來。

tree.png land.png sea.png bridge.png beach.png

素材不是來自《三國志曹操傳》,因為沒整理好《三國志曹操傳》的地圖素材,所以就隨便找了些。不過也照樣可以用。希望大家不要介意。

 

麻煩的代碼最容易弄得亂七八糟,因此在此時要良好的區分開樣式設置和拼圖核心。

拼圖核心在哪里呢???在這里:

 1 var mScene = {
 2                 'L': ['./land.png', '陸地']
 3                 , 'S': ['./sea.png', '河流']
 4                 , 'T': ['./tree.png', '樹木']
 5                 , 'B': ['./bridge.png', '橋']
 6                 , 'C': ['./beach.png', '沙灘']
 7             };
 8 //{{Add new grid above.
 9 
10 var mCurrent = {
11                     Margin: {
12                         left: -1
13                         , top: -1
14                         , right: -1
15                         , bottom: -1
16                     }
17                     , Position: {
18                         X: -1
19                         , Y: -1
20                     }
21                     , Type: 'NONE'
22 
23                 };
24 var mTitle = {};
25 
26 var sHurdleONE = 
27         'S,S,S,S,S,S,S,S,S,S,S'
28         + ';T,L,T,T,T,T,S,S,S,S,T'
29         + ';T,L,L,T,S,S,S,S,S,L,T'
30         + ';T,L,L,L,C,C,C,S,S,T,S'
31         + ';T,L,L,L,C,C,C,B,B,L,T'
32         + ';T,L,L,C,C,C,C,S,S,L,T'
33         + ';T,L,L,C,C,T,S,S,L,L,T'
34         ;
35 //{{Add hurdle above.
36 
37 var vHurdles = [sHurdleONE];
38 //{{After add hurdle, add the hurdle to the vector above.

首先我把S,T,B,C,L定義好,使S代表河流,T代表樹木,B代表橋,C代表沙灘,L代表陸地。var mCurrent后面有用,暫不解釋。然后是var mTitle,這個專門是用來顯示title的,所以也不解釋了。關鍵是在下:

1 var sHurdleONE = 
2         'S,S,S,S,S,S,S,S,S,S,S'
3         + ';T,L,T,T,T,T,S,S,S,S,T'
4         + ';T,L,L,T,S,S,S,S,S,L,T'
5         + ';T,L,L,L,C,C,C,S,S,T,S'
6         + ';T,L,L,L,C,C,C,B,B,L,T'
7         + ';T,L,L,C,C,C,C,S,S,L,T'
8         + ';T,L,L,C,C,T,S,S,L,L,T'
9         ;

這段代碼就是把定義好的S,T,B,C,L連在一起的核心。后面只用定義S,T,B,C,L的寬度高度定義就能把它們連成一塊。並且只要把它們在數組里的位置調一調就能改變樣式。

接下來為了能切換地圖,我們把第一張地圖放進了數組:

1 var vHurdles = [sHurdleONE];
2 //{{After add hurdle, add the hurdle to the vector above.

如果以后加了地圖,只用把地圖所屬的數組名加到vHurdles數組就可以了,調用是就可以直接寫對應下標。

樣式設置在下:

  1 function _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin)
  2 {
  3     var mCoordMember = {
  4                             left: nWidthBasic
  5                             , top: nHeightBasic
  6                             , right: nWidthBasic + nPicWidth
  7                             , bottom: nHeightBasic + nPicHeight
  8                         };
  9     var mPositionMember = {
 10                             X: (mCoordMember.left - mMargin.x) / nPicWidth
 11                             , Y: (mCoordMember.top - mMargin.y) / nPicHeight
 12                         };
 13     var mItem = {
 14                     Coord: mCoordMember
 15                     , Position: mPositionMember
 16                     , Type: cType
 17                 };
 18 
 19     return mItem;
 20 }
 21 
 22 function _loadHurdle(sHurdle)
 23 {
 24     var nBasic = 0;
 25     var nWidthBasic = nBasic;            //margin-left.
 26     var nHeightBasic = 0;                //margin-top.
 27     
 28     //{{Change map margin above.
 29 
 30     var nPicWidth = 45;        //Picture width is nBasic.
 31     var nPicHeight = 45;        //Picturn height is nHeightBasic.
 32     //{{Change icon size above.
 33     
 34     var nSub;
 35     var nRow;
 36     var nCol;
 37 
 38     var v = sHurdle.split(';');
 39     var vRec = [];
 40 
 41     for(nSub = 0; nSub < v.length; nSub++){
 42         var vCrid = v[nSub].split(',');
 43         vRec[vRec.length] = vCrid;
 44     }
 45 
 46     for(nRow = 0; nRow < vRec.length; nRow++){
 47         var vCol = vRec[nRow];
 48 
 49         for(nCol = 0; nCol < vCol.length; nCol++){
 50             var cType = vCol[nCol];
 51             var mMargin = {x: nBasic, y: nBasic};
 52 
 53             vView[vView.length] = _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin);
 54 
 55             nWidthBasic += nPicWidth;
 56         }
 57 
 58         nHeightBasic += nPicHeight;
 59         nWidthBasic = nBasic;
 60     }
 61 }
 62 
 63 
 64 
 65 //Show map with vector 'vView'.
 66 function _showMap(sID)
 67 {
 68     var xDiv=document.getElementById(sID);
 69 
 70     var xGrid;
 71     var xImg;
 72 
 73 
 74     var nTop = 0;
 75 
 76     var nSub;
 77     var sIdPrefix = 'ID_IMG_NUM_';
 78     var sIdGrid = 'ID_A_NUM_';
 79     for(nSub = 0; nSub < vView.length; nSub++){
 80         var mGrid = vView[nSub];
 81 
 82         if(mGrid){
 83             var xMargin = mGrid.Coord;
 84             var cType = mGrid.Type;
 85             var xProper = mScene[cType];
 86             
 87             if(xProper){
 88                 xGrid = document.createElement('a');
 89                 xImg = document.createElement('img');
 90 
 91                 xImg.style.position = 'absolute';
 92                 xImg.style.marginLeft = xMargin.left;
 93                 xImg.style.marginTop = xMargin.top;
 94                 
 95                 xImg.src = xProper[0];
 96 
 97                 xImg.style.border = '0px solid #000000';
 98                 xImg.id = sIdPrefix + nSub;
 99 
100                 xImg.style.width = 45;
101                 xImg.style.height = 45;
102     
103                 xImg.style.display = 'block';
104                 
105                 xGrid.onclick = function(e){
106                     var xCurrentGrid = e.target;
107                     var sId = xCurrentGrid.id;
108                     var nIdAsSub = parseInt(sId.substring(sIdPrefix.length, sId.length));
109 
110                     mCurrent = vView[nIdAsSub];
111                     if(!mCurrent){
112                         alert("Error 0004.");
113                     }
114                 };
115                 xGrid.title = xProper[1] + '(' + parseInt(mGrid.Position.X) + ', ' + parseInt(mGrid.Position.Y+2) + ')';
116                 xGrid.id = sIdGrid + nSub;
117 
118                 xGrid.appendChild(xImg);
119 
120                 xDiv.appendChild(xGrid);
121             }else{
122                 alert("Error: 0003.");
123             }
124         }else{
125             alert("Error: 0002.");
126         }
127     }
128 }

以上的代碼很簡單,自己可以看看,提示一下:當你在自己開發的過程中如果彈出一個Error: 0002, Error: 0003, Error: 0001什么之類的,就代表出了錯,需要馬上去檢查。這是為了在麻煩的程序開發中有一點提醒而設計的。值得注意的是:這里的圖片全是createElement弄出來的,所以請不要猜疑html代碼里有什么蹊蹺。

接着看:

1 function _showHurdle(nHurdle)
2 {
3     if(vHurdles[nHurdle - 1]){
4         _loadHurdle(vHurdles[nHurdle - 1]);
5         _showMap('ID_DIV_BATTLEFIELD');
6     }else{
7         alert("Error: 0001.");
8     }
9 }

這是在你要弄出地圖的調用函數,當你在html代碼里寫上:<body onload="_showHurdle(nHurdle)">幾可以把拼的圖一下子畫出來。nHurdle就是地圖在數組vHurdles里的對應下標,最低是1,而不是0,也就是說要用第一張地圖,那nHurdle就該賦值為1,調用是寫為:<body onload="_showHurdle(1)">。

源代碼下載:http://files.cnblogs.com/ducle/map.rar 

 

三、演示效果

演示圖在下:

由於是靜態的,所以就不給demo了。這種方法雖然很麻煩,而且地圖塊多了就很慢,但是畢竟是種技術,如果大家有什么好的方法也可以來告訴我。

 

希望大家多支持。謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM