基于JavaScript Canvas的植物大战僵尸,周末爆肝之作,请点个赞再走!

引言:

前两天看到小朋友在玩植物大战僵尸,想起来多年以前自己也经常玩这个游戏,是比较经典的一款休闲游戏,然后就心血来潮就周末写了一个,花了不少时间去找素材和编写代码,感觉上基本的功能是做好了(要上班,没那么多时间搞),写出来大家看看,确实有点爆肝!

效果图:

实现思路

  1. 用两张画布来实现,第一个画布绘制不用更新的东西,比如背景图、按钮、积分图,卡牌图等;
  2. 第二个画布,绘制经常更新的东西,比如僵尸的走动、僵尸吃植物、僵尸死亡、植物的摇摆、豌豆苗发射豌豆、子弹的运动、阳光的产生、阳光的收集等等;
  3. 动画的实现,通过图片的不停切换来实现的,开启一个总定时任务100毫秒重新绘制画布2,当然其他的每个动画都会重新开启定时任务(我称他们为子任务),它们不负责绘制,只负责改变对应的参数,绘制都是由总任务来完成的, 比如僵尸走动动画:开启子任务100毫秒执行一次图片切换,切换到最后一张的时候,返回到第一张,如果要走动的话同时改变图片的位置就好,子任务修改完成后,总任务自然会绘制出来;
  4. 卡牌的实现,目前就写了2张卡牌(向日葵、豌豆苗),给卡牌绘制了相同大小的方形来控制鼠标点击事件,当点击卡牌的时候,会创建对应的植物并且跟随鼠标移动,移动鼠标到合适的位置后点击(田 里面对应的方块),会在对应的位置种植;
  5. 田位置的控制,以方形来划分,每一块可以种植物的区域都用一个小方块来控制,植物就种在对应的方块内,当选择一个卡牌后,鼠标移动到田里面就会标示出来一个方形的区域,标示植物种植在这块区域里面。
  6. 豌豆苗被种植后,会定时的发射子弹,当子弹的位置和僵尸的位置交汇的时候,就判断为击中(处理子弹击中动画、子弹消失、僵尸扣除相应血量、击中的音效等),僵尸血量归零后会停止走动的动画,开启新的倒地动画,倒地完成后删除僵尸,同时累计得到的分数;
  7. 当僵尸的位置和植物的位置交汇的时候,僵尸会停止行走的动画,开启吃的动画(植物被扣除血量、僵尸吃的音效),植物血量归零后,植物对象会被清理;
  8. 阳光有两种产生方式,定时产生和向日葵产生,产生后会开启往下飘的动画,飘到一定范围后停止动画、开启计数器(目前设定为10秒),计数归零没有此阳光依然未被点击收集的话就会消失,在指定时间内点击了该阳光(音效),则会开启往左上角飞行的动画,到终点后阳光消失,阳光分增加(音效);
  9. 结束条件:1)僵尸触及田的最左边--判定为失败。2)得分300--判定为胜利!

实现

绘制背景

	//绘制背景
	Plants.prototype.drawBG=function(){
		var image,img,sx=150,sy=0,sWidth=900,sHeight=600,dx=0,dy=0,dWidth=900,dHeight=600;
		//背景
		image = this.imgObj[1];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.renderArr.push(img);
	}

绘制上方的卡牌区域、积分区域,相关按钮

//绘制游戏上方的相关图片(卡片等)
	Plants.prototype.drawCard=function(){
		var image,img,sx=0,sy=0,sWidth=446,sHeight=87,dx=0,dy=0,dWidth=446,dHeight=80;
		//方形卡片盘
		image = this.imgObj[2];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.renderArr.push(img);
		
		sWidth=128,sHeight=31,dx=450,dy=0,dWidth=128,dHeight=40;
		//积分
		image = this.imgObj[12];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.renderArr.push(img);
		
		sWidth=50,sHeight=70,dx=76,dy=5,dWidth=50,dHeight=68;
		//方形卡片 太阳花
		image = this.imgObj[3];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		img.sunCost=50;//生产一个苗需要50阳光
		img.type='sun';//植物类型
		this.renderArr.push(img);
		this.cardArr.push(img);
		
		sWidth=50,sHeight=70,dx=130,dy=4,dWidth=50,dHeight=70;
		//方形卡片 豌豆
		image = this.imgObj[4];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		img.sunCost=100;//生产一个苗需要100阳光
		img.type='wandou';//植物类型
		this.renderArr.push(img);
		this.cardArr.push(img);

		
		sWidth=97,sHeight=33,dx=780,dy=8,dWidth=97,dHeight=33;
		//开始按钮图片
		image = this.imgObj[5];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.startImage=img;
		this.renderArr.push(img);
		
		sWidth=97,sHeight=33,dx=650,dy=8,dWidth=97,dHeight=33;
		//创建僵尸图片
		image = this.imgObj[8];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.createZombiesImage=img;
		this.renderArr.push(img);
	}

基于JavaScript Canvas的植物大战僵尸,周末爆肝之作,请点个赞再走!_第1张图片

点击开始的逻辑

点击开始就是游戏的入口,游戏的大部分功能都是在这个逻辑里面实现,包含

展示开始图片、开启背景音乐、阳光计分显示、积分显示、创建田的背景方形、创建卡牌的背景方形、开启总任务、定时创建太阳光、定时创建僵尸。

展示开始图片

//展示开始图片
	Plants.prototype.startShow=function(){
		var image,img,sx=0,sy=0,sWidth=225,sHeight=108,dx=this.w/2-110,dy=this.h/2-100,dWidth=225,dHeight=108;
		image = this.imgObj[10];
		img = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.renderArr2.push(img);
		
		var that=this;
		setTimeout(function(){
			that.clear(img);
		},2000);
	}

这里设置一个延时2秒后自动清除掉这个图片

基于JavaScript Canvas的植物大战僵尸,周末爆肝之作,请点个赞再走!_第2张图片

阳光计分显示

//创建阳光分
	Plants.prototype.createSunText=function(){
		x=40,y=74,content=this.sunTotalCount;
		var	text = new _.Text({
			x:x,
			y:y,
			text:content,
			font:'20px ans-serif',
			textAlign:'center',
			fill:true,
			fillStyle:'green'
		});	
		this.renderArr2.push(text);	
		this.sunCountObj=text;
	}

积分显示

	//创建积分
	Plants.prototype.createCountText=function(){
		x=530,y=34,content=this.curCount;
		var	text = new _.Text({
			x:x,
			y:y,
			text:content,
			font:'30px ans-serif',
			textAlign:'center',
			fill:true,
			fillStyle:'pink'
		});	
		this.renderArr2.push(text);	
		this.countObj=text;
	}

创建卡牌的背景方形(用于监听鼠标点击卡牌)

根据卡牌数组来创建,循环这个数组,方形的坐标和宽高与卡牌数组元素相对应,并且方形的fillStyle采用rgba来处理,如:rgba(192,192,192,0)  rgba(192,192,192,0.6),当最后一个数字是0的时候卡牌可用,当为0.6的时候,卡牌会被遮罩起来不可用(不可用是在鼠标点击的时候控制,这里只是一个遮罩的效果),当然这里会设置一个参数alive,当它为true表示可用,false则点击无效,鼠标点击的时候就是根据这个参数来控制的。

	//创建卡片背景方形
	Plants.prototype.createCardBGRect=function(){
		var x=0,y=0,rect,fillStyle,alive;
		for(var i=0;i=item.sunCost? 'rgba(192,192,192,0)':'rgba(192,192,192,0.5)';
			alive = this.sunTotalCount>=item.sunCost? true:false;
			rect = new _.Rect({
				x:item.dx,
				y:item.dy,
				width:item.dWidth,
				height:item.dHeight,
				fill:true,
				fillStyle:fillStyle
			 })
			 rect.sunCost=item.sunCost;//设定需要花费的阳光数值
			 rect.alive=alive;
			 rect.type=item.type;
			 this.renderArr2.push(rect);
			 this.cardRectArr.push(rect);
		}
		
	}

创建田的背景方形(用于监听植物的种植)

根据背景上田的规格,来设置好X、Y坐标以及宽高,这样创建的方形就会和背景相对应,种植物的时候就比较好控制了,解释如下:

上图是我自己随便画的,也没有画好、没画全,实际上每个里面都有,并且比较整齐,我把代码稍微修改一下截图,最终的代码肯定不是这样的哦

基于JavaScript Canvas的植物大战僵尸,周末爆肝之作,请点个赞再走!_第3张图片

这样,就把田的区域一块块的覆盖起来,但我们这里也是要用rgba的方式来,种植物的时候才会突出显示

//创建植物田背景方形
	Plants.prototype.createBGRect=function(){
		var x=0,y=0,rect;
		for(var i=1;i<=5;i++){//5行
			y = 75+(i-1)*100;
			for(var j=1;j<=9;j++){//9列
				x = 105+(j-1)*80;
				rect = new _.Rect({
					x:x,
					y:y,
					width:80,
					height:100,
					fill:true,
					//fillStyle:_.getRandomColor()
					fillStyle:'rgba(0,250,154, 0)'
				 })
				 rect.index=i;//标记行数
				 this.renderArr2.push(rect);
				 this.bgRectArr.push(rect);
			}
		}
	}

创建阳光

1、向日葵植物创建阳光和定时创建阳光都放到这里了,他们的区别是:定时创建的X坐标随机产生,而向日葵创建的阳光X、Y坐标是根据向日葵的位置来的。

2、设定阳光的分值、阳光的血量、阳光默认运动的终点位置(这个位置可以自己定,我定义Y坐标的是400),阳光为什么有血量呢?这个血量是用来控制消失时间的,比如我设定血量为100,当阳光运动到底部停止运动后,就会开启计算血量的任务,每100毫秒执行一次,让血量 -1,因100毫秒执行10次是1秒,1秒后血量就变成90了,当血量归零后如若依然没有去收集这个阳光,需要让阳光消失,同时关闭此定时器。

3、当点击阳光后,就把计算血量的定时器关闭,开启向左上角运动的动画,当然这里要用到  Math.atan2 根据阳光点击的位置和做上角的位置,计算出角度,然后根据角度利用Math.cos、Math.sin 计算出运动的X、Y的数值,定时器将根据这个数值来运动。

4、运动指定的位置后,要做以下动作:清除运动定时器、阳光积分累加与显示、收集音效开启、阳光消失、卡牌可用状态的更新。

//创建阳光
	Plants.prototype.createSun=function(plant){
		var image,sun,sx=0,sy=0,sWidth=77,sHeight=74,dx=0,dy=70,dWidth=45,dHeight=44;
		
		if(plant){//这种是植物创建的太阳
			dx = plant.dx;
			dy = plant.dy;
		}else{
			dx = _.getRandom(200,800);//x方形随机200-800
		}
		
		//绘制时的图片下标
		var startKey=this.count+this.zombiesRunCount+this.wandousRunCount+this.zombiesDeadCount+1;
		//方形卡片盘
		image = this.imgObj[startKey];
		sun = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		sun.imageKey=startKey;//执行动画更新的下标
		sun.key=startKey;//原始下标
		sun.value=20;//收集一个20分
		sun.blood=100;//默认10点血量(10秒消失,因为我给太阳设置的是100毫秒执行一次,所以这个blood设置为100,每次-1 ,10秒就刚好100)
		sun.floor=400;//到底的位置
		this.renderArr2.push(sun);
		
		this.suns.push(sun);
		
		sun.timmer = setInterval(animate.bind(this,sun),100);
		function animate(z){
			var that=this;
			z.imageKey ++;
			//一个循环了,重新回到初始位置
			if(z.imageKey>=(that.sunRunCount+z.key)){
				z.imageKey=z.key;
			}
			z.image = that.imgObj[z.imageKey];
			z.dy+=2;
			if(z.dy>=z.floor){
				//console.log('太阳到位置了');
				clearInterval(z.timmer);
				//开启定时任务,多少秒以后消失
				sun.timmer = setInterval(time.bind(this,sun),100);
			}
		}
		
		//太阳计时
		function time(z){
			var that=this;
			z.imageKey ++;
			//一个循环了,重新回到初始位置
			if(z.imageKey>=(that.sunRunCount+z.key)){
				z.imageKey=z.key;
			}
			z.image = that.imgObj[z.imageKey];
			//计算消失时间
			z.blood--;
			if(z.blood<=0){
				clearInterval(z.timmer);
				//console.log('太阳到时间了');
				fade.call(this,z);//执行消失
			}
		}
		
		//太阳消失
		function fade(z){
			this.clear(z);
			//console.log('太阳消失了');
			this.clearAssign(this.suns,z);//清楚指定对象
			z=null;
		}
		//太阳被点击
		function sunClick(z){
			//console.log('太阳被点击了')
			clearInterval(z.timmer);//清楚之前的定时器
			
			this.pointsMusic.play();
			
			var cx=cy=20;//收集点的X\Y坐标
			var angle = Math.atan2((z.dy-cy), (z.dx-cx))  //弧度 
			
			//计算出X\Y每一帧移动的距离
			var mx = my=0;
			mx = Math.cos(angle)*20;
			my = Math.sin(angle)*20;
			z.mx=mx,z.my=my;
			//开启移动定时器
			z.timmer = setInterval(sunCollect.bind(this,z),100);
		}
		//收集太阳动画
		function sunCollect(z){
			var that=this;
			z.imageKey ++;
			//一个循环了,重新回到初始位置
			if(z.imageKey>=(that.sunRunCount+z.key)){
				z.imageKey=z.key;
			}
			z.image = that.imgObj[z.imageKey];
			z.dx-=z.mx;
			z.dy-=z.my;
			if(z.dy<=20||z.dx<=20){
				//console.log('太阳收集完成');
				clearInterval(z.timmer);
				
				this.moneyfallsMusic.play();
				
				fade.call(this,z);//执行消失
				//计数累加
				that.sunTotalCount+=z.value;
				
				//更新卡片是否可用情况
				that.updateCardUse();
				//更新阳光数值
				that.sunCountObj.text=that.sunTotalCount;
			}
		}
		
		sun.click=sunClick.bind(this,sun);//给这个sun对象绑定点击函数
	}

创建僵尸

1、创建僵尸:定时(10秒)、随机数量(1-5只)、随机行(1-5行,这里表示出现在地图的哪一行)。

2、设定僵尸的血量、僵尸所处的行数、僵尸的状态(run、eat、dead),状态是用来控制切换图片的下标的,不然动画会出错。

3、行走动画依赖于图片的切换和X坐标的改变(每一帧x坐标 减少2即可)。

4、每一帧都要判断x坐标与植物的坐标是否交汇,如果是先关闭行走的动画,更新状态为 eat ,开启吃的动画,切换图片的下标。

5、每一次吃的时候递减植物的血量,判断植物的血量,如果血量归零则表示吃完了,此时要清理掉植物,僵尸回归行走的动画,状态改为run;若没吃完则继续吃。

6、每一帧也要判断僵尸的x坐标是否到了最左边,如果是游戏结束。

创建

	//创建僵尸
	Plants.prototype.createZombie=function(){
		var image,zomble,sx=0,sy=0,sWidth=75,sHeight=119,dx=900-75,dy=270,dWidth=75,dHeight=119;
		
		var index = _.getRandom(1,6);//随机获取1\2\3\4\5 行数
		if(index==1){
			dy=60;
		}else if(index==2){
			dy=160;
		}else if(index==3){
			dy=260;
		}else if(index==4){
			dy=355;
		}else if(index==5){
			dy=460;
		}
		
		//绘制时的图片下标
		var startKey=this.count+1;
		//方形卡片盘
		image = this.imgObj[startKey];
		zomble = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		zomble.imageKey=startKey;//执行动画更新的下标
		zomble.key=startKey;//原始下标
		zomble.blood=10;//默认10点血量
		zomble.index=index;//设定僵尸的行数
		zomble.state='run';
		this.renderArr2.push(zomble);
		this.zombies.push(zomble);
		
		zomble.run=run.bind(this);
		
		zomble.run();
		
		function run(){
			zomble.timmer = setInterval(animate.bind(this,zomble),100);
		}
		function animate(z){
			var that=this;
			z.imageKey ++;
			//一个循环了,重新回到初始位置
			if(z.imageKey>=(that.zombiesRunCount+z.key)){
				z.imageKey=z.key;
			}
			z.image = that.imgObj[z.imageKey];
			z.dx-=2;
			//判断有没有接触到植物,如果有开始吃植物 
			that.eat(zomble)
			
			if(z.dx<=100){
				console.log('结束了');
				that.end();
			}	
		}
	}

僵尸吃

//僵尸吃
	Plants.prototype.eat=function(zomble){
		//先判断当前僵尸有没有到达吃的位置,有的话就开始吃,关闭掉之前的僵尸动画,开始吃的动画
		var plants=this.plants;
		var plant;//被捕获的植物
		for(var i=0;i=zomble.dx){//判断为吃
					plant=item;
					break;
				}
			}
			
		}
		if(plant){
			clearInterval(zomble.timmer);//清除移动动画
			zomble.imageKey=zomble.key=this.count+this.zombiesRunCount+this.wandousRunCount+this.zombiesDeadCount+this.sunRunCount+1;//设定key
			zomble.state='eat';
			zomble.timmer = setInterval(animate.bind(this,zomble,plant),100);
		}
		
		function animate(z,p){
			this.eatMusic.play();
			var that=this;
			z.imageKey ++;
			//一个循环了,重新回到初始位置
			if(z.imageKey>=(that.zombiesEatCount+z.key)){
				z.imageKey=z.key;
			}
			z.image = that.imgObj[z.imageKey];
			
			p.blood--;//植物血量的处理
			if(p.blood<=0){
				//console.log('植物被吃了');
				clearInterval(z.timmer);
				//清除植物
				this.delPlant(p);
				zomble.state='run';
				zomble.imageKey=zomble.key=this.count+1;//设定key
				//继续移动
				z.run();
			}
		}
	}

删除植物

//删除掉植物
	Plants.prototype.delPlant=function(plant,type){
		if(!type){//还没有创建的植物不需要清除这两个任务
			//停止植物自身的动画
			clearInterval(plant.timmerSelf);
			//停止植物发射子弹的动画
			clearInterval(plant.timmer);
		}
		//渲染中删除
		this.clear(plant);
		//plants数组中删除
		this.clearAssign(this.plants,plant);
		//植物对应的背景处理
		if(plant.bgRect){
			plant.bgRect.alive=false;
			plant.bgRect.plant=false;
		}
		plant=null;
	}

创建向日葵

1、点击卡牌后的创建,所以肯定是要传入鼠标的位置,创建的跟随鼠标移动(此时向日葵已经创建)

2、设定 alive 函数,当在田里面选中位置后,执行此函数,进行种植操作。

3、扣除阳光花费、更新卡牌是否可用、开启定时产生阳光的任务。

	//创建太阳植物
	Plants.prototype.createSunPlant=function(pos,item){
		var image,plant,sx=0,sy=0,sWidth=63,sHeight=73,dx=110,dy=300,dWidth=63,dHeight=73;
		dx = pos.x,dy=pos.y;//设定初始位置为鼠标的位置
		//绘制时的图片下标
		var startKey=this.count+this.zombiesRunCount+this.wandousRunCount+this.zombiesDeadCount+this.sunRunCount+this.zombiesEatCount+1;
		//方形卡片盘
		image = this.imgObj[startKey];
		plant = new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		plant.imageKey=startKey;//执行动画更新的下标
		plant.key=startKey;//原始下标
		plant.sunCost=item.sunCost;//阳光花费值
		plant.blood=50;//设定为50血量,实际是5秒吃完,因为100毫秒计算一次吃
		plant.id='SunPlant';
		this.renderArr2.push(plant);
		
		this.plants.push(plant);
		this.currPlant=plant;//标记正在创建的植物
		
		plant.alive=alive.bind(this);
		
		function alive(bgRect){
			//设置背景对象
			plant.bgRect=bgRect;
			//扣除阳光花费
			this.sunTotalCount-=plant.sunCost;
			//更新卡片是否可用情况
			this.updateCardUse();
			//更新阳光数值
			this.sunCountObj.text=this.sunTotalCount;
			//每6秒发射一个阳光
			plant.timmer = setInterval(shoot.bind(this),6000);
			this.plantMusic.play();//音乐
		}
		
		function shoot(){
			this.createSun(plant);
		}
		//植物本身的动画
		plant.timmerSelf = setInterval(animate.bind(this,plant),100);
		function animate(p){
			var that=this;
			p.imageKey ++;
			//一个循环了,重新回到初始位置
			if(p.imageKey>=(that.sunPlantRunCount+p.key)){
				p.imageKey=p.key;
			}
			p.image = that.imgObj[p.imageKey];
		}
	}

点击卡牌后移动鼠标,向日葵会跟随鼠标移动,移动到田的方形位置,则此块方形的颜色会突出,点击它则会种植下去。

基于JavaScript Canvas的植物大战僵尸,周末爆肝之作,请点个赞再走!_第4张图片

创建豌豆植物

1、与向日葵的创建很相似,就不同的时候向日葵创建的是阳光,豌豆植物创建的是小豌豆,可以攻击僵尸的。

2、子弹在运动的时候、判断是否与僵尸接触,如果接触则执行击中的动画、删除这个子弹、减去僵尸的血量、如果僵尸死亡,则开启僵尸死亡动画,增加积分。

创建

//创建豌豆
	Plants.prototype.createWandou=function(plant){
		var image,img,sx=0,sy=0,sWidth=28,sHeight=28,dx=plant.dx+50,dy=plant.dy,dWidth=28,dHeight=28;
		//绘制时的图片下标
		var startKey=6;
		//方形卡片盘
		image = this.imgObj[startKey];
		var wandou= new _.ImageDraw({image:image,sx:sx,sy:sy,sWidth:sWidth,sHeight:sHeight, dx:dx, dy:dy ,dWidth:dWidth,dHeight:dHeight});
		this.renderArr2.push(wandou);
		
		wandou.index=plant.index;//给子弹设定行数标示
		
		this.shootMusic.play();//射击音乐
		wandou.timmer = setInterval(wandouMove.bind(this,wandou),100);

		function wandouMove(wandou){
			wandou.dx+=10;
			//判断击中僵尸
			var flag = this.hit(wandou);
			if(flag || wandou.dx>850){//击中目标 或者 超出边界
				clearInterval(wandou.timmer);
				if(flag){//击中目标
					//创建子弹击中的图片
					this.hitAnimate(wandou);
					this.hitMusic.play();//击中音乐
				}
				//清除这个子弹
				this.clear(wandou);
				wandou=null;
			}
		}
	}

击中目标

//击中
	Plants.prototype.hit=function(obj){
		var arr = this.zombies;//僵尸对象
		for(var i=0;i

加入事件控制

        //给canvas2画布添加鼠标移动事件(因为画布2在上面)
		canvas2.addEventListener('mousemove',this.mouseMove.bind(this));
		
		//给canvas2画布添加鼠标点击事件(因为画布2在上面)
		canvas2.addEventListener('click',this.mouseClick.bind(this));
		
		//给canvas2画布添加鼠标右键事件(因为画布2在上面)
		canvas2.addEventListener('contextmenu',this.contextMenu.bind(this));

鼠标移动事件

//鼠标移动事件
	Plants.prototype.mouseMove=function(e){
		var that=this;
		if(that.gameOver) return ;//目前设定的是结束后,要刷新页面才可以开始
		if(!this.startImage) return; //防止没加载完成报错
		var pos = _.getOffset(e);//获取鼠标位置
		var isCatch = this.startImage.isPoint(pos);//鼠标捕捉
		
		if(!isCatch  && this.gameAlive){
			isCatch = this.createZombiesImage.isPoint(pos);//鼠标捕捉
		}
		
		if(!isCatch){
			if(this.gameAlive && !this.currPlant) {//游戏开始,并且没有正在创建的植物的时候可以执行
				//循环卡片背景数组
				for(var i=0;i

鼠标点击事件

//鼠标点击事件
	Plants.prototype.mouseClick=function(e){
		if(this.gameOver) return ;//目前设定的是结束后,要刷新页面才可以开始
		var that=this;
		var pos = _.getOffset(e);//获取鼠标位置
		var isCatch = that.startImage.isPoint(pos);//鼠标捕捉
		if(isCatch){
			that.start();
		}
		if(!isCatch && this.gameAlive){
			isCatch = this.createZombiesImage.isPoint(pos);//鼠标捕捉
			if(isCatch){
				that.createZombie();
			}
		}
		if(!isCatch){
			if(this.gameAlive && !this.currPlant) {//游戏开始,并且没有正在创建的植物的时候可以执行
				//循环卡片数组
				for(var i=0;i

鼠标右键事件

//右键事件
	Plants.prototype.contextMenu=function(e){
		var e = e||window.event;
			//取消右键默认事件
		e.preventDefault && e.preventDefault();
		if(this.gameOver) return ;//目前设定的是结束后,要刷新页面才可以开始
		if(!this.startImage) return; //防止没加载完成报错
		if(!this.gameAlive)return;
				console.log('oncontextmenu');
		//正在创建的植物删除
		this.delPlant(this.currPlant,1);
		this.currPlant=null;
		//循环田背景数组
		for(var i=0;i

总结

基本的功能实现了,但是有很多没有实现的功能这里交代一下,确实没有时间去搞了,要上班。。。。。,不能像在座赚了几个亿的大佬一样逍遥自在:

1、结束后必须刷新页面,才能重新开始(”点击开始“按钮)。

2、卡牌支持的作物也比较少,作物也不能用铲子替换。

3、没有过关的感觉、没有车子压僵尸的场景等等(不说了还有好多...)。

如果作为完整的游戏来说,肯定还有很多功能要做、很多地方要完善、其中相当的代码也可以重构;但是如果作为一个练手、学习、思路的分享,我觉得是足够了。

昨天做好的东西,今天晚上写出来也花了不少时间,能看到这里的都是大佬。

欢迎各位大佬 点赞+评论+关注,谢谢!

源码下载

方式1:少量积分,下载代码

方式2:关注下方公众号,回复 129 下载代码

 更多源码

♥ 基于canvas的九宫格抽奖特效(附源码)♥

♥ 基于canvas的手风琴特效(附源码)♥

♥ 抖音很火的华为太空人表盘(附源码)♥

♥ 基于JavaScript页面动态验证码(附源码)♥

♥ 基于JavaScript的拖动滑块拼图验证(附源码)♥

♥ 基于JavaScript的幸运大转盘(附源码)♥

♥ 抖音很火的罗盘时钟(附源码)♥

♥ 基于JavaScript的俄罗斯方块小游戏(附源码)♥

♥ 基于JavaScript的贪吃蛇游戏(附源码)♥

♥ 基于JavaScript的拼图游戏(附源码)♥

♥ 用JavaScript给女儿做的烟花特效(附源码)♥

♥ 老父亲给女儿做的下雪特效,满足女儿看雪的愿望(附源码)♥

♥ 雷达扫描特效(附源码)♥

♥ 香港黄金配角吴孟达去世,80后程序员以轮播图来悼念达叔,达叔一路走好!(附源码)♥

♥ 仿抖音刷新进度条(附源码)♥

♥ 仿头条方形刷新进度条(附源码)♥

♥ 仿360加速球、水波评分特效(附源码)♥

♥ 基于canvas的刮刮卡(附源码)♥

♥ 原生js写的左侧飞入拼图特效,你是喜欢美女单飞还是双飞(附源码)♥

♥ 用js写的旋转木马,在新年献给各位刚登基的皇帝,让你的后宫转起来!程序员就是可以为所欲为!(附源码)♥

♥ 用js写的轮播图,八位女明星,你翻谁的牌,程序员就是可以为所欲为!(附源码)♥

♥ 原生js实现美女拼图,把美女老婆抱回家,5个美女够不够!程序员就是可以为所欲为!(附源码)♥

♥ 用js仿探探拖拽卡片的效果、飞卡片的效果,感觉挺酷,最后有美女看哦!(附源码)♥

♥ 老婆说程序员不懂浪漫,程序员默默拿起了键盘,这就亲手带你去看流星雨,女人真的会影响男人拔刀的速度!(附源码)♥

♥ 学生成绩管理系统(jsp+jquery+java+mysql+tomcat)有源码,你的毕设我的心(附源码)♥

你可能感兴趣的:(canvas,javascript,canvas,植物大战僵尸)