html5 如何实现自动射击,基于HTML5实现的横版射击游戏详解

5268f80b9b1e01f982625ef6fac83ca1.png

功能说明:

基于http://www.gxlcms.com/wiki/1118.html" target="_blank">HTML5的横版射击游戏,参考自flash游戏《双面特工》。左右方向键控制移动,下方向键蹲下,上方向键跳跃,空格键射击。体验前请先关闭输入法。

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

效果预览:

1d09647bbb2b6cc95cf6577d3e5e290e.png

实现分析:

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

};

options = 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; //有多少行

this.width=this.cellSize[0]* mapMatrix[0].length;

this.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;

x = 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;

x = 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;

x = 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){

currentObj.x = currentObj.x || 0;

currentObj.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 newLayer=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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值