[Canvas]Bombman v1.04
Bombman是我仿造红白机上经典游戏爆破小人,用Canvas制作的一款网页版单机游戏, 自我感觉还是有一定的可玩性。
本游戏的胜利条件是用雷消灭所有怪物,但被怪物即使是擦边碰到或是炸弹火焰炸到就算失败。
操作方法是用方向键或是aswd健来控制人物移动,用空格键放雷炸怪物,吃红五星则雷的爆炸范围增加。
点此下载程序1.04版,用浏览器打开,并点“开始”按钮开始游戏,游戏结束后可以点“再来一次”按钮重新玩。
程序的1.06版本由此下载,此版本增加了怪物跟随主角的功能。
本作Github url:https://github.com/horn19782016/Bombman
有空可以玩玩,注意不要操之过急哦。
图例:
近千行源码:
<!DOCTYPE html> <html lang="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <head> <title>炸弹人v1.06 19.3.14 6:34 by:逆火狂飙 horn19782016@163.com</title> <!--1.06版本启用了怪物跟随英雄的功能 --> <style> #canvas{ background:#ffffff; cursor:pointer; margin-left:10px; margin-top:10px; -webkit-box-shadow:3px 3px 6px rgba(0,0,0,0.5); -moz-box-shadow:3px 3px 6px rgba(0,0,0,0.5); box-shadow:3px 3px 6px rgba(0,0,0,0.5); } #controls{ margin-top:10px; margin-left:15px; } </style> </head> <body onload="init()"> <div id="controls"> <input id='animateBtn' type='button' value='开始'/> <input id='playAgainBtn' type='button' value='再来一盘' style='visibility:hidden'/> </div> <canvas id="canvas" width="160px" height="160px" > 出现文字表示你的浏览器不支持HTML5 </canvas> </body> </html> <script type="text/javascript"> <!-- // 暂停/开始游戏 animateBtn.onclick=function(e){ paused=! paused; if(paused){ animateBtn.value="开始"; screenMsg="Paused!"; }else{ animateBtn.value="停止"; window.requestAnimationFrame(animate); } } // 重来游戏 playAgainBtn.onclick=function(e){ init(); playAgainBtn.style.visibility="hidden"; animateBtn.value="停止"; paused=false; window.requestAnimationFrame(animate); } var paused=true;// 是否暂停 var BL=32; // Block length,边长 var ctx; // 绘图环境 var terrain; // 地形 var hero; // 英雄/主角 var monsterMng; // 怪物管理类 var bombs; // 炸弹数组 var fires; // 火焰数组 var screenMsg; // 显示在屏幕中央的话语 var bonusMng; // 奖励管理类 function init(){ // init Canvas var canvas=document.getElementById('canvas'); canvas.width =40*BL; canvas.height=18*BL; ctx=canvas.getContext('2d'); terrain=new Terrain(); hero=new Hero(); monsterMng=new MonsterMng(); bombs=new Array(); fires=new Array(); bonusMng=new BonusMng(); // 响应键盘事件 canvas.addEventListener('keydown', doKeyDown, true); canvas.focus(); window.addEventListener('keydown', doKeyDown, true); }; //------------------------------------ // 响应键盘事件 //------------------------------------ function doKeyDown(e) { var keyID = e.keyCode ? e.keyCode :e.which; if(keyID === 38 || keyID === 87) { // up arrow and W hero.move('up'); e.preventDefault(); } if(keyID === 39 || keyID === 68) { // right arrow and D hero.move('right'); e.preventDefault(); } if(keyID === 40 || keyID === 83) { // down arrow and S hero.move('down'); e.preventDefault(); } if(keyID === 37 || keyID === 65) { // left arrow and A hero.move('left'); e.preventDefault(); } if(keyID === 32 ) { // SpaceBar var b=new Bomb(hero.x,hero.y,hero.explosionRange); bombs.push(b); //console.log('arrows.length='+arrows.length); e.preventDefault(); } } //------------------------------------ // 更新各实例状态 //------------------------------------ function update(){ monsterMng.move(); var heroX=parseInt(hero.x/BL,10); var heroY=parseInt(hero.y/BL,10); // 看英雄碰到怪物没 if(monsterMng.isTouched(heroX,heroY)){ hero.setDead(); } // 计算爆炸范围 var explosions=[]; for(var i=0;i<fires.length;i++){ var f=fires[i]; if(f.lifeTime>0){ explosions.push(new Point(f.x,f.y)); } } // 爆炸对怪物的伤害 monsterMng.makeDeadInRange(explosions); // 爆炸对英雄的伤害 hero.makeDeadInRange(explosions); // 奖励 bonusMng.enlargeExplosionRange(hero); // 让怪物吃奖励提升速度 var aliveMonsters=monsterMng.getAliveMonsters(); bonusMng.raiseSpeed(aliveMonsters); // 游戏结束条件 if(hero.alive==false){ // 英雄死亡 paused=true; screenMsg="You lost!"; animateBtn.value="开始"; playAgainBtn.style.visibility="visible"; } // 游戏胜利条件 if(monsterMng.noMonster() && hero.alive==true){ // 怪物全清除 及 英雄存活 paused=true; screenMsg="You win!"; animateBtn.value="开始"; playAgainBtn.style.visibility="visible"; } } //------------------------------------ // 在ctx里画出各实例 //------------------------------------ function draw(){ // Clear Canvas ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); ctx.fillStyle="#ffffff"; ctx.fillRect(0,0,ctx.canvas.width,ctx.canvas.height); terrain.paint(ctx); // 画地形 bonusMng.paint(ctx);// 画奖励 monsterMng.paint(ctx); hero.paint(ctx); // 画英雄 // 画炸弹 for(var i=0;i<bombs.length;i++){ var b=bombs[i]; b.paint(ctx); } // 画火焰 for(var i=0;i<fires.length;i++){ var b=fires[i]; b.paint(ctx); } } //------------------------------------ // 运行动画 //------------------------------------ function animate(){ if(!paused){ update(); draw(); window.requestAnimationFrame(animate); /// 让浏览器自行决定帧速率 }else{ ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font="bold 48px 宋体"; ctx.fillStyle='Red'; ctx.fillText(screenMsg,ctx.canvas.width/2,ctx.canvas.height/2); } } //------------------------------------ // 常规函数:角度得到弧度 //------------------------------------ function getRad(degree){ return degree/180*Math.PI; } //------------------------------------------------------------ // 常规函数:得到0到N(包括N)的随机整数 // 如果要得到数组里面的一个要把数组长度减一 //------------------------------------------------------------ function getRndFromZeroToN(n){ return Math.floor(Math.random()*(n+1)); } //------------------------------------------------------------ // 常规函数:得到lowerLimit到upperlimit(包括端点值)的随机整数 //------------------------------------------------------------ function getRndBetween(lowerLimit,upperlimit){ return Math.floor(Math.random()*(upperlimit-lowerLimit+1))+lowerLimit; } //---------------------------------------------------地形类定义开始------------------------------------------------------------------->> Terrain=function(){ this.files=["road.png", // 0 "tree.png", // 1 "farmerHouse.png", // 2 "twoBuilding.png", // 3 "threeBuilding.png",// 4 "bank.png", // 5 "villa.png", // 6 "blackWhiteRoad.png",]; // 7 /*this.maps=new Array( [0,0,0,0,0], [0,0,1,0,0], [0,0,0,0,0], [0,2,0,0,0], [0,0,0,3,0], );*/ this.maps=new Array( [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,1,2,1,2,1,0,1,2,1,0,0,1,1,1,1,1,0,], [0,0,0,0,0,0,0,0,0,0,0,0,3,3,3,3,1,0,], [0,1,2,1,2,1,0,1,2,1,0,0,5,0,0,3,1,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,1,0,], [0,1,2,1,2,1,0,1,2,1,0,0,3,3,3,3,1,0,], [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,], [0,1,2,1,2,1,0,1,2,1,0,1,4,4,4,4,1,0,], [0,0,0,0,0,0,0,0,0,0,0,1,4,0,0,0,1,0,], [0,1,2,1,2,1,0,1,2,1,0,1,5,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,1,4,0,0,0,1,0,], [0,1,2,1,2,1,0,1,2,1,0,1,4,4,4,4,1,0,], [0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,1,6,1,6,1,6,0,], [0,1,2,1,2,1,0,1,2,1,0,6,0,0,0,0,1,0,], [0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,6,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,5,0,0,1,0,], [0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,6,0,], [0,1,2,1,2,1,0,1,2,1,0,6,0,0,0,0,1,0,], [0,0,0,0,0,0,0,0,0,0,0,1,6,1,6,1,6,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,1,6,1,6,1,0,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,1,2,1,2,1,0,1,2,1,6,1,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,], [0,1,2,1,2,1,0,1,2,1,6,1,0,4,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,3,0,0,], [0,1,2,1,2,1,0,1,2,1,6,1,0,0,0,4,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,], [0,1,2,1,2,1,0,1,2,1,6,1,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,1,2,1,2,1,0,1,2,1,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,], [0,1,2,1,2,1,0,1,2,1,0,2,2,2,0,2,2,2,], [0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,], [0,1,2,1,2,1,0,1,2,1,0,2,0,0,0,0,0,2,], ); } Terrain.prototype={ files:[], maps:[], // method paint:function(ctx){ for(var i=0;i<this.maps.length;i++){ var arr=this.maps[i]; for(var j=0;j<arr.length;j++){ var value=arr[j]; var img=new Image(); img.src=this.files[value]; ctx.drawImage(img,i*BL,j*BL); } } }, // 是否有障碍 hasObstacle:function(i,j){ if(i<0 || i>=this.maps.length){ return true; } var arr=this.maps[i]; if(j<0 || j>=arr.length){ return true; } var value=arr[j]; if(value==0){ return false; }else{ return true; } }, getValue:function(i,j){ if(i<0 || i>=this.maps.length){ return undefined; } var arr=this.maps[i]; if(j<0 || j>=arr.length){ return undefined; } var value=arr[j]; return value; }, setValue:function(i,j,value){ if(i<0 || i>=this.maps.length){ return undefined; } var arr=this.maps[i]; if(j<0 || j>=arr.length){ return undefined; } arr[j]=value; }, // 取得空点数组 getEmptyPoints:function(count){ var allEmptyPoints=[]; for(var i=0;i<this.maps.length;i++){ var arr=this.maps[i]; for(var j=0;j<arr.length;j++){ var value=arr[j]; if(value==0){ allEmptyPoints.push(new Point(i*BL,j*BL)); } } } var retval=[]; //var n=allEmptyPoints.length; //console.log("allEmptyPoints.length="+allEmptyPoints.length); for(var i=0;i<count;i++){ var seed=this.getRndFromZeroToN(allEmptyPoints.length-1); var p=allEmptyPoints[seed]; retval.push(p); } return retval; }, //------------------------------------------------------------ // 得到0到N(包括N)的随机整数 // 如果要得到数组里面的一个要把数组长度减一 //------------------------------------------------------------ getRndFromZeroToN:function(n){ return Math.floor(Math.random()*(n+1)); }, } //---------------------------------------------------地形类定义结束-------------------------------------------------------------------<< //---------------------------------------------------英雄类定义开始------------------------------------------------------------------->> Hero=function(){ this.pngs=[ {left:0,top:10,width:40,height:40}, {left:0,top:68,width:40,height:40}, {left:0,top:123,width:40,height:40}, {left:0,top:180,width:40,height:40}, ]; } Hero.prototype={ pngs:[], x:19*BL, y:10*BL, xTo:19*BL, yTo:10*BL, step:BL, direction:'up', // 面向 alive:true, // 是否活着 explosionRange:4, // 爆炸范围 setDead:function(){ //console.log('Hero dead'); this.alive=false; }, paint:function(ctx){ var img=new Image(); img.src='bowman.png'; var index=0; if(this.direction=='up'){ index=3; } if(this.direction=='down'){ index=0; } if(this.direction=='left'){ index=1; } if(this.direction=='right'){ index=2; } var pos=this.pngs[index]; ctx.drawImage(img,pos.left,pos.top,pos.width,pos.height,this.x,this.y,32,32); }, move:function(direction){ this.direction=direction; if(this.direction=='up'){ this.yTo-=this.step; } if(this.direction=='down'){ this.yTo+=this.step; } if(this.direction=='left'){ this.xTo-=this.step; } if(this.direction=='right'){ this.xTo+=this.step; } if(terrain.getValue(this.xTo/this.step,this.yTo/this.step)==0){ this.x=this.xTo; this.y=this.yTo; }else{ this.xTo=this.x; this.yTo=this.y; } }, // 爆炸火焰一样对英雄造成伤害 makeDeadInRange:function(explosions){ for(var j=0;j<explosions.length;j++){ var point=explosions[j]; // 爆炸范围判断符合实际情况 var xx=Math.pow((this.x-point.x),2); var yy=Math.pow((this.y-point.y),2); var distance=Math.sqrt(xx+ yy); if(distance<BL/2){ this.setDead(); } } }, } //---------------------------------------------------英雄类定义结束-------------------------------------------------------------------<< //---------------------------------------------------点类定义开始------------------------------------------------------------------->> Point=function(x,y){ this.x=x; this.y=y; } Point.prototype={ x:0, // 横坐标 y:0, // 纵坐标 } //---------------------------------------------------点类定义结束-------------------------------------------------------------------<< //---------------------------------------------------怪物类定义开始------------------------------------------------------------------->> Monster=function(x,y){ this.x=x; this.y=y; steps=[1,2,4,8]; var rndSeed=this.getRndFromZeroToN(steps.length-1); this.step=steps[rndSeed]; this.files=["monster1.png", // 0 "monster1Dead.png", // 1 "monster2.png", // 2 "monster2Dead.png", // 3 "monster3.png", // 4 "monster3Dead.png", // 5 "monster4.png", // 6 "monster4Dead.png", // 7 ]; } Monster.prototype={ x:0, // 横坐标,乘以32等于真正的横坐标 y:0, // 纵坐标,乘以32等于真正的纵坐标 step:1, // 行走速度 steps:[], // 行走速度数组 direction:'', // 方向 files:[], // 显示图片 alive:true, // 是否活着 thinking:true, // 是否在找路 targetPoint:[], // 设置死亡 setDead:function(){ this.alive=false; }, // 成倍提升速度 doubleStep:function(){ this.step*=2; if(this.step>=512){ this.step=512; } }, // 移动 move:function(){ if(this.alive){ if(this.thinking==true){ // 思考下一步往哪里走 targetPoint=null; // 选择偏向英雄的方向 var xDiff=this.x-hero.x; var yDiff=this.y-hero.y; var emptyPlaces=[]; var monsterX=parseInt(this.x/BL,10); var monsterY=parseInt(this.y/BL,10); var pointsTmp=[]; if(xDiff>=0){ // 左边方格 for(var i=1;i<=this.step;i++){ var hasObstacle=terrain.hasObstacle(monsterX-i,monsterY); if(hasObstacle==false){ pointsTmp.push(new Point(monsterX-i,monsterY)); }else{ break; } } if(pointsTmp.length>0){ emptyPlaces.push(pointsTmp[pointsTmp.length-1]); pointsTmp=[]; } } if(xDiff<0){ // 右边方格 for(var i=1;i<=this.step;i++){ var hasObstacle=terrain.hasObstacle(monsterX+i,monsterY); if(hasObstacle==false){ pointsTmp.push(new Point(monsterX+i,monsterY)); }else{ break; } } if(pointsTmp.length>0){ emptyPlaces.push(pointsTmp[pointsTmp.length-1]); pointsTmp=[]; } } if(yDiff>=0){ // 上边方格 for(var i=1;i<=this.step;i++){ var hasObstacle=terrain.hasObstacle(monsterX,monsterY-i); if(hasObstacle==false){ pointsTmp.push(new Point(monsterX,monsterY-1)); }else{ break; } } if(pointsTmp.length>0){ emptyPlaces.push(pointsTmp[pointsTmp.length-1]); pointsTmp=[]; } } if(yDiff<0){ // 下边方格 for(var i=1;i<=this.step;i++){ var hasObstacle=terrain.hasObstacle(monsterX,monsterY+i); if(hasObstacle==false){ pointsTmp.push(new Point(monsterX,monsterY+1)); }else{ break; } } if(pointsTmp.length>0){ emptyPlaces.push(pointsTmp[pointsTmp.length-1]); pointsTmp=[]; } } // 下面是随机选择方向 var rndSeed=this.getRndFromZeroToN(emptyPlaces.length-1); this.targetPoint=emptyPlaces[rndSeed]; //console.log(targetPoint); if(this.targetPoint!=null){ //console.log(this.targetPoint); this.thinking=false; } }else{ // 思考好了就走 var targetX=this.targetPoint.x*BL; var targetY=this.targetPoint.y*BL; //console.log(this.targetPoint,this.x,this.y); if(targetX==this.x && targetY<this.y){ this.y-=this.step; } if(targetX==this.x && targetY>this.y){ this.y+=this.step; } if(targetX<this.x && targetY==this.y){ this.x-=this.step; } if(targetX>this.x && targetY==this.y){ this.x+=this.step; } if(targetX==this.x && targetY==this.y){ this.thinking=true; } } } }, //------------------------------------------------------------ // 得到0到N(包括N)的随机整数 // 如果要得到数组里面的一个要把数组长度减一 //------------------------------------------------------------ getRndFromZeroToN:function(n){ return Math.floor(Math.random()*(n+1)); }, // 画怪物 paint:function(ctx){ var img=new Image(); if(this.alive==true && this.step==1){ img.src=this.files[0]; } if(this.alive==false && this.step==1){ img.src=this.files[1]; } if(this.alive==true && this.step==2){ img.src=this.files[2]; } if(this.alive==false && this.step==2){ img.src=this.files[3]; } if(this.alive==true && this.step==4){ img.src=this.files[4]; } if(this.alive==false && this.step==4){ img.src=this.files[5]; } if(this.alive==true && this.step>=8){ img.src=this.files[6]; } if(this.alive==false && this.step>=8){ img.src=this.files[7]; } ctx.drawImage(img,this.x,this.y); }, } //---------------------------------------------------怪物类定义结束-------------------------------------------------------------------<< //---------------------------------------------------怪物管理类定义开始------------------------------------------------------------------->> MonsterMng=function(){ this.addMonster(9); } MonsterMng.prototype={ monsters:[], // 生成怪物,测试用 generateMonsters:function(){ this.monsters=new Array(); this.monsters.push(new Monster(1*BL,1*BL,3)); this.monsters.push(new Monster(1*BL,10*BL,3)); this.monsters.push(new Monster(16*BL,16*BL,2)); this.monsters.push(new Monster(10*BL,13*BL,5)); this.monsters.push(new Monster(10*BL,10*BL,6)); this.monsters.push(new Monster(24*BL,1*BL,1)); }, // 画怪物 paint:function(ctx){ for(var i=0;i<this.monsters.length;i++){ var m=this.monsters[i]; m.paint(ctx); } // 写怪物数目 ctx.textAlign = 'left'; ctx.textBaseline = 'middle'; ctx.font="bold 24px 宋体"; ctx.fillStyle='maroon'; ctx.fillText("Monsters:"+this.getAliveMonsterNum(),ctx.canvas.width-5*BL,BL/2); }, // 让怪物移动 move:function(ctx){ for(var i=0;i<this.monsters.length;i++){ var m=this.monsters[i]; m.move(); } }, // 得到活着的怪兽数量 getAliveMonsterNum:function(){ var count=0; for(var i=0;i<this.monsters.length;i++){ var m=this.monsters[i]; if(m.alive){ count++; } } return count; }, // 得到活着的怪兽数组 getAliveMonsters:function(ctx){ var arr=[]; for(var i=0;i<this.monsters.length;i++){ var m=this.monsters[i]; if(m.alive==true){ arr.push(m); } } return arr; }, // 判断怪物还是否存在 hasMonster:function(){ var count=this.getAliveMonsterNum(); return count==0; }, // 看英雄是否碰到怪物 isTouched:function(heroX,heroY){ for(var i=0;i<this.monsters.length;i++){ var monster=this.monsters[i]; var monsterX=parseInt(monster.x/BL,10); var monsterY=parseInt(monster.y/BL,10); //console.log('isTouched',heroX,heroY,monsterX,monsterY); if(heroX==monsterX && heroY==monsterY && monster.alive==true){ //console.log('touched',heroX,heroY,monsterX,monsterY); return true; } } return false; }, // 看有没有怪物了 noMonster:function(heroX,heroY){ var count=0; for(var i=0;i<this.monsters.length;i++){ var monster=this.monsters[i]; if(monster.alive){ count++; } } return count==0; }, // 将爆炸范围内的怪物致死 makeDeadInRange:function(explosions){ //console.log(explosions); for(var i=0;i<this.monsters.length;i++){ var monster=this.monsters[i]; if(monster.alive){ for(var j=0;j<explosions.length;j++){ var point=explosions[j]; //console.log(monster.x,monster.y,point.x,point.y); /*if(monster.x==point.x && monster.y==point.y){ // 精确判断不符合实际情况 monster.setDead(); }*/ // 范围判断符合实际情况 var xx=Math.pow((monster.x-point.x),2); var yy=Math.pow((monster.y-point.y),2); var distance=Math.sqrt(xx+ yy); if(distance<BL/2){ monster.setDead(); } } } } }, // 添加怪物 addMonster:function(n){ this.monsters=new Array(); var points=terrain.getEmptyPoints(n); for(var i=0;i<points.length;i++){ var p=points[i]; this.monsters.push(new Monster(p.x,p.y)); //this.bonusArr.push(new Bonus(p.x,p.y)); } console.log(this.monsters); }, } //---------------------------------------------------怪物管理类定义结束-------------------------------------------------------------------<< //---------------------------------------------------炸弹类定义开始------------------------------------------------------------------->> Bomb=function(x,y,explosionRange){ this.x=x; this.y=y; // 放下炸弹,让其起障碍作用 var bombX=parseInt(this.x/BL,10); var bombY=parseInt(this.y/BL,10); terrain.setValue(bombX,bombY,7); this.explosionRange=explosionRange; this.files=['bomb1.png','bomb2.png','bomb3.png','bomb4.png']; } Bomb.prototype={ x:0, // 横坐标 y:0, // 纵坐标 files:[], // 表现炸弹的图片 level:0, // 等级,越高越解决爆炸 exploded:false, // 是否爆炸 explosionRange:1,// 爆炸范围 // 画炸弹 paint:function(ctx){ if(this.exploded==false){ var img=new Image(); this.level+=0.75; if(this.level<20){ img.src=this.files[0]; }else if(this.level>=20 && this.level<40){ img.src=this.files[1]; }else if(this.level>=40 && this.level<60){ img.src=this.files[2]; }else if(this.level>=60 && this.level<80){ img.src=this.files[3]; }else if(this.level>=80 && this.level<100){ img.src=this.files[4]; }else if(this.level>=100){ // 起爆 this.exploded=true; // 爆炸完毕,让其恢复通行 var bombX=parseInt(this.x/BL,10); var bombY=parseInt(this.y/BL,10); terrain.setValue(bombX,bombY,0); // 创建火焰对象 this.makeFire(); } ctx.drawImage(img,this.x,this.y); } }, // 制造火焰 makeFire:function(){ var emptyPlaces=[]; var bombX=parseInt(this.x/BL,10); var bombY=parseInt(this.y/BL,10); //console.log(bombX,bombY); // Left for(var i=1;i<=this.explosionRange;i++){ var hasObstacle=terrain.hasObstacle(bombX-i,bombY); if(hasObstacle==false){ emptyPlaces.push(new Point(bombX-i,bombY)); }else{ break; } } // Right for(var i=1;i<=this.explosionRange;i++){ var hasObstacle=terrain.hasObstacle(bombX+i,bombY); if(hasObstacle==false){ emptyPlaces.push(new Point(bombX+i,bombY)); }else{ break; } } // Up for(var i=1;i<=this.explosionRange;i++){ var hasObstacle=terrain.hasObstacle(bombX,bombY-i); if(hasObstacle==false){ emptyPlaces.push(new Point(bombX,bombY-i)); }else{ break; } } // down for(var i=1;i<=this.explosionRange;i++){ var hasObstacle=terrain.hasObstacle(bombX,bombY+i); if(hasObstacle==false){ emptyPlaces.push(new Point(bombX,bombY+i)); }else{ break; } } // Center var hasObstacle=terrain.hasObstacle(bombX,bombY); if(hasObstacle==false){ emptyPlaces.push(new Point(bombX,bombY)); } //console.log(emptyPlaces); // 添加火焰对象 for(var i=0;i<emptyPlaces.length;i++){ var p=emptyPlaces[i]; var f=new Fire(p.x*BL,p.y*BL); fires.push(f); } }, } //---------------------------------------------------炸弹类定义结束-------------------------------------------------------------------<< //---------------------------------------------------火焰类定义开始------------------------------------------------------------------->> Fire=function(x,y){ this.x=x; this.y=y; this.files=['fire1.png','fire2.png']; } Fire.prototype={ x:0, // 横坐标 y:0, // 纵坐标 files:[], // 火焰图片 lifeTime:50, // 显示时间 paint:function(ctx){ if(this.lifeTime>0){ this.lifeTime--; var img=new Image(); if(this.lifeTime>25){ img.src=this.files[0]; }else{ img.src=this.files[1]; } ctx.drawImage(img,this.x,this.y); } }, } //---------------------------------------------------火焰类定义结束-------------------------------------------------------------------<< //---------------------------------------------------奖励类定义开始------------------------------------------------------------------->> Bonus=function(x,y){ this.x=x; this.y=y; this.files=['bonus.png']; } Bonus.prototype={ x:0, // 横坐标 y:0, // 纵坐标 files:[], // 图片 used:false, // 是否使用过 paint:function(ctx){ if(this.used==false){ var img=new Image(); img.src=this.files[0]; ctx.drawImage(img,this.x,this.y); } }, } //---------------------------------------------------奖励类定义结束-------------------------------------------------------------------<< //---------------------------------------------------奖励管理类定义开始------------------------------------------------------------------->> BonusMng=function(x,y){ this.bonusArr=new Array(); this.addBonus(2); } BonusMng.prototype={ bonusArr:[], // 奖励数组 paint:function(ctx){ for(var i=0;i<this.bonusArr.length;i++){ var b=this.bonusArr[i]; b.paint(ctx); } }, // 提升英雄的爆炸范围 enlargeExplosionRange:function(hero){ for(var i=0;i<this.bonusArr.length;i++){ var b=this.bonusArr[i]; if(b.used==false && b.x==hero.x && b.y==hero.y){ hero.explosionRange+=1; b.used=true; break; } } this.refresh(); }, // 提升怪物速度 raiseSpeed:function(monsters){ for(var i=0;i<monsters.length;i++){ var monster=monsters[i]; if(monster.alive==true){ for(var j=0;j<this.bonusArr.length;j++){ var b=this.bonusArr[j]; if(b.used==false && b.x==monster.x && b.y==monster.y){ monster.doubleStep(); b.used=true; console.log(this.bonusArr); } } } } this.refresh(); }, // 更新bonus refresh:function(){ var count=0; for(var i=0;i<this.bonusArr.length;i++){ var b=this.bonusArr[i]; if(b.used==false){ count++;// 统计未被使用的bonus个数 } } if(count==0){ this.addBonus(1);// 如果没有bonus了再动态加几个 } }, addBonus:function(n){ var points=terrain.getEmptyPoints(n); for(var i=0;i<points.length;i++){ var p=points[i]; this.bonusArr.push(new Bonus(p.x,p.y)); } }, } //---------------------------------------------------奖励管理类定义结束-------------------------------------------------------------------<< //--> </script>
2019年3月9日21点28分 (PS:今天在博客园的排名从六百多上升到四百多,不知怎么回事)
1.04版 让怪物吃奖励,改进了怪物寻路算法。2019年3月11日11点23分
[Canvas]Bombman v1.04的更多相关文章
- [Canvas]Bombman v1.00
爆破小人Canvas版,请点此下载,并用浏览器打开试玩. 图例: 源码: <!DOCTYPE html> <html lang="utf-8"> <m ...
- T6跨账套辅助工具[v1.04]
[v1.03] 增加自定义报表,用户可以自行设置报表所打开的数据表,然后设置查询条件 [v1.04]更改单据显示样式,直接以用友打印预览的方式显示,允许用自定义显示,打印样式 下图为新的显示样式 下图 ...
- HTML5用canvas绘制五星红旗
在HTML5一览中,我们提到html 5被冠以很多高帽,其中最高的一顶.备受争议的就是"Flash杀手".IT评论界老喜欢用这个词了,杀手无处不在.不管是不是杀手,HTML 5引进 ...
- 【原创】使用HTML5+canvas+JavaScript开发的原生中国象棋游戏及源码分享
目前已经实现的功能: V1.0 : 实现棋子的布局,画布及游戏场景的初始化V2.0 : 实现棋子的颜色改变V3.0 :实现所有象棋的走棋规则V4.0 : 实现所有棋子的吃子功能 GItHub源码下载地 ...
- 【JavaScript游戏开发】使用HTML5 canvas开发的网页版中国象棋项目
//V1.0 : 实现棋子的布局,画布及游戏场景的初始化 //V2.0 : 实现棋子的颜色改变 //V3.0 :实现所有象棋的走棋规则 //V4.0 : 实现所有棋子的吃子功能 完整的项目源码已经开源 ...
- git代码库误操作还原记录
先做一些前情提要: 我们项目使用git作为代码管理,同时为了操作更方便,安装了乌龟git(tortoiseGit)工具.以下几乎所有操作都是在乌龟git上进行. 我们的项目是分阶段完成的,在完成上一阶 ...
- snmp数据包分析
今天看了一下snmp数据包的报文格式,用wireshark抓了两个数据包来分析. 先说说snmp get-request的书报包格式吧,get-next-request,get-response,se ...
- Centos6.5搭建bugzilla
一.安装httpd. mod_ssl. mysql-server . mysql .php-mysql . gcc . perl* . mod-perl-devel [root@localhost ~ ...
- kubernetes入门(03)kubernetes的基本概念
一.Pod 在Kubernetes集群中,Pod是创建.部署和调度的基本单位.一个Pod代表着集群中运行的一个进程,它内部封装了一个或多个应用的容器.在同一个Pod内部,多个容器共享存储.网络IP,以 ...
随机推荐
- Optimization algorithm----Deep Learning
深度学习中的优化算法总结 以下内容简单的汇总了在深度学习中常见的优化算法,每个算法都集中回答:是什么?(原理思想)有什么用?(优缺点)怎么用?(在tensorflow中的使用) 目录 1.SGD 1. ...
- tomcat 输入学习
Tomcat学习—Tomcat7 修改/webapps/ROOT发布路径(Linux和windows环境) https://blog.csdn.net/u010648555/article/detai ...
- ubuntu 语言设置
1.ubuntu ibus 输入法无法切换拼音 原因未安装中文输入法 sudo apt install ibus-pinyin //安装pinyinwin + space(空格) 切换中文输入法 再用 ...
- php中foreach()跳出循环或者终止循环的实现方法
$arr = array('a','b','c','d','e'); $html = ''; foreach($arr as $key => $value){ if($value=='b'){ ...
- web----ssl通信
ssl通信 https://www.cnblogs.com/zhengah/p/5007753.html
- 里氏代换原则(Liskov Substitution Principle,LSP)
第一种定义: 如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2,程序P的行为没有发生变化,那么类型S是类型T的子类型. 第二种定义: 所有引 ...
- POJ 1017 Packets【贪心】
POJ 1017 题意: 一个工厂制造的产品形状都是长方体,它们的高度都是h,长和宽都相等,一共有六个型号,他们的长宽分别为 1*1, 2*2, 3*3, 4*4, 5*5, 6*6. 这些产品通常 ...
- java:矩阵面积
实现一个矩阵类Rectangle,包含如下的一些成员变量与函数: 两个共有的成员变量 width 和 height 分别代表宽度和高度. 一个构造函数,接受2个参数 width 和 height 来设 ...
- jquery 中remove()与detach()的区别
remove()与detach()方法都是从dom中删除所有的元素 两者的共同之处在于都不会把匹配的元素从jQuery对象中删除. 不同之处在于用remove()删除的元素,除了元素被保留,其他的在这 ...
- 014 view-controller标签
1.说明 可以直接相应转发的页面, 而无需再经过 Handler 的方法. 这个时候可以使用mvc:view-controller标签. 但是以前的映射会出现问题,这个时候需要再配置一个标签<m ...