这篇文章我们来讲一讲用canvas画一个躲水果的小游戏。就是通过手指控制一个人物移动来躲避水果,若发生碰撞,则游戏结束。
我们定义一个game_control对象来处理初始化,事件绑定,游戏开始,游戏结果判定,游戏结束等判定。
在游戏中,我们需要一个人物以及三种水果的图片,我们做成了雪碧图。
接下来直接上代码吧~
首先我们定义一个ship对象,3个水果、一个人物都是基于这个对象的。
function ship(options){ if (options) { var width=options.width, height=options.height; this.x=options.x; this.y=options.y; this.width=width; this.height=height; this.first_x=options.x; this.first_y=options.y; this.speedx=options.speedx; this.speedy=options.speedy; this.csspeedx=options.speedx; this.csspeedy=options.speedy; this.xDirection=options.xDirection||1;//x轴方向 this.yDirection=options.yDirection||1;//y轴方向 var canvasOffscreen = document.createElement('canvas'); canvasOffscreen.width =width; canvasOffscreen.height =height; canvasOffscreen.getContext('2d').drawImage(options.image, options.sourcex, options.sourcey, options.sourcewidth, options.sourceheight, 0, 0, width, height); this.canvasOffscreen=canvasOffscreen; this.init(); } } ship.prototype={ init:function(){ }, reset:function(){ }, draw:function(ctx){ //let canvasOffscreen=this.canvasOffscreen; ctx.drawImage(this.canvasOffscreen, this.x, this.y); }, move:function(modifier){ this.x+=this.xDirection*this.speedx * modifier; this.y+=this.yDirection*this.speedy * modifier; if(this.x>winwidth-this.width){ this.x=winwidth-this.width; this.xDirection=-1; }else if(this.x<0){ this.x=0; this.xDirection=1 } if(this.y>winheight-this.height){ this.y=winheight-this.height; this.yDirection=-1; }else if(this.y<0){ this.y=0; this.yDirection=1; } } }
当我们用canvas绘制人物和水果时,可以采用离屏绘制的方法,就是先将每个水果,人物绘制一遍,然后每次重绘的时候,再用canvas将这个已绘制的绘制出来就可以了,这样效率会比每次都直接绘制图片要高
var canvasOffscreen = document.createElement('canvas'); canvasOffscreen.width =width; canvasOffscreen.height =height; canvasOffscreen.getContext('2d').drawImage(options.image, options.sourcex, options.sourcey, options.sourcewidth, options.sourceheight, 0, 0, width, height); ctx.drawImage(this.canvasOffscreen, this.x, this.y);
接下来说一下game_control 初始化init方法吧
init:function(){ var canvas=document.getElementById('game-canvas'), self=this, ctx=canvas.getContext('2d'); self.ctx=ctx; canvas.width=winwidth; canvas.height=winheight; let img=new Image(); img.onload=function(){ var zjb=new hero({ image:img, x:gettruesize(250), y:gettruesize(56), gettruesize(50), height:gettruesize(50), source104, sourceheight:104, sourcex:0, sourcey:0 }); for(var i=0;i<3;i++){ var x=60,y=110; if(i==1){x=38,y=330;} if(i==2){x=218,y=338;} var monster=new ship({ image:img, x:gettruesize(x), y:gettruesize(y), gettruesize(50), height:gettruesize(50), source104, sourceheight:104, speedx:gettruesize(getrandom(60,100)), speedy:gettruesize(getrandom(60,100)), sourcex:104*(i+1), sourcey:0 }); self.monsters.push(monster); } self.objs=zjb; self.draw(); self.bindmove(canvas,zjb); } img.src="all.png"; }
主要作用是当 雪碧图载入完成后,定义出一个人物对象以及3个水果对象,并通过draw方法将他们用canvas绘制出来,同时给人物对象进行手指事件的绑定(bindmove方法)
接下来讲讲bindmove方法
bindmove:function(canvas,hero){ let self=this; canvas.addEventListener('touchstart', function(e) { var event = e||window.event, csx = event.touches[0].clientX, csy = event.touches[0].clientY, nanshengcsx = hero.x, nanshengcsy = hero.y; if (csx <= hero.x + hero.width && csx >= hero.x && csy <= hero.y + hero.height && csy >= hero.y) { if (!self.startstate) { self.start(); timer = setInterval(function(){ self.draw(); }, 1); } document.addEventListener('touchmove', move,false); function move(e){ e.preventDefault(); var event = e||window.event, nowx = event.touches[0].clientX, nowy = event.touches[0].clientY; hero.x = nanshengcsx + nowx - csx; hero.y = nanshengcsy + nowy - csy; if(hero.x<0){ hero.x=0; }else if(hero.x+hero.width>winwidth){ hero.x=winwidth-hero.width; } if(hero.y<0){ hero.y=0; }else if(hero.y+hero.height>winheight){ hero.y=winheight-hero.height; } } function moveend(e){ document.removeEventListener('touchend',moveend); document.removeEventListener('touchmove',move); } document.addEventListener('touchend', moveend ,false); } },false); }
这个方法用来判断手指触碰屏幕时是否在 人物这个位置,如果是,则游戏开始(触发start方法),并注册移动事件,跟随手指移动而移动。
start方法中定义一个循环,让canvas 一帧一帧的画。
start:function(){ var self=this; this.startstate=true; this.then=Date.now(); this.starttime=this.then; document.getElementById('tips').style.display="none"; timer = setInterval(function(){ self.draw(); }, 1); }
最后还要一个check方法,来判断人物与水果间有没有发生触碰,若有则游戏结束。
check:function(){ var last=this.then-this.starttime; var monsters=this.monsters; var nansheng=this.objs; if (this.monsterSum != Math.floor(last / 5000)){//如果时间经过5秒就增加一个怪兽实例 this.monsterSum ++; for(var i=0;i<monsters.length;i++){ monsters[i].speedx+=60; monsters[i].speedy+=60; } } for(var i=0;i<monsters.length;i++){ var monster1=monsters[i]; if ((monster1.x - nansheng.width) <= nansheng.x && nansheng.x <= (monster1.x + monster1.width) && (monster1.y - nansheng.height) <= nansheng.y && nansheng.y <= (monster1.y + monster1.height)) { this.end(); } } }
这样一个简单的小游戏就完成啦~