`
yorhomwang
  • 浏览: 13102 次
  • 性别: Icon_minigender_1
  • 来自: 成都
最近访客 更多访客>>
szk
文章分类
社区版块
存档分类
最新评论

用Javascript开发《三国志曹操传》-开源讲座(四)-用地图块拼成大地图

 
阅读更多
小时候我们玩过拼图游戏,是用自己的手去拼的。今天我们来研究研究用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

欢迎继续关注我的博客

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics