零基礎HTML5游戲制作教程 第6章 貪吃蛇的實現及代碼


第6章 貪吃蛇的實現及代碼

講了不少東西了,老講理論的東西沒勁呀,我們不如先試着做一個小游戲吧。

作為我們的第一個游戲,當然是越簡單越好。《貪吃蛇》大家應該都玩過吧?我覺得我玩過的游戲中,她應該算是最簡單的一個了。好,就讓我們從做《貪吃蛇》開始,享受自己做游戲的樂趣吧。

由於這個游戲是本教程的第一個實際的游戲例子,我會講的比較詳細一些。請大家重點注意編程的思路和實現的方法,這些遠比代碼本身要重要。

 

一,蛇身的制作

蛇身由一系列方格組成,初始我們設定蛇身的長度是4,以后每吃到一次食物就增加1。

我們需要給組成蛇身的每一節一個坐標(可以保存在數組里),並設定一個變量var lenth=4;來存放蛇身的長度。

這樣我們要畫出蛇身的時候就很容易,只要用一個for循環for(i=0;i<lenth;i++)就可以根據坐標,一個一個格子地畫出蛇身。

二,蛇的前進

這個對於初學者來說,可能有一點點困難。因為在某一時間點,整個蛇的前進方向可能是不一樣的。

比如蛇頭正在向下運動,而尾巴可能還在向右。

如果你仔細觀察,你會發現,蛇的下一節的移動方向,就是她的前一節原來所在的地方。

比如蛇的第一節(也就是蛇頭)正在向右移動一格,那么她的第二節,就正在移動到第一節原來所在的地方;同樣,第三節正在移動到第二節原來所在的地方。

這樣就好辦了,我們只要讓下一節的坐標直接等於上一節當前的坐標就可以了。

function move()
{for(i=(lenth-1);i>=1;i--)
 {worma[i]=worma[i-1];
  wormb[i]=wormb[i-1];
 }
}

還剩第一節(蛇頭),因為第一節是沒有上一節的,所以第一節的坐標由蛇目前前進的方向(來自玩家的鍵盤輸入)計算得出。

三,食物的隨機出現

貪吃蛇的食物是隨機出現的。比如在我做的例子里,地圖的寬度是30,高度是20,那么我們可以使用random函數和floor函數來獲得一個寬30高20范圍內的隨機坐標。

(函數中的foodboolean用於判斷當前的food是否存在,如果不存在(=0),就生成新的food,如果已經存在(=1),就不新生成了。)

function getfood()
{if(foodboolean==0)
 {fooda=Math.floor(Math.random()*20);
  foodb=Math.floor(Math.random()*30);
  foodboolean=1;
 }

四,判斷是不是咬到了自己

如果蛇頭(第一節)碰到了她自己身體的其他任意一節,那么這個時候,這2節的坐標是一樣的。我們可以根據這個來判斷是不是咬到自己了。

for(i=1;i<=lenth-1;i++)
{if ((worma[i]==worma[0])&&(wormb[i]==wormb[0]))
  {crash=1;}
}

五,自動前進和防止后退

鍵盤有4個方向,但是貪吃蛇在前進時,只有3個方向。我們只能讓她向前,或左轉,或右轉,而不能向后轉。所以如果玩家按了和當前前進方向相反的鍵盤按鍵,我們必須防止貪吃蛇反向移動。

方法是設定一個變量,direction,用於儲存當前的移動方向。如果玩家沒有新的輸入,那么貪吃蛇一直沿原來的方向走;如果有新的輸入,那么在判斷新的方向“合法”之后,存入direction變量,取代原來的方向。

例子中的direction變量用於儲存當前移動方向,dnext變量用於儲存下一個移動方向。

function fkeydown(kd)
{if(Math.abs(direction-kd.keyCode)!=2)
 {dnext=kd.keyCode;};
}

六,其他的一些說明

 

1,由於javascript不支持二維數組,所以用了2個數組來儲存貪吃蛇的當前坐標,2個數組分別儲存x和y坐標。(當然,可以用1維數組模擬2維,我們下一章講地圖的時候會講到,但是這里沒必要用,直接用2個數組更簡單。)

2,有的人做《貪吃蛇》的時候喜歡把整個地圖做成一個2維數組,然后在每一個地圖的格子內儲存一些值,比如0代表這一格是空的,1代表這一格有被貪吃蛇占據,2代表這一格是食物等等。這當然也可以,但是這樣會比較復雜一點,也占用比較多的內存。因為貪吃蛇是最簡單的游戲,所以我們可以把她盡量簡化,我們可以完全不出現地圖數組,只依靠坐標來判斷。我們可以按照貪吃蛇和食物的坐標,而不是地圖的值,直接把它們畫出來;同樣,根據坐標來直接判斷貪吃蛇是否吃到食物,或者是否撞到她自己。

3,我下面的程序是今天新寫的,為了這個教程才寫的,沒有改過,也沒有經過簡化(其實有部分函數可以合並)。但是我覺得作為零基礎教程來說,每一個函數都很簡單,反而更容易理解,所以就不去簡化了。程序中的主要功能,已經在上面講過了,剩余部分很簡單。

4,本程序使用了結構化的方法,沒有使用面向對象的方法。以后我們在做一些較復雜的游戲時,會使用面向對象。

5,本程序經測試,可以正常使用。

轉載的話,請注明出處,謝謝

CSDN博客:  http://blog.csdn.net/trackstatic/

博客園博客:http://www.cnblogs.com/phyy/   地球生活eev 

(連本段一起復制,就算是注明出處了)

下面是源程序:

<html>
<head>
<title>greedy snake from eev</title>
<script>
var x=0;
var y=0;
var i=0;
var a=0;
var b=0;
var fooda=0;
var foodb=0;
var foodboolean=0;
var lenth=4;
var timer=0;
var direction=39;
var dnext=39;
var crash=0;
var worma=new Array();
var wormb=new Array();
worma[0]=10;
wormb[0]=1;
worma[1]=9;
wormb[1]=1;
worma[2]=8;
wormb[2]=1;
worma[3]=7;
wormb[3]=1;
var nexta=10;
var nextb=1;
function getfood()
{if(foodboolean==0)
 {fooda=Math.floor(Math.random()*20);
  foodb=Math.floor(Math.random()*30);
  foodboolean=1;
 };
}
function next()
{direction=dnext;
 if (direction==37)
 {fleft();}
 else if(direction==38)
 {fup();}
 else if(direction==39)
 {fright();}
 else if(direction==40)
 {fdown();} 
}
function eat()
{lenth=lenth+1;
 move();
 foodboolean=0;
}
function eatormove()
{if((foodboolean==1)&&(nexta==fooda)&&(nextb==foodb))
 {eat();}
 else
 {move();};
}
function move()
{for(i=(lenth-1);i>=1;i--)
 {worma[i]=worma[i-1];
  wormb[i]=wormb[i-1];
 };
 worma[0]=nexta;
 wormb[0]=nextb;
}
function fleft()
{if(wormb[0]>=1)
 nextb=wormb[0]-1;
 else
 nextb=29;
}
function fright()
{if(wormb[0]<29)
 nextb=wormb[0]+1;
 else
 nextb=0;
}
function fup()
{if(worma[0]>=1)
 nexta=worma[0]-1;
 else
 nexta=19;
}
function fdown()
{if(worma[0]<19)
 nexta=worma[0]+1;
 else
 nexta=0;
}
function fkeydown(kd)
{if(Math.abs(direction-kd.keyCode)!=2)
 {dnext=kd.keyCode;};
}
function draw()
{ctx.clearRect(0,0,1200,800);
 for(i=0;i<=lenth-1;i++)
 {x=wormb[i]*40;
  y=worma[i]*40;
  ctx.fillStyle="red";
  ctx.fillRect(x,y,40,40);
 }
 if(foodboolean==1)
 {ctx.fillStyle="green";
  x=foodb*40;
  y=fooda*40;
  ctx.fillRect(x,y,40,40);
 } 
}
function refresh()
{timer=timer+1;
 for(i=1;i<=lenth-1;i++)
 {if ((worma[i]==worma[0])&&(wormb[i]==wormb[0]))
  {crash=1;};
 } 
 if ((timer%5==1)&&crash==0)
 {next();
  eatormove();
 };
 draw(); 
 getfood(); 
}
</script>
</head>
<body onkeydown="fkeydown(event)">
<canvas id="canvas01" width="1200" height="800" style="background-color:black">
</canvas>
<script>
var cvs=document.getElementById("canvas01");
var ctx=cvs.getContext("2d");
ctx.fillStyle="red";
var intval=setInterval("refresh();",100);
</script>
</body>
</html>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM