[Canvas]Bowman
试玩请点此下载并用浏览器打开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分
[Canvas]Bowman的更多相关文章
- [Canvas]Bombman v1.04
Bombman是我仿造红白机上经典游戏爆破小人,用Canvas制作的一款网页版单机游戏, 自我感觉还是有一定的可玩性. 本游戏的胜利条件是用雷消灭所有怪物,但被怪物即使是擦边碰到或是炸弹火焰炸到就算失 ...
- [Canvas]Bombman v1.00
爆破小人Canvas版,请点此下载,并用浏览器打开试玩. 图例: 源码: <!DOCTYPE html> <html lang="utf-8"> <m ...
- [Canvas]炸弹人初成版
试玩请点此下载代码,并使用浏览器打开index.html. 用方向键操作小人,空格键放炸弹,把敌人消灭算赢,被炸弹炸中或是碰到敌人算输. 图例: 源码: <!DOCTYPE html> & ...
- [Canvas]游戏增加怪物爆炸效果,改善箭头形状
请点此下载代码并用浏览器打开试玩. 图例: 代码: <!DOCTYPE html> <html lang="utf-8"> <meta http-eq ...
- [Canvas]首个小游戏告成
英雄在地图上射箭杀怪兽,杀完了就胜利了. 点此下载程序试玩. 图例: 代码: <!DOCTYPE html> <html lang="utf-8"> < ...
- [Canvas]英雄可以射箭了
点此下载源码并用浏览器观看. 图例: 代码: <!DOCTYPE html> <html lang="utf-8"> <meta http-equiv ...
- [Canvas]人物型英雄出现(前作仅为箭头)
源码点此下载,用浏览器打开index.html观看. 代码: <!DOCTYPE html> <html lang="utf-8"> <meta ht ...
- html5 canvas常用api总结(三)--图像变换API
canvas的图像变换api,可以帮助我们更加方便的绘画出一些酷炫的效果,也可以用来制作动画.接下来将总结一下canvas的变换方法,文末有一个例子来更加深刻的了解和利用这几个api. 1.画布旋转a ...
- 【探索】利用 canvas 实现数据压缩
前言 HTTP 支持 GZip 压缩,可节省不少传输资源.但遗憾的是,只有下载才有,上传并不支持.如果上传也能压缩,那就完美了.特别适合大量文本提交的场合,比如博客园,就是很好的例子. 虽然标准不支持 ...
随机推荐
- C#--整型与字节数组byte[]之间的转换
using System; int i = 123;byte [] intBuff = BitConverter.GetBytes(i); // 将 int 转换成字节数组lob.Write ...
- hdu 1455 N个短木棒 拼成长度相等的几根长木棒 (DFS)
N根短木棒 能够拼成几根长度相等的长木棒 求长木棒的长度 如果答案不止一种 输出最小的 Sample Input95 2 1 5 2 1 5 2 141 2 3 40 Sample Output65 ...
- python算法双指针问题:使用列表和数组模拟单链表
这个很多基础算法,python已内部实现了. 所以,要想自己实现链表这些功能时, 反而需要自己来构造链表的数据结构. 当然,这是python灵活之处, 也是python性能表达不如意的来源. valu ...
- asp.net core 2.0 cookie的使用
本文假设读者已经了解cookie的概念和作用,并且在传统的.net framework平台上使用过. cookie的使用方法和之前的相比也有所变化.之前是通过cookie的add.set.clear. ...
- BZOJ1178 [Apio2009]CONVENTION会议中心 贪心 set
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1178 题意概括 一堆线段,现在取出最多条数,使其互不覆盖,并输出字典序最小的方案. 题解 这题好坑 ...
- 1.HTTP协议|web框架
1.web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件.应用程序有两种模式C/S.B/S.C/S是客户端 ...
- Unity 之 场景切换
Application.LoadLevel();//场景名称或索引,删除掉原场景的所有东西 Application.LoadLevelAdditive()//添加并加载场景,不删除当前场景的物体, ...
- php 三元运算符实例详细介绍
三元运算符的功能与“if....else”流程语句一致,它在一行中书写,代码精练.执行效率高.在PHP程序中恰当地使用三元运算符能够让脚本更为简洁.高效.代码的语法如下: ? 1 (expr1)?(e ...
- 阿里dubbo服务注册原理解析
阿里分布式服务框架 dubbo现在已成为了外面很多中小型甚至一些大型互联网公司作为服务治理的一个首选或者考虑方案,相信大家在日常工作中或多或少都已经用过或者接触过dubbo了.但是我搜了 ...
- 浅谈vue之动态路由匹配
在日常开发过程中,可能会遇到一些类似于新闻详情页的内容,需要把所有详情页映射到同一组件上,这是动态路由匹配的应用场景之一.在使用的过程中,也遇到过一些小坑,此篇做个简要的总结说明: 基本使用 { pa ...