基于HTML5的横版射击游戏发布

基于HTML5的横版射击游戏发布

  功能说明:

  基于HTML5的横版射击游戏,参考自flash游戏《双面特工》。左右方向键控制移动,下方向键蹲下,上方向键跳跃,空格键射击。体验前请先关闭输入法。

  该游戏基于自己开发的HTML5游戏框架cnGameJS。

  效果预览:

  

  移步原文预览

  实现分析:

  1.关于多层地图。

  在上一个HTML5游戏《坦克后援队》中,所用的地图只为简单的单层地图,意思是地图中除了石头就是空地,仅仅只有一层的地图。但是这种单层地图具有比较大的局限性,如果需要实现场景类的游戏(例如超级玛丽和上面的游戏),只有一层的地图往往是不够的,因为我们除了游戏主角所站的障碍物外,还有游戏背景等元素(例如后面的墙壁等),因此我们需要为地图对象分层,从而达到多层展示的目的。

  新增的layer对象:

  每个layer对象维护该层的sprite,负责更新和绘制它们,并且可以获取指定坐标在该层的矩阵上的值。layer对象源码如下:

  /**  
          *层对象  
          **/                                 
          var layer = function(id,mapMatrix, options) {  
        
              if (!(this instanceof arguments.callee)) {  
                  return new arguments.callee(id,mapMatrix, options);  
              }  
              this.init(id,mapMatrix, options);  
          }  
  layer.prototype={  
                
              /**  
              *初始化  
              **/  
              init: function(id,mapMatrix,options) {  
                  /**  
                  *默认对象  
                  **/      
                  var defaultObj = {  
                      cellSize: [32, 32],   //方格宽,高  
                      x: 0,                      //layer起始x  
                      y: 0                  //layer起始y  
        
                  };      
  optionsoptions = options || {};  
  options = cg.core.extend(defaultObj, options);  
  this.id=options.id;  
  this.mapMatrix = mapMatrix;  
  this.cellSize = options.cellSize;  
  this.x = options.x;  
  this.y = options.y;  
  this.row = mapMatrix.length; //有多少行  
  thisthis.width=this.cellSize[0]* mapMatrix[0].length;  
  thisthis.height=this.cellSize[1]* this.row;  
  this.spriteList=new cg.SpriteList();//该层上的sprite列表  
  this.imgsReference=options.imgsReference;//图片引用字典:{“1″:{src:”xxx.png”,x:0,y:0},”2″:{src:”xxx.png”,x:1,y:1}}  
  this.zIindex=options.zIndex;  
              },  
              /**  
              *添加sprite  
              **/              
              addSprites:function(sprites){  
                  if (cg.core.isArray(sprites)) {  
                      for (var i = 0, len = sprites.length; i <len; i++) {  
                          arguments.callee.call(this, sprites[i]);  
                      }  
                  }  
                  else{  
                      this.spriteList.add(sprites);  
  sprites.layer=this;  
                  }                  
                    
              },  
              /**  
              *获取特定对象在layer中处于的方格的值  
              **/  
              getPosValue: function(x, y) {  
                  if (cg.core.isObject(x)) {  
  y = x.y;  
  xx = x.x;  
                  }  
                  var isUndefined = cg.core.isUndefined;  
  y = Math.floor(y / this.cellSize[1]);  
  x = Math.floor(x / this.cellSize[0]);  
                  if (!isUndefined(this.mapMatrix[y]) && !isUndefined(this.mapMatrix[y][x])) {  
                      return this.mapMatrix[y][x];  
                  }  
                  return undefined;  
              },  
              /**  
              *获取特定对象在layer中处于的方格索引  
              **/  
              getCurrentIndex: function(x, y) {  
                  if (cg.core.isObject(x)) {  
  y = x.y;  
  xx = x.x;  
                  }  
                  return [Math.floor(x / this.cellSize[0]), Math.floor(y / this.cellSize[1])];  
              },  
              /**  
              *获取特定对象是否刚好与格子重合  
              **/  
              isMatchCell: function(x, y) {  
                  if (cg.core.isObject(x)) {  
  y = x.y;  
  xx = x.x;  
                  }  
                  return (x % this.cellSize[0] == 0) && (y % this.cellSize[1] == 0);  
              },  
              /**  
              *设置layer对应位置的值  
              **/  
              setPosValue: function(x, y, value) {  
                  this.mapMatrix[y][x] = value;  
              },  
              /**  
              *更新层上的sprite列表  
              **/              
              update:function(duration){  
                  this.spriteList.update(duration);  
                    
              },  
              /**  
              *根据layer的矩阵绘制layer和该layer上的所有sprite  
              **/  
              draw: function() {  
                  var mapMatrix = this.mapMatrix;  
                  var beginX = this.x;  
                  var beginY = this.y;  
                  var cellSize = this.cellSize;  
                  var currentRow;  
                  var currentCol  
                  var currentObj;  
                  var row = this.row;  
                  var img;  
                  var col;  
                  for (var i = beginY, ylen = beginY + row * cellSize[1]; i <ylen; i += cellSize[1]) {    //根据地图矩阵,绘制每个方格  
  currentRow = (i – beginY) / cellSize[1];  
  col=mapMatrix[currentRow].length;  
                      for (var j = beginX, xlen = beginX + col * cellSize[0]; j <xlen; j += cellSize[0]) {  
  currentCol = (j – beginX) / cellSize[0];  
  currentObj = this.imgsReference[mapMatrix[currentRow][currentCol]];  
                          if(currentObj){  
  currentObjcurrentObj.x = currentObj.x || 0;  
  currentObjcurrentObj.y = currentObj.y || 0;  
  img = cg.loader.loadedImgs[currentObj.src];  
                              //绘制特定坐标的图像  
                              cg.context.drawImage(img, currentObj.x, currentObj.y, cellSize[0], cellSize[1], j, i, cellSize[0], cellSize[1]);   
                          }  
                      }  
                  }  
                  //更新该layer上所有sprite  
                  this.spriteList.draw();  
        
              }  
          } 

  之后我们可以很方便地创建不同的层,并添加到地图中:

  /*    背景矩阵    */  
  var bgMatrix = [  
                      [1,1,1],  
                      [1,1,1],  
                      [1,1,1]  
                  ];  
  this.map = new cnGame.Map({width:3000,height:3000});  
  var newnewLayer=new cnGame.Layer(“bg”,bgMatrix, { cellSize: [1000, 1000], width: this.map.width, height: this.map.height });  
  newLayer.imgsReference={ “1”: { src: srcObj.bg }};  
  this.map.addLayer(newLayer); 

  2.关于移动场景。 

  在上一次的HTML5《游戏超级玛丽游戏demo》中,我们通过使游戏玩家的移动转换为游戏场景的移动来实现玩家固定,场景移动的效果,但是这种实现方法有比较大的问题,因为它干涉了地图和玩家的xy值的变化,因此会带来很多不便。更好的实现方法是,保持玩家和地图的xy值不变,只改变绘制它们时原点的坐标。

  view对象新增的方法:applyInView:

  applyInView方法的作用是在不改变地图和玩家实际坐标的前提下,在绘制时使view固定,其他游戏元素相对于view移动,实现移动背景的效果。例如,我们需要使玩家相对于view中点固定,该map上的其他所有游戏元素相对于view移动,我们只需要在初始化时:

  this.view=new cnGame.View({map:this.map,x:0,y:0,width:cnGame.width,height:cnGame.height});  
  this.view.centerElem(this.player,true); 

  在绘制时:

  this.view.applyInView(function(){  
              map.draw();          
          }); 

  这样map内所有元素都会相对于view而移动。

  而applyInView的实现原理也非常简单,它只是不断使绘制的原点和view的坐标等长且相反:

  /**  
              *使坐标相对于view  
              **/  
              applyInView:function(func){      
                  cg.context.save();  
                  cg.context.translate(-this.x, -this.y);  
                  func();  
                  cg.context.restore();  
              }, 

  这样无论view的坐标如何变化,view在视觉上始终固定在canvas,其他元素的坐标在视觉上始终相对于view。

  该游戏所有源码下载地址:点击下载

基于HTML5的横版射击游戏发布

相关文章:

你感兴趣的文章:

标签云: