用Javascript開發《三國志曹操傳》-開源講座(四)-用地圖塊拼成大地圖

來源:互聯網
上載者:User

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

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

前幾章的位置:

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

http://blog.csdn.net/yorhomwang/article/details/8008759

用Javascript開發《三國志曹操傳》-開源講座(二)-讓目標人物移動

http://blog.csdn.net/yorhomwang/article/details/8007871

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

http://blog.csdn.net/yorhomwang/article/details/7984576

二、代碼講解

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

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

/*  *Prompt:  *If you want to add hurdle, find string: "{{Add hurdle above." and "{{After add hurdle, add the hurdle to the vector above." please.  *If you want to add or change type of grid, find string: "{{Add new grid above.".  *If you want to change position of map, please find string: "{{Change map margin above.".  *If the icon of crid is changed, you have to change the size of icon. Find "{{Change icon size above." to change size. */  //Map of hurdle or military or resource. var vView = [];  /*Remarks:  *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  *r: research Center *P: port *D: dock *s: Shipyard */ var mScene = {                 'L': ['./land.png', '陸地']                 , 'S': ['./sea.png', '河流']                 , 'T': ['./tree.png', '樹木']                 , 'B': ['./bridge.png', '橋']                 , 'C': ['./beach.png', '沙灘']             }; //{{Add new grid above.  var mCurrent = {                     Margin: {                         left: -1                         , top: -1                         , right: -1                         , bottom: -1                     }                     , Position: {                         X: -1                         , Y: -1                     }                     , Type: 'NONE'                  }; var mTitle = {};  var sHurdleONE =          'S,S,S,S,S,S,S,S,S,S,S'         + ';T,L,T,T,T,T,S,S,S,S,T'         + ';T,L,L,T,S,S,S,S,S,L,T'         + ';T,L,L,L,C,C,C,S,S,T,S'         + ';T,L,L,L,C,C,C,B,B,L,T'         + ';T,L,L,C,C,C,C,S,S,L,T'         + ';T,L,L,C,C,T,S,S,L,L,T'         ; //{{Add hurdle above.  var vHurdles = [sHurdleONE]; //{{After add hurdle, add the hurdle to the vector above.  function _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin) {     var mCoordMember = {                             left: nWidthBasic                             , top: nHeightBasic                             , right: nWidthBasic + nPicWidth                             , bottom: nHeightBasic + nPicHeight                         };     var mPositionMember = {                             X: (mCoordMember.left - mMargin.x) / nPicWidth                             , Y: (mCoordMember.top - mMargin.y) / nPicHeight                         };     var mItem = {                     Coord: mCoordMember                     , Position: mPositionMember                     , Type: cType                 };      return mItem; }  function _loadHurdle(sHurdle) {     var nBasic = 0;     var nWidthBasic = nBasic;            //margin-left.     var nHeightBasic = 0;                //margin-top.          //{{Change map margin above.      var nPicWidth = 45;        //Picture width is nBasic.     var nPicHeight = 45;        //Picturn height is nHeightBasic.     //{{Change icon size above.          var nSub;     var nRow;     var nCol;      var v = sHurdle.split(';');     var vRec = [];      for(nSub = 0; nSub < v.length; nSub++){         var vCrid = v[nSub].split(',');         vRec[vRec.length] = vCrid;     }      for(nRow = 0; nRow < vRec.length; nRow++){         var vCol = vRec[nRow];          for(nCol = 0; nCol < vCol.length; nCol++){             var cType = vCol[nCol];             var mMargin = {x: nBasic, y: nBasic};              vView[vView.length] = _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin);              nWidthBasic += nPicWidth;         }          nHeightBasic += nPicHeight;         nWidthBasic = nBasic;     } }    //Show map with vector 'vView'. function _showMap(sID) {     var xDiv=document.getElementById(sID);      var xGrid;     var xImg;       var nTop = 0;      var nSub;     var sIdPrefix = 'ID_IMG_NUM_';     var sIdGrid = 'ID_A_NUM_';     for(nSub = 0; nSub < vView.length; nSub++){         var mGrid = vView[nSub];          if(mGrid){             var xMargin = mGrid.Coord;             var cType = mGrid.Type;             var xProper = mScene[cType];                          if(xProper){                 xGrid = document.createElement('a');                 xImg = document.createElement('img');                  xImg.style.position = 'absolute';                 xImg.style.marginLeft = xMargin.left;                 xImg.style.marginTop = xMargin.top;                                  xImg.src = xProper[0];                  xImg.style.border = '0px solid #000000';                 xImg.id = sIdPrefix + nSub;                  xImg.style.width = 45;                 xImg.style.height = 45;                      xImg.style.display = 'block';                                  xGrid.onclick = function(e){                     var xCurrentGrid = e.target;                     var sId = xCurrentGrid.id;                     var nIdAsSub = parseInt(sId.substring(sIdPrefix.length, sId.length));                      mCurrent = vView[nIdAsSub];                     if(!mCurrent){                         alert("Error 0004.");                     }                 };                 xGrid.title = xProper[1] + '(' + parseInt(mGrid.Position.X) + ', ' + parseInt(mGrid.Position.Y+2) + ')';                 xGrid.id = sIdGrid + nSub;                  xGrid.appendChild(xImg);                  xDiv.appendChild(xGrid);             }else{                 alert("Error: 0003.");             }         }else{             alert("Error: 0002.");         }     } }  //Show map of hurdle. function _showHurdle(nHurdle) {     if(vHurdles[nHurdle - 1]){         _loadHurdle(vHurdles[nHurdle - 1]);         _showMap('ID_DIV_BATTLEFIELD');     }else{         alert("Error: 0001.");     } }

看看,這點程式就用了195行,而且這還是一張地圖,看來還很有點麻煩哦。沒關係,慢慢解釋。
首先還是把素材放在這裡:

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

素材不是來自《三國志曹操傳》,因為沒整理好《三國志曹操傳》的地圖素材,所以就隨便找了些。不過也照樣可以用。希望大家不要介意。
 
麻煩的代碼最容易弄得亂七八糟,因此在此時要良好的區分開樣式設定和拼圖核心。
拼圖核心在哪裡呢???在這裡:

var mScene = {                 'L': ['./land.png', '陸地']                 , 'S': ['./sea.png', '河流']                 , 'T': ['./tree.png', '樹木']                 , 'B': ['./bridge.png', '橋']                 , 'C': ['./beach.png', '沙灘']             }; //{{Add new grid above.  var mCurrent = {                     Margin: {                         left: -1                         , top: -1                         , right: -1                         , bottom: -1                     }                     , Position: {                         X: -1                         , Y: -1                     }                     , Type: 'NONE'                  }; var mTitle = {};  var sHurdleONE =          'S,S,S,S,S,S,S,S,S,S,S'         + ';T,L,T,T,T,T,S,S,S,S,T'         + ';T,L,L,T,S,S,S,S,S,L,T'         + ';T,L,L,L,C,C,C,S,S,T,S'         + ';T,L,L,L,C,C,C,B,B,L,T'         + ';T,L,L,C,C,C,C,S,S,L,T'         + ';T,L,L,C,C,T,S,S,L,L,T'         ; //{{Add hurdle above.  var vHurdles = [sHurdleONE]; //{{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的,所以也不解釋了。關鍵是在下:

var sHurdleONE =          'S,S,S,S,S,S,S,S,S,S,S'         + ';T,L,T,T,T,T,S,S,S,S,T'         + ';T,L,L,T,S,S,S,S,S,L,T'         + ';T,L,L,L,C,C,C,S,S,T,S'         + ';T,L,L,L,C,C,C,B,B,L,T'         + ';T,L,L,C,C,C,C,S,S,L,T'         + ';T,L,L,C,C,T,S,S,L,L,T'         ;

這段代碼就是把定義好的S,T,B,C,L連在一起的核心。後面只用定義S,T,B,C,L的寬度高度定義就能把它們連成一塊。並且只要把它們在數組裡的位置調一調就能改變樣式。
接下來為了能切換地圖,我們把第一張地圖放進了數組:

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

如果以後加了地圖,只用把地圖所屬的數組名加到vHurdles數組就可以了,調用是就可以直接寫對應下標。
樣式設定在下:

function _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin) {     var mCoordMember = {                             left: nWidthBasic                             , top: nHeightBasic                             , right: nWidthBasic + nPicWidth                             , bottom: nHeightBasic + nPicHeight                         };     var mPositionMember = {                             X: (mCoordMember.left - mMargin.x) / nPicWidth                             , Y: (mCoordMember.top - mMargin.y) / nPicHeight                         };     var mItem = {                     Coord: mCoordMember                     , Position: mPositionMember                     , Type: cType                 };      return mItem; }  function _loadHurdle(sHurdle) {     var nBasic = 0;     var nWidthBasic = nBasic;            //margin-left.     var nHeightBasic = 0;                //margin-top.          //{{Change map margin above.      var nPicWidth = 45;        //Picture width is nBasic.     var nPicHeight = 45;        //Picturn height is nHeightBasic.     //{{Change icon size above.          var nSub;     var nRow;     var nCol;      var v = sHurdle.split(';');     var vRec = [];      for(nSub = 0; nSub < v.length; nSub++){         var vCrid = v[nSub].split(',');         vRec[vRec.length] = vCrid;     }      for(nRow = 0; nRow < vRec.length; nRow++){         var vCol = vRec[nRow];          for(nCol = 0; nCol < vCol.length; nCol++){             var cType = vCol[nCol];             var mMargin = {x: nBasic, y: nBasic};              vView[vView.length] = _createGrid(nWidthBasic, nHeightBasic, nPicWidth, nPicHeight, cType, mMargin);              nWidthBasic += nPicWidth;         }          nHeightBasic += nPicHeight;         nWidthBasic = nBasic;     } }    //Show map with vector 'vView'. function _showMap(sID) {     var xDiv=document.getElementById(sID);      var xGrid;     var xImg;       var nTop = 0;      var nSub;     var sIdPrefix = 'ID_IMG_NUM_';     var sIdGrid = 'ID_A_NUM_';     for(nSub = 0; nSub < vView.length; nSub++){         var mGrid = vView[nSub];          if(mGrid){             var xMargin = mGrid.Coord;             var cType = mGrid.Type;             var xProper = mScene[cType];                          if(xProper){                 xGrid = document.createElement('a');                 xImg = document.createElement('img');                  xImg.style.position = 'absolute';                 xImg.style.marginLeft = xMargin.left;                 xImg.style.marginTop = xMargin.top;                                  xImg.src = xProper[0];                  xImg.style.border = '0px solid #000000';                 xImg.id = sIdPrefix + nSub;                  xImg.style.width = 45;                 xImg.style.height = 45;                      xImg.style.display = 'block';                                  xGrid.onclick = function(e){                     var xCurrentGrid = e.target;                     var sId = xCurrentGrid.id;                     var nIdAsSub = parseInt(sId.substring(sIdPrefix.length, sId.length));                      mCurrent = vView[nIdAsSub];                     if(!mCurrent){                         alert("Error 0004.");                     }                 };                 xGrid.title = xProper[1] + '(' + parseInt(mGrid.Position.X) + ', ' + parseInt(mGrid.Position.Y+2) + ')';                 xGrid.id = sIdGrid + nSub;                  xGrid.appendChild(xImg);                  xDiv.appendChild(xGrid);             }else{                 alert("Error: 0003.");             }         }else{             alert("Error: 0002.");         }     } }

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

function _showHurdle(nHurdle) {     if(vHurdles[nHurdle - 1]){         _loadHurdle(vHurdles[nHurdle - 1]);         _showMap('ID_DIV_BATTLEFIELD');     }else{         alert("Error: 0001.");     } }

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


原始碼下載:http://files.cnblogs.com/ducle/map.rar 


三、示範效果

示範圖在下:


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

----------------------------------------------------------------

歡迎大家轉載我的文章。

轉載請註明:轉自Yorhom's Game Box

歡迎繼續關注我的部落格

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.