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 相关文章推荐
JS数组的遍历方式for循环与for...in
Jul 31 Javascript
解析Node.js基于模块和包的代码部署方式
Feb 16 Javascript
拥有一个属于自己的javascript表单验证插件
Mar 24 Javascript
Javascript封装id、class与元素选择器方法示例
Mar 13 Javascript
获取url中用&amp;隔开的参数实例(分享)
May 28 Javascript
mui框架 页面无法滚动的解决方法(推荐)
Jan 25 Javascript
vue 实现剪裁图片并上传服务器功能
Mar 01 Javascript
详解Vue.js v-for不支持IE9的解决方法
Dec 29 Javascript
微信小程序如何加载数据库真实数据的实现
Mar 04 Javascript
js实现html滑动图片拼图验证
Jun 24 Javascript
JS前后端实现身份证号验证代码解析
Jul 23 Javascript
js实现表格数据搜索
Aug 09 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
php模板原理讲解
2013/11/13 PHP
php查询及多条件查询
2017/02/26 PHP
JS 文件本身编码转换 图文教程
2009/10/12 Javascript
javascript 获取表单file全路径
2009/12/31 Javascript
js身份证判断方法支持15位和18位
2014/03/18 Javascript
Javascript学习笔记之数组的遍历和 length 属性
2014/11/23 Javascript
详细解密jsonp跨域请求
2015/04/15 Javascript
jquery实现Li滚动时滚动条自动添加样式的方法
2015/08/10 Javascript
jQuery实现无限往下滚动效果代码
2016/04/16 Javascript
JavaScript简单验证表单空值及邮箱格式的方法
2017/01/20 Javascript
微信小程序 Nginx环境配置详细介绍
2017/02/14 Javascript
vue.js异步上传文件前后端实现代码
2017/08/22 Javascript
微信小程序实战篇之购物车的实现代码示例
2017/11/30 Javascript
node简单实现一个更改头像功能的示例
2017/12/29 Javascript
详解vuex中mapState,mapGetters,mapMutations,mapActions的作用
2018/04/13 Javascript
jQuery利用cookie 实现本地收藏功能(不重复无需多次命名)
2019/11/07 jQuery
Vue实现input宽度随文字长度自适应操作
2020/07/29 Javascript
Vue实现穿梭框效果
2020/09/30 Javascript
Python中pygame的mouse鼠标事件用法实例
2015/11/11 Python
Python批量创建迅雷任务及创建多个文件
2016/02/13 Python
利用python修改json文件的value方法
2018/12/31 Python
python检测服务器端口代码实例
2019/08/31 Python
python字符串格式化方式解析
2019/10/19 Python
css3实现顶部社会化分享按钮示例
2014/05/06 HTML / CSS
纯CSS实现设置半个字符的样式
2014/07/03 HTML / CSS
使用CSS3滤镜的filter:blur属性制作毛玻璃模糊效果的方法
2016/07/08 HTML / CSS
德国高性价比网上药店:medpex
2017/07/09 全球购物
高中生毕业自我鉴定范文
2013/12/22 职场文书
党员干部廉洁自律承诺书
2015/04/28 职场文书
党员进社区活动总结
2015/05/07 职场文书
小学运动会入场词
2015/07/18 职场文书
电力安全教育培训心得体会
2016/01/11 职场文书
Ajax实现三级联动效果
2021/10/05 Javascript
Spring 使用注解开发
2022/05/20 Java/Android
HTML5之高度塌陷问题的解决
2022/06/01 HTML / CSS
SpringBoot详解执行过程
2022/07/15 Java/Android