好久没写过小游戏了,最近抽时间写了一个,看了一些高人写的游戏,无限感慨呀。。。也从中学到了不少东西。 我不会写什么大的游戏,因为需要很多时间与精力,而且自认水平有限,个人喜欢写些小游戏。 这次的游戏是【是男人就忍30秒】,游戏玩法很简单,就是用键盘控制飞机,飞来飞去,躲开子弹,看你能撑多久。 本来是打算写一个教程来一步步说明的,但后来想了想,还是算了,免得误人子弟,在源码上加些注释就可以。 没有测试过IE9,因为没有IE9。。。鄙人还是用XP的。。。所以还是请用谷歌或者FF或者Safari吧。 刚刚修复了在FF下不能使用的问题,因为没给canvas设置tabindex属性,它就不能触发keydown事件,以及设置canvas为focus,现在可以了。。。 游戏预览如下: 请使用chrome,safari,ff 此游戏用了四个js文件。 1。canvas.js,简单了封装了一些需要用到的画图方法,相信一看就懂了。。。 1 //画布类 2 var Canvas = { 3 //画布的2d对象 4 cxt : null, 5 //初始化画布 6 init : function(id){ 7 this.cxt = (typeof id=='string'?document.getElementById(id):id).getContext('2d'); 8 }, 9 //清除画布 10 clear : function(x,y){ 11 this.cxt.clearRect(0,0,x,y); 12 }, 13 //画图 14 drawImg : function(obj){ 15 this.cxt.drawImage(obj.img,obj.x,obj.y); 16 }, 17 //画文字 18 drawText : function(string,x,y,color){ 19 20 this.cxt.fillStyle = color; 21 this.cxt.font = 'bold 14px sans-serif'; 22 this.cxt.fillText(string,x,y); 23 }, 24 //加载图片 25 //imgs:图片对象的数组 26 //callback:回调函数 27 //context:上下文对象 28 loadImgs : function(imgs,callback,context){ 29 30 var success_count = 0; 31 32 var addCount = function(){ 33 success_count += 1; 34 35 if(success_count == l)callback && callback.call(context); 36 } 37 38 for(var i=0,l=imgs.length;i<l;i++){ 39 imgs[i].onload = addCount; 40 } 41 42 } 43 } 2。fly.js,飞机类,采用在计时器中移动,而非一般的键盘按一下就移动一格,这样做,控制得更流畅,而且,可以支持打斜飞。 1 var Fly = function(img,x,y){ 2 //飞机的图片 3 this.img = img; 4 //飞机的坐标 5 this.x = x; 6 this.y = y; 7 //飞机的移动方向值 8 this.moveDir = { 9 left:false, 10 right:false, 11 up:false, 12 down:false 13 }; 14 //移动的速度 15 this.movesp = 2; 16 } 17 Fly.prototype = { 18 //键盘码对应移动方向 19 keyCode2Dir : { 20 37:'left', 21 38:'up', 22 39:'right', 23 40:'down' 24 }, 25 //键盘按下事件 26 //keyCode:键盘码 27 keyDown : function(keyCode){ 28 //修改对应的移动值 29 this.moveDir[this.keyCode2Dir[keyCode]]=true; 30 }, 31 //键盘释放事件 32 //keyCode:键盘码 33 keyUp : function(keyCode){ 34 //修改对应的移动值 35 this.moveDir[this.keyCode2Dir[keyCode]]=false; 36 }, 37 //判断是否在移动中 38 checkMove : function(){ 39 if(this.moveDir.left || this.moveDir.right || this.moveDir.up || this.moveDir.down)return true; 40 return false; 41 }, 42 //移动 43 //gameInfo:游戏背景信息 44 move : function(gameInfo){ 45 46 var This = this; 47 //根据方向来移动 48 if(This.moveDir.left)This.x -= This.movesp; 49 if(This.moveDir.right)This.x += This.movesp; 50 if(This.moveDir.up)This.y -= This.movesp; 51 if(This.moveDir.down)This.y += This.movesp; 52 //边界值检测 53 if(This.x <0)This.x=0; 54 else if(This.x >gameInfo.width-This.img.width)This.x = gameInfo.width-This.img.width; 55 if(This.y <0)This.y=0; 56 else if(This.y >gameInfo.height-This.img.height)This.y = gameInfo.height-This.img.height; 57 } 58 59 } 3。bullet.js,子弹类,子弹的飞,我承认,确实做得很简单,希望大家自己改进这个算法。。。 1 var Bullet = function(img){ 2 //子弹的图片 3 this.img = img; 4 //X坐标 5 this.x = 0; 6 //Y坐标 7 this.y = 0; 8 //子弹要飞的x与y的速度 9 this.arc = {}; 10 //移动的帧数 11 this.moveFps = 20; 12 //帧数延迟 13 this.moveFpsLazy = 0; 14 //初始化 15 this.init(); 16 } 17 Bullet.prototype = { 18 //方向数组 19 arrDir : ['left','right','up','down'], 20 //初始化 21 init : function(){ 22 //最小位置 23 var min = 5, 24 //最大位置 25 max = 395, 26 //随机位置 27 rnd = Math.floor(Math.random()*370+10), 28 //移动方向 29 dir = this.arrDir[Math.floor(Math.random()*4)]; 30 31 //设置子弹的初始位置与将要飞的方向与速度 32 switch(dir){ 33 case 'left':{ 34 this.x = max; 35 this.y = rnd; 36 if(this.y>=max/2)this.arc = {x:-5,y:-2}; 37 else this.arc={x:-5,y:2}; 38 break; 39 } 40 case 'right':{ 41 this.x = min; 42 this.y = rnd; 43 if(this.y>=max/2)this.arc = {x:5,y:-2}; 44 else this.arc={x:5,y:2}; 45 break; 46 } 47 case 'up':{ 48 this.y = max; 49 this.x = rnd; 50 if(this.x>=max/2)this.arc = {x:-3,y:-5}; 51 else this.arc={x:3,y:-5}; 52 break; 53 } 54 case 'down':{ 55 this.y = min; 56 this.x = rnd; 57 if(this.x>=max/2)this.arc = {x:-3,y:5}; 58 else this.arc={x:3,y:5}; 59 break; 60 } 61 } 62 }, 63 //更新子弹数据 64 //gameInfo:游戏背景信息 65 updata : function(gameInfo){ 66 //延迟+10 67 this.moveFpsLazy += 10; 68 //判断延迟是否等于移动帧数 69 if(this.moveFpsLazy == this.moveFps){ 70 //移动 71 this.x += this.arc.x; 72 this.y += this.arc.y; 73 //边界值检测 74 if(this.x <0 || this.x > gameInfo.width || this.y <0 || this.y > gameInfo.height){ 75 this.callback(); 76 return false; 77 } 78 //清0 79 this.moveFpsLazy = 0; 80 } 81 }, 82 //检测是否撞到飞机 83 //fly:飞机对象 84 checkCrashFly : function(fly){ 85 //获取子弹与飞机的圆心坐标 86 var bx = this.x+this.img.width/2,by = this.y+this.img.height/2, 87 fx = fly.x+fly.img.width/2,fy = fly.y+fly.img.height/2; 88 //判断圆心距 89 if(Math.sqrt(Math.pow(bx-fx,2)+Math.pow(by-fy,2)) < (fly.img.width/2+this.img.width/2)){ 90 return true; 91 } 92 return false; 93 }, 94 //回调函数 95 callback : function(){} 96 97 } 4。Game.js,游戏控制类,主要控制游戏的逻辑 1 var Game = { 2 //游戏背景数据,主要是宽与高 3 gameInfo :{width:0,height:0}, 4 //飞机对象 5 fly : null, 6 //子弹对象数组 7 bullets : [], 8 //子弹图片 9 bulletImg : null, 10 //子弹产生的延迟 11 bulletLazyFps : 0, 12 //绘画处理计时器ID 13 processId : 0, 14 //分数 15 score : 0, 16 //是否开始 17 isStart : false, 18 //显示开始信息 19 showStart : function(){ 20 21 var This = this; 22 //画开始字 23 Canvas.drawText("Press Enter to Start!",120,200,'white'); 24 //绑定事件 25 document.body.onkeydown = function(e){This.keyDown(e);}; 26 document.body.onkeyup = function(e){This.keyUp(e);}; 27 }, 28 //游戏初始化 29 init : function(){ 30 //设置游戏背景信息 31 var gameBg = document.getElementById('js_canvas'); 32 this.gameInfo.width = gameBg.offsetWidth; 33 this.gameInfo.height = gameBg.offsetHeight; 34 //初始化画布 35 gameBg.focus();Canvas.init(gameBg); 36 //设置飞机图片与子弹图片 37 var flyImg = new Image(); 38 var bulletImg = new Image(); 39 flyImg.src = "http://blog.soso.com/qz.q/img/fly.gif"; 40 bulletImg.src = "http://blog.soso.com/qz.q/img/bullet.gif"; 41 //加载图片,成功后,回调显示开始信息 42 Canvas.loadImgs([flyImg,bulletImg],this.showStart,this); 43 //设置飞机对象 44 this.fly = new Fly(flyImg,200,200); 45 //设置Game子弹图片 46 this.bulletImg = bulletImg; 47 }, 48 //生成子弹 49 createBullets : function(){ 50 51 var This = this; 52 //判断延时是否200 53 if(this.bulletLazyFps == 200){ 54 //创建子弹,添加到数组中 55 var bullet = new Bullet(this.bulletImg); 56 bullet.callback = function(){ 57 This.removeBullet(this); 58 } 59 60 this.bullets.push(bullet); 61 this.bulletLazyFps = 0; 62 } 63 else{ 64 this.bulletLazyFps += 10; 65 } 66 }, 67 //开始 68 start : function(){ 69 70 var This = this; 71 //重置数据 72 this.reset(); 73 //设置开始 74 this.isStart = true; 75 //开始绘画 76 this.process(); 77 78 }, 79 //重置数据 80 reset : function(){ 81 82 this.score = 0; 83 this.bullets = []; 84 }, 85 //结束 86 end : function(){ 87 88 this.isStart = false; 89 90 clearInterval(this.processId); 91 92 this.showStart(); 93 }, 94 //绘画函数 95 process : function(){ 96 97 var This = this; 98 //绘画计时器 99 this.processId = setInterval(function(){ 100 101 if(!This.isStart)return; 102 //清除画布 103 Canvas.clear(This.gameInfo.width,This.gameInfo.hei ght); 104 //判断飞机是否移动 105 if(This.fly.checkMove())This.fly.move(This.gameInfo) ; 106 //画飞机 107 Canvas.drawImg(This.fly); 108 //生产子弹 109 This.createBullets(); 110 //画出所有子弹 111 for(var i=0,l=This.bullets.length;i<l;i++){ 112 113 var bullet = This.bullets[i]; 114 115 if(!bullet)continue; 116 //更新子弹信息 117 bullet.updata(This.gameInfo); 118 //画子弹 119 Canvas.drawImg(bullet); 120 //检测是否撞到飞机 121 if(bullet.checkCrashFly(This.fly)){ 122 This.end(); 123 } 124 } 125 //画分数 126 Canvas.drawText(Math.floor(This.score/1000)+"秒",20,20,'white'); 127 This.score += 10; 128 },10); 129 }, 130 //键盘按下事件 131 keyDown : function(e){ 132 133 var This =this; 134 //游戏还没开始,而且按了回车 135 if(e.keyCode == 13 && !this.isStart){ 136 e.preventDefault(); 137 //开始 138 this.start(); 139 } 140 //游戏开始而且按了方向键 141 if(e.keyCode >= 37 && e.keyCode <= 40 && this.isStart){ 142 e.preventDefault(); 143 144 This.fly.keyDown(e.keyCode); 145 } 146 }, 147 //键盘释放事件 148 keyUp : function(e){ 149 150 var This = this; 151 //释放了方向键 152 if(e.keyCode >= 37 && e.keyCode <= 40){ 153 e.preventDefault(); 154 155 This.fly.keyUp(e.keyCode); 156 } 157 }, 158 //移除子弹 159 removeBullet : function(item){ 160 161 for(var i=0,l=this.bullets.length;i<l;i++){ 162 163 if(this.bullets[i] == item){ 164 this.bullets.splice(i,1); 165 return true; 166 } 167 } 168 } 169 170 } 突然发觉自己写的那些,为啥会那么卡了。。。因为,我以前都是计时器分开来写,后来才发现,要放在同一个计时器去做动画。。。 希望大家喜欢,有啥不好的,欢迎指出。。。 源码下载>> |
|