引言:
前兩天看到小朋友在玩植物大戰僵尸,想起來多年以前自己也經常玩這個游戲,是比較經典的一款休閑游戲,然后就心血來潮就周末寫了一個,花了不少時間去找素材和撰寫代碼,感覺上基本的功能是做好了(要上班,沒那么多時間搞),寫出來大家看看,確實有點爆肝!
效果圖:



實作思路
- 用兩張畫布來實作,第一個畫布繪制不用更新的東西,比如背景圖、按鈕、積分圖,卡牌圖等;
- 第二個畫布,繪制經常更新的東西,比如僵尸的走動、僵尸吃植物、僵尸死亡、植物的搖擺、豌豆苗發射豌豆、子彈的運動、陽光的產生、陽光的收集等等;
- 影片的實作,通過圖片的不停切換來實作的,開啟一個總定時任務100毫秒重新繪制畫布2,當然其他的每個影片都會重新開啟定時任務(我稱他們為子任務),它們不負責繪制,只負責改變對應的引數,繪制都是由總任務來完成的, 比如僵尸走動影片:開啟子任務100毫秒執行一次圖片切換,切換到最后一張的時候,回傳到第一張,如果要走動的話同時改變圖片的位置就好,子任務修改完成后,總任務自然會繪制出來;
- 卡牌的實作,目前就寫了2張卡牌(向日葵、豌豆苗),給卡牌繪制了相同大小的方形來控制滑鼠點擊事件,當點擊卡牌的時候,會創建對應的植物并且跟隨滑鼠移動,移動滑鼠到合適的位置后點擊(田 里面對應的方塊),會在對應的位置種植;
- 田位置的控制,以方形來劃分,每一塊可以種植物的區域都用一個小方塊來控制,植物就種在對應的方塊內,當選擇一個卡牌后,滑鼠移動到田里面就會標示出來一個方形的區域,標示植物種植在這塊區域里面,
- 豌豆苗被種植后,會定時的發射子彈,當子彈的位置和僵尸的位置交匯的時候,就判斷為擊中(處理子彈擊中影片、子彈消失、僵尸扣除相應血量、擊中的音效等),僵尸血量歸零后會停止走動的影片,開啟新的倒地影片,倒地完成后洗掉僵尸,同時累計得到的分數;
- 當僵尸的位置和植物的位置交匯的時候,僵尸會停止行走的影片,開啟吃的影片(植物被扣除血量、僵尸吃的音效),植物血量歸零后,植物物件會被清理;
- 陽光有兩種產生方式,定時產生和向日葵產生,產生后會開啟往下飄的影片,飄到一定范圍后停止影片、開啟計數器(目前設定為10秒),計數歸零沒有此陽光依然未被點擊收集的話就會消失,在指定時間內點擊了該陽光(音效),則會開啟往左上角飛行的影片,到終點后陽光消失,陽光分增加(音效);
- 結束條件: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);
}

點擊開始的邏輯
點擊開始就是游戲的入口,游戲的大部分功能都是在這個邏輯里面實作,包含:
展示開始圖片、開啟背景音樂、陽光計分顯示、積分顯示、創建田的背景方形、創建卡牌的背景方形、開啟總任務、定時創建太陽光、定時創建僵尸,
展示開始圖片
//展示開始圖片
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秒后自動清除掉這個圖片

陽光計分顯示
//創建陽光分
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<this.cardArr.length;i++){
var item=this.cardArr[i];
fillStyle = this.sunTotalCount>=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坐標以及寬高,這樣創建的方形就會和背景相對應,種植物的時候就比較好控制了,解釋如下:

上圖是我自己隨便畫的,也沒有畫好、沒畫全,實際上每個里面都有,并且比較整齊,我把代碼稍微修改一下截圖,最終的代碼肯定不是這樣的哦

這樣,就把田的區域一塊塊的覆寫起來,但我們這里也是要用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<plants.length;i++){
var item=plants[i];
if(item.index==zomble.index){
if(item.dx+item.dWidth-20>=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];
}
}
點擊卡牌后移動滑鼠,向日葵會跟隨滑鼠移動,移動到田的方形位置,則此塊方形的顏色會突出,點擊它則會種植下去,

創建豌豆植物
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<arr.length;i++){
var item = arr[i];
if(item.dx<=obj.dx+obj.dWidth && obj.index==item.index ){//子彈的函式標示與僵尸的行數標示也要相等
item.blood--;
if(item.blood==0){//消滅這個僵尸
clearInterval(item.timmer);
if(item.state=='run'){
item.imageKey=item.key=item.key+this.zombiesRunCount+this.wandousRunCount;//設定死亡圖片下標
}else if(item.state=='eat'){
item.imageKey=item.key=item.key-this.sunRunCount-this.zombiesDeadCount;//設定死亡圖片下標
}
item.state='dead';
this.addCount();//增加積分
this.dead(item);//死亡影片
arr.splice(i,1);
}
return true;
}
}
}

加入事件控制
//給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<this.cardRectArr.length;i++){
var item=this.cardRectArr[i];
if(item.isPoint(pos) && item.alive){//滑鼠捕捉
isCatch=true;
break;
}
}
}
}
if(!isCatch){
//回圈太陽陣列
for(var i=0;i<this.suns.length;i++){
var item=this.suns[i];
if(item.isPoint(pos)){//滑鼠捕捉
isCatch=true;
break;
}
}
}
var plant = this.currPlant;
if(!isCatch){
if(plant){//創建植物的時候,才出現填入背景框
//回圈田背景陣列
for(var i=0;i<this.bgRectArr.length;i++){
var item=this.bgRectArr[i];
if(item.isPoint(pos) && !item.plant){//滑鼠捕捉,并且當前沒有植物
isCatch=true;
item.fillStyle="rgba(0,250,154, 0.5)";
}else{
item.fillStyle="rgba(0,250,154, 0)";
}
}
}
}
if(isCatch){
this.el.style.cursor = 'pointer';//改為手狀形態
}else{
this.el.style.cursor = '';
}
//表示當前正在創建植物
if(plant){
plant.dx=pos.x;
plant.dy=pos.y;
}
this.render2();
}
滑鼠點擊事件
//滑鼠點擊事件
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<this.cardRectArr.length;i++){
var item=this.cardRectArr[i];
if(item.isPoint(pos) && item.alive){//滑鼠捕捉
isCatch=true;
//生成一個新的豌豆苗,跟隨滑鼠移動
this.createPlant(pos,item);//創建植物
break;
}
}
}
}
if(!isCatch){
//回圈太陽陣列
for(var i=0;i<this.suns.length;i++){
var item=this.suns[i];
if(item.isPoint(pos)){//滑鼠捕捉
item.click && item.click();
break;
}
}
}
if(!isCatch){
var plant = this.currPlant;
if(plant){//正在創建植物
//回圈田背景陣列
for(var i=0;i<this.bgRectArr.length;i++){
var item=this.bgRectArr[i];
if(item.plant) continue;//如果當前有植物,則跳過
if(item.isPoint(pos)){//滑鼠捕捉
isCatch=true;
plant.dx=item.x+10;
plant.dy=item.y+20;
plant.index=item.index;//給plant設定行數
plant.alive(item);//植物生效
item.plant=true;//表示有植物
item.fillStyle="rgba(0,250,154, 0)";
this.currPlant=null;
break;
}
}
}
}
}
滑鼠右鍵事件
//右鍵事件
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<this.bgRectArr.length;i++){
var item=this.bgRectArr[i];
item.fillStyle="rgba(0,250,154, 0)";
}
}
總結
基本的功能實作了,但是有很多沒有實作的功能這里交代一下,確實沒有時間去搞了,要上班,,,,,,不能像在座賺了幾個億的大佬一樣逍遙自在:
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)有原始碼,你的畢設我的心(附原始碼)?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/278490.html
標籤:其他
