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实现点击链接取消跳转效果的方法
Jan 24 Javascript
Node.js文件操作方法汇总
Mar 22 Javascript
JS button按钮实现submit按钮提交效果
Nov 01 Javascript
10个在JavaScript开发中常遇到的BUG
Dec 18 Javascript
微信小程序地图(map)组件点击(tap)获取经纬度的方法
Jan 10 Javascript
新手快速上手webpack4打包工具的使用详解
Jan 28 Javascript
vue实现拖拽的简单案例 不超出可视区域
Jul 25 Javascript
layui 根据后台数据动态创建下拉框并同时默认选中的实例
Sep 02 Javascript
vuex存取值和映射函数使用说明
Jul 24 Javascript
Vue生命周期activated之返回上一页不重新请求数据操作
Jul 26 Javascript
js实现盒子移动动画效果
Aug 09 Javascript
JavaScript实现网页留言板功能
Nov 23 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合并数组+与array_merge的区别分析
2010/08/01 PHP
php+ajax做仿百度搜索下拉自动提示框(有实例)
2012/08/21 PHP
PHP5下$_SERVER变量不再受magic_quotes_gpc保护的弥补方法
2012/10/31 PHP
PHP中CURL方法curl_setopt()函数的参数分享
2013/01/19 PHP
基于Zookeeper的使用详解
2013/05/02 PHP
Function eregi is deprecated (解决方法)
2013/06/21 PHP
解析php取整的几种方式
2013/06/25 PHP
Yii2.0高级框架数据库增删改查的一些操作
2015/11/16 PHP
PHP注释语法规范与命名规范详解篇
2018/01/21 PHP
php微信扫码支付 php公众号支付
2019/03/24 PHP
基于JQuery的密码强度验证代码
2010/03/01 Javascript
javascript动态添加表格数据行(ASP后台数据库保存例子)
2010/05/08 Javascript
JQuery下的Live方法和$.browser方法使用代码
2010/06/02 Javascript
jQuery中创建实例与原型继承揭秘
2011/12/21 Javascript
JSON.parse()和JSON.stringify()使用介绍
2014/06/20 Javascript
jQuery简单操作cookie的插件实例
2016/01/13 Javascript
jQuery日历插件datepicker用法详解
2016/03/03 Javascript
angular学习之ngRoute路由机制
2017/04/12 Javascript
Angular 4依赖注入学习教程之简介(一)
2017/06/04 Javascript
vue-cli2.9.3 详细教程
2018/04/23 Javascript
vue mint-ui tabbar变组件使用
2018/05/04 Javascript
create-react-app修改为多页面支持的方法
2018/05/17 Javascript
angular 表单验证器验证的同时限制输入的实现
2019/04/11 Javascript
vuejs数据超出单行显示更多,点击展开剩余数据实例
2019/05/05 Javascript
Vue路由守卫之路由独享守卫
2019/09/25 Javascript
JS实现长图上下滚动效果
2020/03/19 Javascript
[02:04]2014DOTA2国际邀请赛 DK一个时代的落幕
2014/07/21 DOTA
利用python爬取散文网的文章实例教程
2017/06/18 Python
python与C互相调用的方法详解
2017/07/14 Python
pytorch查看通道数 维数 尺寸大小方式
2020/05/26 Python
Python基于mediainfo批量重命名图片文件
2020/12/29 Python
Gap中国官网:美式休闲风服饰
2017/02/05 全球购物
设计部经理的岗位职责
2013/11/16 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
2015年公司后勤管理工作总结
2015/05/13 职场文书
一文帮你理解PReact10.5.13源码
2021/04/03 Javascript