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

小时候我们玩过拼图游戏,是用自己的手去拼的。今天我们来研究研究用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行,而且这还是一张地图,看来还很有点麻烦哦。没关系,慢慢解释。
首先还是把素材放在这里:


素材不是来自《三国志曹操传》,因为没整理好《三国志曹操传》的地图素材,所以就随便找了些。不过也照样可以用。希望大家不要介意。

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

复制代码 代码如下:

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

源代码下载
三、演示效果

演示图在下:


由于是静态的,所以就不给demo了。这种方法虽然很麻烦,而且地图块多了就很慢,但是毕竟是种技术,如果大家有什么好的方法也可以来告诉我。

希望大家多支持。谢谢。

时间: 2024-09-30 00:50:47

javascript游戏开发之《三国志曹操传》零部件开发(四)用地图块拼成大地图_javascript技巧的相关文章

javascript游戏开发之《三国志曹操传》零部件开发(三)情景对话中仿打字机输出文字_javascript技巧

前两讲我告诉了大家如何使人物移动,那么今天我们就来看看如何实现仿<三国志曹操传>人物情景对话.具体的链接我写在下方. 一.前言 相信大家都还记得吧,在某些新闻里会有一些惨不忍睹的结果是用像打字机一样的方式把文字弄出来.那么今天的主要目的就是要办到这个. 就在9月5日的时候,我在办公室里起了个做这种程序的念头,并且有了点思路.我首先想用调margin的方法,按理说是作出来了,但很不让人满意,毕竟很麻烦,并且技术也差.所以我打算用上数组和循环.9月13日我抽空写出来了,但由于这几天很忙,基本上在工

javascript游戏开发之《三国志曹操传》零部件开发(一)让静态人物动起来_javascript技巧

首先来说,让一个游戏赋有可玩性必须要动静结合.(哈哈,大家以为我要讲作文了...但其实我今天要讲的是Javascript)静态的东西谁不会做呢?因为东西一生下来就是静态的(除非你是用的gif动画),所以不需要任何处理就能完成静态.那么我将要在下面告诉大家如何运用Javascript将静态图片变为动态图片. 一.图片准备     fight01.pngfight02.pngfight03.pngfight04.png03.png02.png01.png首先,我找了一些出自经典游戏<三国志曹操传>

JavaScript.The.Good.Parts阅读笔记(二)作用域&amp;amp;闭包&amp;amp;减缓全局空间污染_javascript技巧

如代码块 复制代码 代码如下: if (true) { int i = 100; } print(i); //错误,变量i没有声明 如上面例子所示,代码块外的函数是无法访问i变量的. 但在javaScript里,情况则完全不同. 复制代码 代码如下: if (true) { var i = 100; } alert(i); //弹出框并显示100 很多现代语言都推荐尽可能迟地声明变量,但在Javascript里这是一个最糟糕的建议.由于缺少块级作用域,最好在函数体的顶部声明函数中可能用到的所有变

JavaScript中string转换成number介绍_javascript技巧

JavaScript中,可以通过以下3种方法来将string值转换成number: 1.调用Number()来对string进行值类型转换. 2.parseInt(). 3.parseFloat(). Number() 使用Number()函数来对string进行强制类型转换是最直接的做法.不过,这种做法有一个局限性:如果字符串截去开头和结尾的空白字符后,不是纯数字字符串,那么最终返回结果为NaN.David Flanagan的JavaScript – The Definitive Guide

js实现分割上传大文件_javascript技巧

本文实例介绍了js上传文件操作,分享给大家供大家参考,具体内容如下 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN"> &l

JavaScript中通过闭包解决只能取得包含函数中任何变量最后一个值的问题_javascript技巧

复制代码 代码如下: <script type="text/javascript"> function createArray() { var arr = new Array(); for (var i = 0; i < 10; i++) { arr[i] = function () { return i; } } return arr; } var funcs = createArray(); for (var i = 0; i < funcs.length;

JavaScript快速切换繁体中文和简体中文的方法及网站支持简繁体切换的绝招_javascript技巧

一般商业网站都有一个语言的需求,就是为了照顾使用正体中文的国人,会特地提供一个切换到正体中文的选项(或曰"繁体中文").传统做法是在服务端完成的,即通过某些控件或者过滤器转换文本语言.这里笔者介绍一种简单可行的方法,不是在服务端而是利用前端的 JavaScript 就可以切换正体中文. 大概六年前我还专门写过这议题的博文,这篇也是奠基在那篇文章(旧文也是参考了一高手代码)之上,<对 JavaScript 繁简字切换的小改进>.时过境迁,有必要把代码进行更新一下--以前的太稚

JavaScript实现url参数转成json形式_javascript技巧

朋友问的一个面试题:有个url,要求获取url 的参数,返回值为json格式. 简单的写了下,发笔记备份. <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>simple a example for url to json</title> <script> var url = 'https://www.baidu.com/s?ie=u

Javascript表单特效之十大常用原理性样例代码大总结_javascript技巧

案例一:全选等 运用知识点:ondblclick=()| onclick | 寻找标签属性及判断和函数的应用 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> </head> <body> <div> <input type="button" value="