【CSON原创】HTML5游戏《坦克后援队》发布
2012-02-18 19:22
453 查看
功能描述:
该游戏实质上是坦克大战+推箱子。玩家控制坦克,在与敌人战斗的同时把物资顺利运送到目的地则可顺利过关,共三个关卡。
继上一个HTML5游戏小demo《HTML5超级玛丽游戏demo》后,这次开发的游戏添加了更多元素并增强了可玩性,该游戏同样基于本人开发的HTML5游戏框架cnGameJS。
游戏说明:上下左右方向键控制移动,空格键发射炮弹,推动所有物资箱子(
)到目的地(
),则可过关。
// var wrap=document.getElementById("wrap");
var canvas=document.createElement("canvas");
canvas.id="gameCanvas"
canvas.innerHTML="请使用支持canvas的浏览器查看";
wrap.appendChild(canvas);
/* 开始界面 */
var startLevel={
level:"start",
srcObj:{
startSrc:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_start.png"
}
}
/* 第一关 */
var level1={
level:1,
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_grass.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy1.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png", destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,0,2,2,0,0,0,2,2,0,0,0,1],
[1,0,1,0,0,0,2,0,0,0,4,0,0,0,2,1],
[1,0,1,0,0,0,0,0,2,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,2,0,0,0,0,1,3,0,0,0,1],
[1,0,0,0,0,2,0,2,0,0,1,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:400,enemyBeginY:120,goodsArr:[{x:120,y:200}]}
}
/* 第二关 */
var level2={
level:2,
//游戏资源字典
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_desert2.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy2.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png",
destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],
[1,0,1,1,0,0,0,4,0,0,1,1,0,0,0,1],
[1,3,2,0,0,1,2,0,0,0,0,0,2,0,2,1],
[1,0,2,0,0,0,0,0,2,0,0,2,2,0,0,1],
[1,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1],
[1,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1],
[1,1,1,2,2,1,1,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,2,0,0,0,0,0,0,2,0,0,1],
[1,0,0,0,0,2,0,1,0,0,0,0,2,3,0,1],
[1,0,0,1,0,0,2,2,0,0,0,0,2,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:280,enemyBeginY:80,goodsArr:[{x:120,y:320},{x:400,y:120}]}
}
/* 第三关 */
var level3={
level:3,
//游戏资源字典
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_desert.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy3.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png",
destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,3,1,0,0,0,0,0,0,0,2,2,0,0,1],
[1,0,0,2,0,0,0,0,0,0,1,2,3,0,0,1],
[1,0,2,2,0,1,2,0,0,0,0,0,2,1,1,1],
[1,0,2,0,0,1,0,0,2,0,0,2,2,0,0,1],
[1,0,2,2,0,0,2,0,0,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,0,0,1,0,0,0,0,1],
[1,1,1,2,2,0,0,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1],
[1,0,0,0,0,0,4,1,0,2,0,0,2,0,0,1],
[1,0,0,1,0,0,2,2,0,2,3,0,2,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:240,enemyBeginY:360,goodsArr:[{x:520,y:360},{x:520,y:200},{x:240,y:160}]}
}
/* 关卡管理器 */
var LevelManager=(function(){
var optionsObj={};//所有关卡参数对象
return {
add:function(levelObj,gameObj){
var srcArr=[];
for(name in levelObj.srcObj){
if(levelObj.srcObj.hasOwnProperty(name)){
srcArr.push(levelObj.srcObj[name]);
}
}
var opt=optionsObj[levelObj.level]={};
opt.gameObj=gameObj;
opt.srcArray=srcArr;
opt.startOptions=levelObj.startOptions||{};
opt.startOptions.mapMatrix=levelObj.mapMatrix;
opt.startOptions.srcObj=levelObj.srcObj;
opt.startOptions.level=levelObj.level;
},
startLevel:function(num){
var op=optionsObj[num];
cnGame.loader.start(op.gameObj,op);
}
}
})();
cnGame.init("gameCanvas",{width:640,height:480});//初始化游戏框架
var srcObj;
/* 玩家对象 */
var player=function(options){
this.init(options);
this.angle=0;//旋转角
this.rSpeed=8;
this.moveSpeed=5;
this.shootDuration=0.2;
this.shootLast=0;
};
cnGame.core.inherit(player,cnGame.Sprite);
/* 判断是否可以向某方向移动 */
var canRight=function(obj,map){
var posValue=map.getPosValue(obj.x+obj.width,obj.y);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x+obj.width,obj.y,map);
}
var canLeft=function(obj,map){
var posValue=map.getPosValue(obj.x-obj.moveSpeed,obj.y);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x-obj.moveSpeed,obj.y,map);
}
var canUp=function(obj,map){
var posValue=map.getPosValue(obj.x,obj.y-obj.moveSpeed);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x,obj.y-obj.moveSpeed,map);
}
var canDown=function(obj,map){
var posValue=map.getPosValue(obj.x,obj.y+obj.height);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x,obj.y+obj.height,map)
}
/* 判断朝向是否为某方向 */
var isToRight=function(obj){
return obj.angle==0||obj.angle==360;
}
var isToLeft=function(obj){
return obj.angle==180||obj.angle==-180;
}
var isToUp=function(obj){
return obj.angle==90||obj.angle==-270;
}
var isToDown=function(obj){
return obj.angle==-90||obj.angle==270;
}
/* 判断是那种类型的游戏对象 */
var isEnemy=function(obj){
return obj instanceof enemy;
}
var isGoods=function(obj){
return obj instanceof goods;
}
var isBullet=function(obj){
return obj instanceof bullet;
}
var isPlayer=function(obj){
return obj instanceof player;
}
/* 判断对象是否在地图内 */
var isInnerMap=function(obj){
return obj.x>=0&&obj.x<=cnGame.width-obj[i].width&&obj[i].y>=0&&obj[i].y<=cnGame.height-obj[i].height;
}
/* 设置以一定角速度旋转 */
var rotateToAngle=function(obj,angle){
if(!obj){
return;
}
if(obj.angle-angle<-180){
angle=angle-360;
}
else if(obj.angle-angle>180){
if(angle!=0){
angle=360-angle;
}
else{
angle=360;
}
}
if(obj.angle>angle){
obj.rotateSpeed=-obj.rSpeed;
obj.minAngle=angle;
}
else if(obj.angle=this.shootDuration){
if(Math.floor(this.x)==Math.floor(player.x)){//和玩家处于同一列格子
if((this.y>player.y&&(isToUp(this)))||(this.yplayer.x&&(isToLeft(this)))||(this.x_player.shootDuration){
shoot(_player,"player");
_player.shootLast=0;
}
}
_player.shootLast+=duration;
for(var i=0,len=_goodsArr.length;i_goods.y){
if(canUp(_goods,_map)){
_goods.speedY=_player.speedY;
}
else{
_goods.speedY=_player.speedY=0;
}
}
if(isToDown(_player)&&_player.y<_goods.y){
if(canDown(_goods,_map)){
_goods.speedY=_player.speedY;
}
else{
_goods.speedY=_player.speedY=0;
}
}
}
if(_player.y==_goods.y){
if(isToRight(_player)&&_player.x<_goods.x){
if(canRight(_goods,_map)){
_goods.speedX=_player.speedX;
}
else{
_goods.speedX=_player.speedX=0;
}
}
if(isToLeft(_player)&&_player.x>_goods.x){
if(canLeft(_goods,_map)){
_goods.speedX=_player.speedX;
}
else{
_goods.speedX=_player.speedX=0;
}
}
}
}
}
//遍历数组,更新sprite
for(var i=0,len=list.length;i=this.changeEnemyDirDuration){
list[i].getRandomDir(dirArr);
changeDirLast=0;
}
else{
changeDirLast+=duration;
}
detectMove(list[i],list[i].enemyDirection,this.map,dirArr);//敌人定时改变移动方向
}
else if(isBullet(list[i])&&!list[i].isExploding){//如果是还没爆炸的子弹,判别击中的目标
/* 击中石头或围墙 */
if(posValue=_map.getPosValue(list[i].x,list[i].y)){//如果还在地图内(有对应格子值)
if(posValue==2||posValue==1){
if(posValue==2){
currentIndex=_map.getCurrentIndex(list[i].x,list[i].y);
_map.setPosValue(currentIndex[0],currentIndex[1],0);//如果击中石头,把石头变成空地
}
list[i].explode();//子弹爆炸
continue;
}
}
/* 击中goods或player或enemy */
for(var j=0;j=this.createEnemyDuraton){//如果超过时间间隔,则创建敌人
if(!isMoveCollision({},this.enemyBeginX,this.enemyBeginY,this.map)){
var newEnemy=new enemy({src:srcObj.enemy,width:40,height:40,x:this.enemyBeginX,y:this.enemyBeginY});
newEnemy.getRandomDir(dirArr);
cnGame.spriteList.add(newEnemy);
createEnemyLast=0;
}
}
else{
createEnemyLast+=duration;
}
this.cleanBullets();//清除已爆炸的子弹
},
/* 画出地图 */
draw:function(){
if(this.map){
this.map.draw({"0":{src:srcObj.ground},"1":{src:srcObj.wall},"2":{src:srcObj.stone},"3":{src:srcObj.destination},"4":{src:srcObj.source}}); }
},
/* 结束游戏 */
end:function(){
cnGame.loop.end();
}
}
})();
/* 开始界面对象 */
var startObj={
initialize:function(options){debugger;
var name="HTML5坦克后援队";
var author="by Cson";
var begin="按回车键开始";
var state1="游戏说明:方向键上下左右控制坦克的移动,空格键发射炮弹。";
var state2="把所有物资顺利推送到目的地则可完成任务进入下一关。";
this.startSrc=options.srcObj.startSrc;
this.text1=cnGame.shape.Text(name,{x:20,y:250,style:"#FFF",font:"bold 22px sans-serif"});
this.text2=cnGame.shape.Text(author,{x:145,y:280,style:"#FFF",font:"15px sans-serif"});
this.text3=cnGame.shape.Text(begin,{x:40,y:340,style:"#FFF",font:"bold 32px sans-serif"});
this.text4=cnGame.shape.Text(state1,{x:40,y:410,style:"#FFF",font:"bold 15px sans-serif"});
this.text5=cnGame.shape.Text(state2,{x:120,y:430,style:"#FFF",font:"bold 15px sans-serif"});
cnGame.input.onKeyDown("enter",function(){LevelManager.startLevel("1");/*开始第一关*/});
cnGame.input.preventDefault("enter");
},
draw:function(){
cnGame.context.drawImage(cnGame.loader.loadedImgs[this.startSrc],0,0,cnGame.width,cnGame.height);//画出开始界面
this.text1.draw();
this.text2.draw();
this.text3.draw();
this.text4.draw();
this.text5.draw();
}
}
LevelManager.add(startLevel,startObj);
LevelManager.add(level1,gameObj);
LevelManager.add(level2,gameObj);
LevelManager.add(level3,gameObj);
LevelManager.startLevel("start");//开始界面
// ]]>
代码分析:
由于该游戏分了几个关卡,所以这里首先来看看关卡管理器是如果管理各个关卡的:
在初始化阶段,我们首先创建自己的每个关卡的对象,然后调用add方法添加进关卡管理器,之后就可以调用startLevel开始该关卡。这样就可以方便我们之后在每个关卡中的跳转。另外每个关卡所用到的游戏对象也可以在这里传入。在该游戏中,由于每个关卡游戏的逻辑基本相同,因此使用相同的游戏对象。而该游戏的开始界面则使用另一个游戏对象。每个游戏对象的组织形式如下:
之后看看游戏对象gameObj具体的的初始化函数:
初始化函数中,我们需要初始化的参数有:地图对象,物资数组,玩家对象,还有敌人对象。地图对象可以使用cnGameJS的map,而玩家和敌人对象则继承cnGameJS的sprite。
在每次gameObj的update中,我们需要判断是否所有物资对象已经就位,如果是,则可以跳入下一关。
另外,在每次update 中,还需要判断子弹是否击中敌人,击中玩家,或物资:
如果击中的是敌人或玩家,则把对应对象从spriteList里删除,这样下次就不会更新和绘制该对象。另外每次子弹击中物体,就产生一个spriteSheet的爆炸动画:
该动画的spriteSheet图片如下:
生成的动画其实就是每次从不同位置开始把该图片绘制在canvas上,关于spriteSheet动画详情请看:《HTML5游戏框架cnGameJS开发实录:动画篇》。
另外,不同于上次的游戏超级玛丽,该游戏属于地图型。因此在游戏开始阶段就需要设计地图并绘制。地图通过二维矩阵生成,例如第一关的游戏地图对应的二维矩阵如下:
关于cnGameJS中的map对象如何生成地图,并提供常用接口,可参考该文章:《HTML5游戏框架cnGameJS开发实录(地图篇)》
cnGameJS游戏框架以及游戏源码下载:点击这里
PS:部分图片来自《坦克大战online》。
欢迎转载,请标明出处:/article/5223745.html
该游戏实质上是坦克大战+推箱子。玩家控制坦克,在与敌人战斗的同时把物资顺利运送到目的地则可顺利过关,共三个关卡。
继上一个HTML5游戏小demo《HTML5超级玛丽游戏demo》后,这次开发的游戏添加了更多元素并增强了可玩性,该游戏同样基于本人开发的HTML5游戏框架cnGameJS。
游戏说明:上下左右方向键控制移动,空格键发射炮弹,推动所有物资箱子(
)到目的地(
),则可过关。
// var wrap=document.getElementById("wrap");
var canvas=document.createElement("canvas");
canvas.id="gameCanvas"
canvas.innerHTML="请使用支持canvas的浏览器查看";
wrap.appendChild(canvas);
/* 开始界面 */
var startLevel={
level:"start",
srcObj:{
startSrc:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_start.png"
}
}
/* 第一关 */
var level1={
level:1,
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_grass.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy1.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png", destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,0,1,0,0,2,2,0,0,0,2,2,0,0,0,1],
[1,0,1,0,0,0,2,0,0,0,4,0,0,0,2,1],
[1,0,1,0,0,0,0,0,2,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1],
[1,1,1,1,1,1,1,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,2,0,0,0,0,1,3,0,0,0,1],
[1,0,0,0,0,2,0,2,0,0,1,0,0,0,0,1],
[1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:400,enemyBeginY:120,goodsArr:[{x:120,y:200}]}
}
/* 第二关 */
var level2={
level:2,
//游戏资源字典
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_desert2.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy2.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png",
destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1],
[1,0,1,1,0,0,0,4,0,0,1,1,0,0,0,1],
[1,3,2,0,0,1,2,0,0,0,0,0,2,0,2,1],
[1,0,2,0,0,0,0,0,2,0,0,2,2,0,0,1],
[1,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1],
[1,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1],
[1,1,1,2,2,1,1,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,2,0,0,0,0,0,0,2,0,0,1],
[1,0,0,0,0,2,0,1,0,0,0,0,2,3,0,1],
[1,0,0,1,0,0,2,2,0,0,0,0,2,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:280,enemyBeginY:80,goodsArr:[{x:120,y:320},{x:400,y:120}]}
}
/* 第三关 */
var level3={
level:3,
//游戏资源字典
srcObj:{
ground:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_desert.png",
stone:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_stone1.png",
wall:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_wall.png",
player:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_player1.png",
bullet:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_bullet1.png",
enemy:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_enemy3.png",
goods:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_goods.png",
destination:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_destination.png",
boom:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_boom.png",
source:"http://images.cnblogs.com/cnblogs_com/Cson/290336/o_source.png"
},
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/
mapMatrix:[
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,0,3,1,0,0,0,0,0,0,0,2,2,0,0,1],
[1,0,0,2,0,0,0,0,0,0,1,2,3,0,0,1],
[1,0,2,2,0,1,2,0,0,0,0,0,2,1,1,1],
[1,0,2,0,0,1,0,0,2,0,0,2,2,0,0,1],
[1,0,2,2,0,0,2,0,0,0,0,0,0,0,0,1],
[1,0,2,0,0,0,0,0,0,0,1,0,0,0,0,1],
[1,1,1,2,2,0,0,0,0,0,1,1,1,2,2,1],
[1,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1],
[1,0,0,0,0,0,4,1,0,2,0,0,2,0,0,1],
[1,0,0,1,0,0,2,2,0,2,3,0,2,0,0,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
],
startOptions:{enemyBeginX:240,enemyBeginY:360,goodsArr:[{x:520,y:360},{x:520,y:200},{x:240,y:160}]}
}
/* 关卡管理器 */
var LevelManager=(function(){
var optionsObj={};//所有关卡参数对象
return {
add:function(levelObj,gameObj){
var srcArr=[];
for(name in levelObj.srcObj){
if(levelObj.srcObj.hasOwnProperty(name)){
srcArr.push(levelObj.srcObj[name]);
}
}
var opt=optionsObj[levelObj.level]={};
opt.gameObj=gameObj;
opt.srcArray=srcArr;
opt.startOptions=levelObj.startOptions||{};
opt.startOptions.mapMatrix=levelObj.mapMatrix;
opt.startOptions.srcObj=levelObj.srcObj;
opt.startOptions.level=levelObj.level;
},
startLevel:function(num){
var op=optionsObj[num];
cnGame.loader.start(op.gameObj,op);
}
}
})();
cnGame.init("gameCanvas",{width:640,height:480});//初始化游戏框架
var srcObj;
/* 玩家对象 */
var player=function(options){
this.init(options);
this.angle=0;//旋转角
this.rSpeed=8;
this.moveSpeed=5;
this.shootDuration=0.2;
this.shootLast=0;
};
cnGame.core.inherit(player,cnGame.Sprite);
/* 判断是否可以向某方向移动 */
var canRight=function(obj,map){
var posValue=map.getPosValue(obj.x+obj.width,obj.y);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x+obj.width,obj.y,map);
}
var canLeft=function(obj,map){
var posValue=map.getPosValue(obj.x-obj.moveSpeed,obj.y);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x-obj.moveSpeed,obj.y,map);
}
var canUp=function(obj,map){
var posValue=map.getPosValue(obj.x,obj.y-obj.moveSpeed);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x,obj.y-obj.moveSpeed,map);
}
var canDown=function(obj,map){
var posValue=map.getPosValue(obj.x,obj.y+obj.height);
return (posValue==0||posValue==3||posValue==4)&&!isMoveCollision(obj,obj.x,obj.y+obj.height,map)
}
/* 判断朝向是否为某方向 */
var isToRight=function(obj){
return obj.angle==0||obj.angle==360;
}
var isToLeft=function(obj){
return obj.angle==180||obj.angle==-180;
}
var isToUp=function(obj){
return obj.angle==90||obj.angle==-270;
}
var isToDown=function(obj){
return obj.angle==-90||obj.angle==270;
}
/* 判断是那种类型的游戏对象 */
var isEnemy=function(obj){
return obj instanceof enemy;
}
var isGoods=function(obj){
return obj instanceof goods;
}
var isBullet=function(obj){
return obj instanceof bullet;
}
var isPlayer=function(obj){
return obj instanceof player;
}
/* 判断对象是否在地图内 */
var isInnerMap=function(obj){
return obj.x>=0&&obj.x<=cnGame.width-obj[i].width&&obj[i].y>=0&&obj[i].y<=cnGame.height-obj[i].height;
}
/* 设置以一定角速度旋转 */
var rotateToAngle=function(obj,angle){
if(!obj){
return;
}
if(obj.angle-angle<-180){
angle=angle-360;
}
else if(obj.angle-angle>180){
if(angle!=0){
angle=360-angle;
}
else{
angle=360;
}
}
if(obj.angle>angle){
obj.rotateSpeed=-obj.rSpeed;
obj.minAngle=angle;
}
else if(obj.angle=this.shootDuration){
if(Math.floor(this.x)==Math.floor(player.x)){//和玩家处于同一列格子
if((this.y>player.y&&(isToUp(this)))||(this.yplayer.x&&(isToLeft(this)))||(this.x_player.shootDuration){
shoot(_player,"player");
_player.shootLast=0;
}
}
_player.shootLast+=duration;
for(var i=0,len=_goodsArr.length;i_goods.y){
if(canUp(_goods,_map)){
_goods.speedY=_player.speedY;
}
else{
_goods.speedY=_player.speedY=0;
}
}
if(isToDown(_player)&&_player.y<_goods.y){
if(canDown(_goods,_map)){
_goods.speedY=_player.speedY;
}
else{
_goods.speedY=_player.speedY=0;
}
}
}
if(_player.y==_goods.y){
if(isToRight(_player)&&_player.x<_goods.x){
if(canRight(_goods,_map)){
_goods.speedX=_player.speedX;
}
else{
_goods.speedX=_player.speedX=0;
}
}
if(isToLeft(_player)&&_player.x>_goods.x){
if(canLeft(_goods,_map)){
_goods.speedX=_player.speedX;
}
else{
_goods.speedX=_player.speedX=0;
}
}
}
}
}
//遍历数组,更新sprite
for(var i=0,len=list.length;i=this.changeEnemyDirDuration){
list[i].getRandomDir(dirArr);
changeDirLast=0;
}
else{
changeDirLast+=duration;
}
detectMove(list[i],list[i].enemyDirection,this.map,dirArr);//敌人定时改变移动方向
}
else if(isBullet(list[i])&&!list[i].isExploding){//如果是还没爆炸的子弹,判别击中的目标
/* 击中石头或围墙 */
if(posValue=_map.getPosValue(list[i].x,list[i].y)){//如果还在地图内(有对应格子值)
if(posValue==2||posValue==1){
if(posValue==2){
currentIndex=_map.getCurrentIndex(list[i].x,list[i].y);
_map.setPosValue(currentIndex[0],currentIndex[1],0);//如果击中石头,把石头变成空地
}
list[i].explode();//子弹爆炸
continue;
}
}
/* 击中goods或player或enemy */
for(var j=0;j=this.createEnemyDuraton){//如果超过时间间隔,则创建敌人
if(!isMoveCollision({},this.enemyBeginX,this.enemyBeginY,this.map)){
var newEnemy=new enemy({src:srcObj.enemy,width:40,height:40,x:this.enemyBeginX,y:this.enemyBeginY});
newEnemy.getRandomDir(dirArr);
cnGame.spriteList.add(newEnemy);
createEnemyLast=0;
}
}
else{
createEnemyLast+=duration;
}
this.cleanBullets();//清除已爆炸的子弹
},
/* 画出地图 */
draw:function(){
if(this.map){
this.map.draw({"0":{src:srcObj.ground},"1":{src:srcObj.wall},"2":{src:srcObj.stone},"3":{src:srcObj.destination},"4":{src:srcObj.source}}); }
},
/* 结束游戏 */
end:function(){
cnGame.loop.end();
}
}
})();
/* 开始界面对象 */
var startObj={
initialize:function(options){debugger;
var name="HTML5坦克后援队";
var author="by Cson";
var begin="按回车键开始";
var state1="游戏说明:方向键上下左右控制坦克的移动,空格键发射炮弹。";
var state2="把所有物资顺利推送到目的地则可完成任务进入下一关。";
this.startSrc=options.srcObj.startSrc;
this.text1=cnGame.shape.Text(name,{x:20,y:250,style:"#FFF",font:"bold 22px sans-serif"});
this.text2=cnGame.shape.Text(author,{x:145,y:280,style:"#FFF",font:"15px sans-serif"});
this.text3=cnGame.shape.Text(begin,{x:40,y:340,style:"#FFF",font:"bold 32px sans-serif"});
this.text4=cnGame.shape.Text(state1,{x:40,y:410,style:"#FFF",font:"bold 15px sans-serif"});
this.text5=cnGame.shape.Text(state2,{x:120,y:430,style:"#FFF",font:"bold 15px sans-serif"});
cnGame.input.onKeyDown("enter",function(){LevelManager.startLevel("1");/*开始第一关*/});
cnGame.input.preventDefault("enter");
},
draw:function(){
cnGame.context.drawImage(cnGame.loader.loadedImgs[this.startSrc],0,0,cnGame.width,cnGame.height);//画出开始界面
this.text1.draw();
this.text2.draw();
this.text3.draw();
this.text4.draw();
this.text5.draw();
}
}
LevelManager.add(startLevel,startObj);
LevelManager.add(level1,gameObj);
LevelManager.add(level2,gameObj);
LevelManager.add(level3,gameObj);
LevelManager.startLevel("start");//开始界面
// ]]>
代码分析:
由于该游戏分了几个关卡,所以这里首先来看看关卡管理器是如果管理各个关卡的:
/* 关卡管理器 */ var LevelManager=(function(){ var optionsObj={};//所有关卡参数对象 return { add:function(levelObj,gameObj){ var srcArr=[]; for(name in levelObj.srcObj){ if(levelObj.srcObj.hasOwnProperty(name)){ srcArr.push(levelObj.srcObj[name]); } } var opt=optionsObj[levelObj.level]={}; opt.gameObj=gameObj; opt.srcArray=srcArr; opt.startOptions=levelObj.startOptions||{}; opt.startOptions.mapMatrix=levelObj.mapMatrix; opt.startOptions.srcObj=levelObj.srcObj; opt.startOptions.level=levelObj.level; }, startLevel:function(num){ var op=optionsObj[num]; cnGame.loader.start(op.gameObj,op); } } })();
在初始化阶段,我们首先创建自己的每个关卡的对象,然后调用add方法添加进关卡管理器,之后就可以调用startLevel开始该关卡。这样就可以方便我们之后在每个关卡中的跳转。另外每个关卡所用到的游戏对象也可以在这里传入。在该游戏中,由于每个关卡游戏的逻辑基本相同,因此使用相同的游戏对象。而该游戏的开始界面则使用另一个游戏对象。每个游戏对象的组织形式如下:
var gameObj={ initialize:function(options){//初始化 }, update:function(){//更新 }, draw:function(){//绘制 } }
之后看看游戏对象gameObj具体的的初始化函数:
/* 初始化 */ initialize:function(options){ srcObj=options.srcObj; this.level=options.level; this.enemyBeginX=options.enemyBeginX; this.enemyBeginY=options.enemyBeginY; this.map=new cnGame.Map(options.mapMatrix,{cellSize:[40,40]}); this.goods=[]; cnGame.input.preventDefault(["left","right","up","down"]); for(var i=0,len=options.goodsArr.length;i<len;i++){ this.goods.push(new goods({src:srcObj.goods,width:40,height:40,x:options.goodsArr[i].x,y:options.goodsArr[i].y})); cnGame.spriteList.add(this.goods[this.goods.length-1]); } this.player=new player({src:srcObj.player,width:40,height:40,x:40,y:cnGame.height-80}); cnGame.spriteList.add(this.player); var newEnemy=new enemy({src:srcObj.enemy,width:40,height:40,x:this.enemyBeginX,y:this.enemyBeginY}); newEnemy.getRandomDir(dirArr); cnGame.spriteList.add(newEnemy); }
初始化函数中,我们需要初始化的参数有:地图对象,物资数组,玩家对象,还有敌人对象。地图对象可以使用cnGameJS的map,而玩家和敌人对象则继承cnGameJS的sprite。
在每次gameObj的update中,我们需要判断是否所有物资对象已经就位,如果是,则可以跳入下一关。
if(_map.isMatchCell(_goods)&&(_map.getPosValue(_goods)==3)){//判断所有物资是否已到达目的地 finishedNum+=1; if(finishedNum==_goodsArr.length){ this.toNextLevel(); } }
另外,在每次update 中,还需要判断子弹是否击中敌人,击中玩家,或物资:
if(isGoods(list[j])||(isEnemy(list[j])&&list[i].from=="player")||(isPlayer(list[j])&&list[i].from=="enemy")){}
如果击中的是敌人或玩家,则把对应对象从spriteList里删除,这样下次就不会更新和绘制该对象。另外每次子弹击中物体,就产生一个spriteSheet的爆炸动画:
/* 击中后的爆炸动画效果 */ bullet.prototype.explode=function(){ var self=this; this.isExploding=true; var spriteSheet=new cnGame.SpriteSheet("boom",srcObj.boom,{width:280,height:40,frameSize:[40,40],frameDuration:40,onFinish:function(){self.isDisappear=true}}); this.setCurrentAnimation(spriteSheet); this.speedX=0; this.speedY=0; }
该动画的spriteSheet图片如下:
生成的动画其实就是每次从不同位置开始把该图片绘制在canvas上,关于spriteSheet动画详情请看:《HTML5游戏框架cnGameJS开发实录:动画篇》。
另外,不同于上次的游戏超级玛丽,该游戏属于地图型。因此在游戏开始阶段就需要设计地图并绘制。地图通过二维矩阵生成,例如第一关的游戏地图对应的二维矩阵如下:
/* 地图矩阵:0.空地 1.墙壁 2.石头 3.目的地 4.敌人基地*/ mapMatrix:[ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,0,1,0,0,2,2,0,0,0,2,2,0,0,0,1], [1,0,1,0,0,0,2,0,0,0,4,0,0,0,2,1], [1,0,1,0,0,0,0,0,2,0,0,0,0,0,0,1], [1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,1], [1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,1,1,1,1,1,1,0,0,0,1,1,1,2,2,1], [1,0,0,0,0,2,0,0,0,0,1,3,0,0,0,1], [1,0,0,0,0,2,0,2,0,0,1,0,0,0,0,1], [1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] ]
关于cnGameJS中的map对象如何生成地图,并提供常用接口,可参考该文章:《HTML5游戏框架cnGameJS开发实录(地图篇)》
cnGameJS游戏框架以及游戏源码下载:点击这里
PS:部分图片来自《坦克大战online》。
欢迎转载,请标明出处:/article/5223745.html
相关文章推荐
- 【CSON原创】HTML5第一人称射击游戏发布
- 【CSON原创】基于HTML5的横版射击游戏发布
- 【CSON原创】HTML5字体动态粒子效果发布
- 【CSON原创】HTML5游戏框架cnGameJS开发实录
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(核心函数模块篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(资源加载模块篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(游戏场景对象)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(基本图形模块篇)
- 【CSON原创】A*算法+HTML5实现游戏寻路
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(外部输入模块篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(碰撞检测模块篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(动画篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(精灵对象篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(游戏循环篇)
- 【CSON原创】HTML5游戏框架cnGameJS开发实录(游戏地图对象篇)
- HTML5开源游戏引擎lufylegend1.8.0发布
- 首届HTML5原创游戏大赛将于6月10日拉开序幕
- 发布HTML5 2D游戏引擎YEngine2D
- GameSalad:率先使用HTML5发布新游戏
- 【CSON原创】HTML5圈泡泡游戏发布