• HTML5学习笔记(4)——运用canvas开发的益智小游戏


      前面几篇的学习日志中我们学习了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

      

  • 相关阅读:
    LyX – The Document Processor
    An HTML5 presentation builder — Read more
    R语言定义
    A Hybrid User and ItemBased Collaborative Filtering with Smoothing on Sparse Data
    RapidMiner
    http://www.rseek.org一个查找R资料的站点
    An HTML5 presentation builder — Read more
    R代码脚本的运行
    data ming with R a book
    A Hybrid User and ItemBased Collaborative Filtering with Smoothing on Sparse Data
  • 原文地址:https://www.cnblogs.com/pgg200/p/2193069.html
Copyright © 2020-2023  润新知