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 相关文章推荐
newxtree.js代码
Mar 13 Javascript
jQuery.autocomplete 支持中文输入(firefox)修正方法
Mar 10 Javascript
jquery 实现checkbox全选,反选,全不选等功能代码(奇数)
Oct 24 Javascript
js的匿名函数使用介绍
Dec 11 Javascript
JavaScript页面实时显示当前时间实例代码
Oct 23 Javascript
详解用vue.js和laravel实现微信授权登陆
Jun 23 Javascript
AugularJS从入门到实践(必看篇)
Jul 10 Javascript
jQuery图片查看插件Magnify开发详解
Dec 25 jQuery
微信小程序实现图片上传放大预览删除代码
Jun 28 Javascript
微信小程序new Date()方法失效问题解决方法
Jul 29 Javascript
微信小程序实现图片翻转效果的实例代码
Sep 20 Javascript
微信小程序点击view动态添加样式过程解析
Jan 21 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 字符串函数收集
2010/03/29 PHP
如何判断php数组的维度
2013/06/10 PHP
php实现微信企业号支付个人的方法详解
2017/07/26 PHP
PHP类与对象后期静态绑定操作实例详解
2018/12/20 PHP
PHP实现提取多维数组指定一列的方法总结
2019/12/04 PHP
jQuery 获取对象 定位子对象
2010/05/31 Javascript
学习从实践开始之jQuery插件开发 菜单插件开发
2012/05/03 Javascript
JavaScript中双叹号!!作用示例介绍
2014/09/21 Javascript
JSON遍历方式实例总结
2015/12/07 Javascript
Javascript基础_嵌入图像的简单实现
2016/06/14 Javascript
JavaScript中Array对象用法实例总结
2016/11/29 Javascript
vue2.0 如何把子组件的数据传给父组件(推荐)
2018/01/15 Javascript
vue.js轮播图组件使用方法详解
2018/07/03 Javascript
vue实现添加与删除图书功能
2018/10/07 Javascript
javascript实现遮罩层动态效果实例
2019/05/14 Javascript
CountUp.js实现数字滚动增值效果
2019/10/17 Javascript
只有 20 行的 JavaScript 模板引擎实例详解
2020/05/11 Javascript
Mac OS X10.9安装的Python2.7升级Python3.3步骤详解
2013/12/04 Python
在Python程序中操作文件之flush()方法的使用教程
2015/05/24 Python
python获取list下标及其值的简单方法
2016/09/12 Python
python实现上传下载文件功能
2020/11/19 Python
Python实现检测文件MD5值的方法示例
2018/04/11 Python
pandas 对group进行聚合的例子
2019/12/27 Python
Python3 Tensorlfow:增加或者减小矩阵维度的实现
2020/05/22 Python
CSS3中的元素过渡属性transition示例详解
2016/11/30 HTML / CSS
可靠的数据流传输TCP
2016/03/15 面试题
党校自我鉴定范文
2013/10/02 职场文书
预防煤气中毒方案
2014/06/16 职场文书
纪念九一八事变演讲稿:忘记意味着背叛
2014/09/14 职场文书
车间统计员岗位职责
2015/04/14 职场文书
2015-2016年小学教导工作总结
2015/07/21 职场文书
物业公司管理制度
2015/08/05 职场文书
pytorch中的model.eval()和BN层的使用
2021/05/22 Python
Spring事务管理下synchronized锁失效问题的解决方法
2022/03/31 Java/Android
docker-compose部署Yapi的方法
2022/04/08 Servers
Vue操作Storage本地化存储
2022/04/29 Vue.js