javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图


Posted in Javascript onJanuary 23, 2013

小时候我们玩过拼图游戏,是用自己的手去拼的。今天我们来研究研究用javascript来拼图。同样是拼图,但用js拼图要比用手拼图麻烦多了,因此以后我要把它优化成引擎。

一、前言

以上是一段导语,话不扯远,对《三国志曹操传》熟悉的玩家知道,《三国志曹操传》的地图是由小地图块拼成的,那要实现它就和导语说得一样:很麻烦。不过即使麻烦也是一门技术,因此在此分享给大家,希望大家喜欢。

二、代码讲解

今天我要换换讲解方式,先不给代码,我们先来想想原理。现在,假如你有一幅图片,把它裁开成若干份,并打乱。现在如果让你用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行,而且这还是一张地图,看来还很有点麻烦哦。没关系,慢慢解释。
首先还是把素材放在这里:

javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图
素材不是来自《三国志曹操传》,因为没整理好《三国志曹操传》的地图素材,所以就随便找了些。不过也照样可以用。希望大家不要介意。

麻烦的代码最容易弄得乱七八糟,因此在此时要良好的区分开样式设置和拼图核心。
拼图核心在哪里呢?在这里:

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)">。

源代码下载
三、演示效果

演示图在下:

javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图
由于是静态的,所以就不给demo了。这种方法虽然很麻烦,而且地图块多了就很慢,但是毕竟是种技术,如果大家有什么好的方法也可以来告诉我。

希望大家多支持。谢谢。

Javascript 相关文章推荐
javascript之解决IE下不渲染的bug
Jun 29 Javascript
Google韩国首页图标动画效果
Aug 26 Javascript
IE6下拉框图层问题探讨及解决
Jan 03 Javascript
js replace替换所有匹配的字符串
Feb 13 Javascript
html的DOM中document对象images集合用法实例
Jan 21 Javascript
JS日期格式化之javascript Date format
Oct 01 Javascript
史上最全JavaScript数组去重的十种方法(推荐)
Aug 17 Javascript
微信小程序 如何引入外部字体库iconfont的图标
Jan 31 Javascript
JavaScript面向对象程序设计中对象的定义和继承详解
Jul 29 Javascript
layui.tree组件的使用以及搜索节点功能的实现
Sep 26 Javascript
Vue props中Object和Array设置默认值操作
Jul 30 Javascript
vue.js+element 默认提示中英文操作
Nov 11 Javascript
javascript游戏开发之《三国志曹操传》零部件开发(三)情景对话中仿打字机输出文字
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(二)人物行走的实现
Jan 23 #Javascript
javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来
Jan 23 #Javascript
JS判断不同分辨率调用不同的CSS样式文件实现思路及测试代码
Jan 23 #Javascript
jquery实现表格奇数偶数行不同样式(有图为证及实现代码)
Jan 23 #Javascript
jquery多行滚动/向左或向上滚动/响应鼠标实现思路及代码
Jan 23 #Javascript
jquery简单瀑布流实现原理及ie8下测试代码
Jan 23 #Javascript
You might like
zend framework多模块多布局配置
2011/02/26 PHP
PHP彩蛋信息介绍和阻止泄漏的方法(隐藏功能)
2014/08/06 PHP
基于jQuery的可用于选项卡及幻灯的切换插件
2011/03/28 Javascript
jquery 使用点滴函数代码
2011/05/20 Javascript
JS获得选取checkbox整行数据的方法
2015/01/28 Javascript
jQuery实现仿Alipay支付宝首页全屏焦点图切换特效
2015/05/04 Javascript
js设置document.domain实现跨域的注意点分析
2015/05/21 Javascript
浅谈Nodejs观察者模式
2015/10/13 NodeJs
jQuery form插件的使用之处理server返回的JSON, XML,HTML数据
2016/01/26 Javascript
JavaScript:Array类型全面解析
2016/05/19 Javascript
jquery实现网页定位导航
2016/08/23 Javascript
JQuery 动态生成Table表格实例代码
2016/12/02 Javascript
Bootstrap jquery.twbsPagination.js动态页码分页实例代码
2017/02/20 Javascript
vue-cli中的babel配置文件.babelrc实例详解
2018/02/22 Javascript
react-native-video实现视频全屏播放的方法
2018/03/19 Javascript
js实现鼠标单击Tab表单切换效果
2018/05/16 Javascript
JS开发 富文本编辑器TinyMCE详解
2019/07/19 Javascript
vue离开当前页面触发的函数代码
2020/09/01 Javascript
Node.js path模块,获取文件后缀名操作
2020/11/07 Javascript
Python 实现简单的电话本功能
2015/08/09 Python
python复制文件到指定目录的实例
2018/04/27 Python
python中shell执行知识点
2020/05/06 Python
python logging.info在终端没输出的解决
2020/05/12 Python
Original Penguin英国官方网站:美国著名休闲时装品牌
2016/10/30 全球购物
线程问题:wait()方法是定义在哪个类里面
2015/07/07 面试题
表彰先进的通报
2014/01/31 职场文书
普罗米修斯教学反思
2014/02/06 职场文书
股份合作协议书
2014/04/12 职场文书
《槐乡五月》教学反思
2014/04/25 职场文书
个人查摆问题整改措施
2014/10/04 职场文书
带刀到教室的检讨书
2014/10/04 职场文书
地方白酒代理协议书
2014/10/25 职场文书
送达通知书
2015/04/25 职场文书
公司晚宴祝酒词
2015/08/11 职场文书
驾驶员安全责任协议书
2016/03/22 职场文书
HTTP中的Content-type详解
2022/01/18 HTML / CSS