试玩请点此下载并用浏览器打开index.html
这个游戏是弓箭射击敌人,用方向键移动人物,空格键发射箭枝。
图例:
代码:
<!DOCTYPE html> <html lang="utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <head> <title>弓箭手打怪物 19.3.8 9:23 by:逆火狂飙 horn19782016@163.com</title> <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='开始'/> </div> <canvas id="canvas" width="160px" height="160px" > 出现文字表示你的浏览器不支持HTML5 </canvas> </body> </html> <script type="text/javascript"> <!-- var paused=true; animateBtn.onclick=function(e){ paused=! paused; if(paused){ animateBtn.value="开始"; }else{ animateBtn.value="停止"; window.requestAnimationFrame(animate); } } var BL=32;// Block length,边长 var ctx;// 绘图环境 var terrain;// 地形 var hero;// 英雄/主角 var arrows;// 箭矢数组 var monsterMng;// 怪物管理者 //------------------------------------ // 初始化函数 //------------------------------------ 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(); arrows=new Array(); monsterMng=new MonsterMng(); // 响应键盘事件 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 a=new Arrow(hero.x+BL/2,hero.y+BL/2,hero.direction); arrows.push(a); //console.log('arrows.length='+arrows.length); e.preventDefault(); } } //------------------------------------ // 更新各实例状态 //------------------------------------ function update(){ for(var i=arrows.length-1;i>-1;i--){ var arrow=arrows[i]; var x=parseInt(arrow.x / 32,10); var y=parseInt(arrow.y / 32,10); // 箭矢射中怪物所在 if(monsterMng.shoot(x,y)==true){ //monsterMng.setValue(x,y,2); arrows.splice(i,1); break; } // 箭矢射中树木房屋等障碍物 if(terrain.getValue(x,y)!=0){ arrows.splice(i,1); } } var heroX=parseInt(hero.x/BL,10); var heroY=parseInt(hero.y/BL,10); // 看英雄碰到怪物没 if(monsterMng.isTouched(heroX,heroY)){ hero.setDead(); } // 游戏结束条件 if(hero.alive==false){ // 英雄死亡 alert("You lost!"); init(); } if(monsterMng.noMonster()){ // 怪物全清除 alert("You Win!"); init(); } } //------------------------------------ // 在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); // 画地形 // 画怪物 monsterMng.paint(ctx); // 画箭矢 for(var i=0;i<arrows.length;i++){ var arrow=arrows[i]; arrow.paint(ctx); } hero.paint(ctx); // 画英雄 } //------------------------------------ // 运行动画 //------------------------------------ function animate(){ if(!paused){ update(); draw(); window.requestAnimationFrame(animate); /// 让浏览器自行决定帧速率 } } //------------------------------------ // 常规函数:角度得到弧度 //------------------------------------ function getRad(degree){ return degree/180*Math.PI; } //------------------------------------ //生成从minNum到maxNum的随机数 //------------------------------------ function randomNum(minNum,maxNum){ switch(arguments.length){ case 1: return parseInt(Math.random()*minNum+1,10); break; case 2: return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10); break; default: return 0; break; } } //---------------------------------------------------地形类定义开始------------------------------------------------------------------->> 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 /*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( [1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,], [0,0,1,1,1,1,1,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,0,], [0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,], [0,0,0,2,0,0,2,0,0,0,0,0,0,3,0,0,0,0,], [0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,5,0,0,6,6,0,0,0,], [0,1,1,1,1,1,1,1,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,], [0,0,1,1,1,1,1,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,0,], [0,0,2,2,2,2,2,2,2,0,0,1,0,0,0,0,3,0,], [0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,3,0,], [0,0,0,2,0,0,2,0,0,0,0,0,0,3,0,0,3,0,], [0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,4,0,], [0,0,0,0,0,0,0,0,0,0,5,0,0,6,6,0,4,0,], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,4,0,], [0,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,0,0,0,0,0,0,5,0,], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,], [0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,5,0,], [0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,], [0,0,0,2,0,0,2,0,0,0,0,0,2,3,0,0,6,0,], [0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,6,0,], [0,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,6,0,], [0,0,0,0,0,0,0,0,0,0,5,0,0,6,6,0,0,0,], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,], [0,0,1,1,1,1,1,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,0,], [0,0,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,2,0,0,0,4,0,0,0,0,0,0,0,], [0,0,0,2,0,0,2,0,0,0,0,0,0,3,0,0,0,0,], [0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,], [0,2,2,2,2,2,2,2,4,0,0,0,0,0,0,0,0,0,], [0,0,0,0,0,0,0,0,0,0,5,0,0,6,6,0,0,0,], [0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,], ); } Terrain.prototype={ files:[], maps:[], // 在ctx画自己 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; }, } //---------------------------------------------------地形类定义结束-------------------------------------------------------------------<< //---------------------------------------------------英雄类定义开始------------------------------------------------------------------->> 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:160, y:160, xTo:160, yTo:160, step:32, direction:'up', alive:true, setDead:function(){ //console.log('Hero dead'); this.alive=false; }, paint:function(ctx){ if(this.alive){ 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); }else{ var img=new Image(); img.src='skull.png'; ctx.drawImage(img,this.x,this.y); } }, move:function(direction){ if(this.alive){ 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; } } } } //---------------------------------------------------英雄类定义结束-------------------------------------------------------------------<< //---------------------------------------------------怪物类定义开始------------------------------------------------------------------->> Monster=function(x,y,step,direction){ this.x=x; this.y=y; this.step=step; this.direction=direction; this.files=["monster.png", // 0 "monsterDead.png", // 1 "monsterUpdated.png", // 2 "monsterUpdatedDead.png",]; // 3 } Monster.prototype={ x:0, // 横坐标,乘以32等于真正的横坐标 y:0, // 纵坐标,乘以32等于真正的纵坐标 step:1, // 行走速度 direction:'', // 方向 files:[], // 显示图片 alive:true, // 是否活着 // 步长加倍 doubleStep:function(){ this.step*=2; }, // 被射中了 beShooted:function(){ this.alive=false; }, // 移动 move:function(){ if(this.alive){ } }, turnAround:function(){ var arr=['left','right','up','down',]; var newArr=[]; for(var i=0;i<arr.length;i++){ if(this.direction!=arr[i]){ newArr.push(arr[i]); } } console.log("newArr="+newArr); var index=randomNum(0,newArr.length-1); console.log("index="+index); this.direction=newArr[index]; }, 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]; } ctx.drawImage(img,this.x,this.y); }, } //---------------------------------------------------怪物类定义结束-------------------------------------------------------------------<< //---------------------------------------------------怪物管理类定义开始------------------------------------------------------------------->> MonsterMng=function(){ this.generateMonsters(); } MonsterMng.prototype={ monsters:[], // 生成怪物 generateMonsters:function(){ this.monsters=new Array(); this.monsters.push(new Monster(1*BL,1*BL,1,"right")); this.monsters.push(new Monster(1*BL,10*BL,1,"right")); this.monsters.push(new Monster(16*BL,16*BL,1,"right")); this.monsters.push(new Monster(10*BL,13*BL,1,"right")); this.monsters.push(new Monster(10*BL,10*BL,1,"right")); }, // 画怪物 paint:function(ctx){ for(var i=0;i<this.monsters.length;i++){ var m=this.monsters[i]; m.paint(ctx); } }, // 判断怪物还是否存在 hasMonster:function(){ return true; }, // 用箭射击怪物 shoot:function(arrowX,arrowY){ 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(arrowX,arrowY,monsterX,monsterY); if(monsterX==arrowX && monsterY==arrowY && monster.alive==true){ monster.beShooted(); //console.log('shooted',arrowX,arrowY,monsterX,monsterY); return true; } } return false; }, // 看英雄是否碰到怪物 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; }, } //---------------------------------------------------怪物管理类定义结束-------------------------------------------------------------------<< //---------------------------------------------------箭矢类定义开始------------------------------------------------------------------->> Arrow=function(x,y,direction){ this.x=x; this.y=y; this.direction=direction; } Arrow.prototype={ x:0, y:0, velocity:1,// 飞行速度 len:16,// 箭杆长 direction:'', // method paint:function(ctx){ var x1=this.x,y1=this.y; var leaf=4;//箭头箭羽长 var x2,y2,x3,y3; var angle=getRad(15); if(this.direction=='up'){ this.y-=this.velocity; y1=this.y-this.len; x1=this.x; y2=y1+leaf*Math.cos(angle); x2=x1-leaf*Math.sin(angle); y3=y2; x3=x1+leaf*Math.sin(angle); } if(this.direction=='down'){ this.y+=this.velocity; y1=this.y+this.len; x1=this.x; y2=y1-leaf*Math.cos(angle); x2=x1-leaf*Math.sin(angle); y3=y2; x3=x1+leaf*Math.sin(angle); } if(this.direction=='left'){ this.x-=this.velocity; x1=this.x-this.len; y1=this.y; x2=x1+leaf*Math.cos(angle); y2=y1-leaf*Math.sin(angle); x3=x2; y3=y1+leaf*Math.sin(angle); } if(this.direction=='right'){ this.x+=this.velocity; x1=this.x+this.len; y1=this.y; x2=x1-leaf*Math.cos(angle); y2=y1-leaf*Math.sin(angle); x3=x2; y3=y1+leaf*Math.sin(angle); } ctx.beginPath(); ctx.lineWidth = 2; ctx.strokeStyle = "#ff0000"; ctx.lineTo(this.x,this.y); ctx.lineTo(x1,y1); ctx.lineTo(x2,y2); ctx.lineTo(x3,y3); ctx.lineTo(x1,y1); ctx.stroke(); ctx.closePath(); }, } //---------------------------------------------------箭矢类定义结束-------------------------------------------------------------------<< //--> </script>
2019年3月8日12点32分