前面几篇的学习日志中我们学习了canvas的基本用法,那么今天,我们就要运用canvas来开发一个小的益智游戏,什么游戏呢?那就是我们小时候常玩的魔板拼图游戏,在一个M*N的魔板中共有(M*N-1)张小块图片,和一个空白块;我们要利用这个空白块来移动这(M*N-1)张小块图片,使之拼成一张原始的完整的图片。
游戏实例:http://xiaowu.shnow.cn/html5/note4/index.html
接下来就要详细讲解如何利用html5中的canvas来开发这样一个益智小游戏,下面我来简单地讲解一下游戏的开发思路。
1.首先我们来定义游戏中需要用到的一些全局配置变量
//全局配置变量
var kBoardWidth = 4; //横向块数
var kBoardHeight = 5; //纵向块数
var kPieceWidth = 100; //每块的宽度
var kPieceHeight = 100; //每块的高度
var kPixelWidth = 1 + kBoardWidth * kPieceWidth; //游戏视野的宽度
var kPixelHeight = 1 + kBoardHeight * kPieceHeight; //游戏视野的高度
var exchangeTimes = 100; //随机对换次数
var gCanvasElement; //canvas元素节点
var gDrawingContext; //canvas元素的context内容
var gMoveCountElem; //移动步数元素节点
var gMoveCount; //移动次数
var gPieces; //小块图片数组
var gNumPieces; //小块图片的张数
2.利用OOP(面向对象)的方法,创建一个Cell类,Cell类当中包含了每个小块图片的行列和内容信息:
//定义一个cell类,cell类包含了小块图片的信息
function Cell(row,column,index)
{
this.row = row; //行信息
this.column = column; //列信息
this.index = index; //内容信息
}
3.接下来可以开始初始化游戏了。
//初始化游戏
function initGame(canvasElement,moveCountElement)
{
//若canvas元素节点不存在则创建canvas元素节点
if(!canvasElement)
{
canvasElement = document.createElement("canvas");
canvasElement.id = "puzzle";
document.body.appendChild(canvasElement);
}
//若记录步数记录节点不存在则创建步数记录节点
if(!moveCountElement)
{
moveCountElement = document.createElement("p");
document.body.appendChild(moveCountElement);
document.body.appendChild(moveCountElement);
}
//初始化参数
gCanvasElement = canvasElement;
gDrawingContext = gCanvasElement.getContext("2d");
gCanvasElement.width = kPixelWidth;
gCanvasElement.height = kPixelHeight;
gMoveCountElem = moveCountElement;
gMoveCount = 0;
newGame(); //载入新的游戏
//监听按键事件
document.onkeydown=function(e)
{
//key接受到的键盘码,以下写法有更好的跨浏览器兼容性
var key=e.keyCode||e.which||e.charCode;
if(key==38 || key==87) movePiece("up"); //上 或者 W 被按下
if(key==40 || key==83) movePiece("down"); //下 或者 S 被按下
if(key==37 || key==65 ) movePiece("left"); //左 或者 A 被按下
if(key==39 || key==68 ) movePiece("right"); //右 或者 D 被按下
}
}
4.其他函数介绍
//开始新游戏
function newGame()
{
gMoveCount = 0;
gMoveCountElem.innerHTML = gMoveCount;
gPieces = new Array(kBoardWidth*kBoardHeight-1);
for(var i=0; i<kBoardWidth*kBoardHeight-1; i++)
{
var row = parseInt(i/kBoardWidth);
var column = i-row*kBoardWidth;
gPieces[i]=new Cell(row,column,i); //创建小块方格元素
}
//创建最后一个空白图片块,index为-1
gPieces[kBoardWidth*kBoardHeight-1] = new Cell(kBoardHeight-1,kBoardWidth-1,-1); //空白的图片
gNumPieces = gPieces.length;
randExchange(); //随机打乱图片
gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight); //清除canvas原有内容
for(var i=0; i<kBoardWidth*kBoardHeight-1; i++) //绘制图片
drawPiece(gPieces[i]);
drawBoard(); //绘制网格线
}
//随机对换,用于打小块图片的次序
function randExchange()
{
var temp1,temp2,temp3;
for(var i=0; i<exchangeTimes; i++)
{
temp1 = parseInt(kBoardWidth*kBoardHeight*Math.random());
temp2 = parseInt(kBoardWidth*kBoardHeight*Math.random());
//交换两个gPieces[temp1],gPieces[temp2]的位置
temp3 = gPieces[temp1].column;
gPieces[temp1].column = gPieces[temp2].column;
gPieces[temp2].column = temp3;
temp3 = gPieces[temp1].row;
gPieces[temp1].row = gPieces[temp2].row;
gPieces[temp2].row = temp3;
}
}
//绘制网格线
function drawBoard()
{
gDrawingContext.beginPath();
//绘制竖直网格线
for (var x = 0; x <= kPixelWidth; x += kPieceWidth) {
gDrawingContext.moveTo(0.5 + x, 0);
gDrawingContext.lineTo(0.5 + x, kPixelHeight);
}
//绘制水平网格线
for (var y = 0; y <= kPixelHeight; y += kPieceHeight) {
gDrawingContext.moveTo(0, 0.5 + y);
gDrawingContext.lineTo(kPixelWidth, 0.5 + y);
}
//设定样式并且绘制到屏幕上
gDrawingContext.strokeStyle = "#f00";
gDrawingContext.stroke();
}
//绘制图片
function drawPiece(p)
{
var column = p.column;
var row = p.row;
var index = p.index;
var _row = parseInt(index/kBoardWidth);
var _column = index-_row*kBoardWidth;
var sy = _row*kPieceWidth;
var sx = _column*kPieceHeight ;
var dx = column * kPieceWidth;
var dy = row * kPieceHeight;
var pic = document.getElementById("pic"); //获取原图片资源
gDrawingContext.drawImage(pic,sx,sy,kPieceWidth,kPieceHeight,dx,dy,kPieceWidth,kPieceHeight); //截取对应的小块图片,并且绘制到canvas中
}
// 根据键盘事件来移动图片
function movePiece(direction)
{
var emptyPieceNum = kBoardWidth*kBoardHeight-1; //得到空白图片的内容
var validMove = false; //是否为一次有效的移动
//向上移动
if(direction=='up')
if(gPieces[emptyPieceNum].row+1<kBoardHeight)
for(var i=0; i<kBoardWidth*kBoardHeight; i++)
if(gPieces[i].column==gPieces[emptyPieceNum].column && gPieces[i].row==gPieces[emptyPieceNum].row+1)
{
gPieces[i].row-=1;
gPieces[emptyPieceNum].row+=1;
validMove = true;
break;
}
//向下移动
if(direction=='down')
if(gPieces[emptyPieceNum].row-1>=0)
for(var i=0; i<kBoardWidth*kBoardHeight; i++)
if(gPieces[i].column==gPieces[emptyPieceNum].column && gPieces[i].row==gPieces[emptyPieceNum].row-1)
{
gPieces[i].row += 1;
gPieces[emptyPieceNum].row -= 1;
validMove = true;
break;
}
//向左移动
if(direction=='left')
if(gPieces[emptyPieceNum].column+1<kBoardWidth)
for(var i=0; i<kBoardWidth*kBoardHeight; i++)
if(gPieces[i].column==gPieces[emptyPieceNum].column+1 && gPieces[i].row==gPieces[emptyPieceNum].row)
{
gPieces[i].column -=1;
gPieces[emptyPieceNum].column += 1;
validMove = true;
break;
}
//向右移动
if(direction=='right')
if(gPieces[emptyPieceNum].column-1>=0)
for(var i=0; i<kBoardWidth*kBoardHeight; i++)
if(gPieces[i].column==gPieces[emptyPieceNum].column-1 && gPieces[i].row==gPieces[emptyPieceNum].row)
{
gPieces[i].column += 1;
gPieces[emptyPieceNum].column -= 1;
validMove = true;
break;
}
//如果是一次有效的移动,开始真正地移动
if(validMove)
{
//清楚canvas所有内容,开始重新绘制
gDrawingContext.clearRect(0, 0, kPixelWidth, kPixelHeight);
for(var i=0; i<kBoardWidth*kBoardHeight-1; i++)
drawPiece(gPieces[i]);
drawBoard();
gMoveCount++; //移动步数加1
gMoveCountElem.innerHTML = gMoveCount; //修改显示移动步数
}
}
整个游戏的js代码就是这么多了,一共只有不到200多行的代码,我们就实现了一个有趣的益智小游戏。游戏在chrome中运行效果:
当然了,你还可以发挥你的聪明才智把这个游戏做的更好,比如可以增加难度设置,关卡设置等一系列的内容,在这里我只是演示游戏的工作原理,从而来说明html5中的canvas属性是多么的方便和强大。
游戏demo演示地址:http://xiaowu.shnow.cn/html5/note4/index.html