1. 程式人生 > >HTML5 + js 貪吃蛇遊戲設計與實現

HTML5 + js 貪吃蛇遊戲設計與實現

遊戲截圖:


遊戲架構:

此遊戲架構大概分為三層:


Game.html:

說明:包含了介面的展示,以及一些事件的入口。

完整程式碼:

<html>
<head>
<title>html5 snake game</title>
<script src ="game.js"></script>
</head>
 
<body>
 
<table>
<tr>
<td>
<!--
遊戲面板
-->
<canvas id="cvsPnl"style="top:0px;border:5px solid;color:#FF9900" width="10"height="10" >你的瀏覽器不支援這個遊戲!</canvas>
</td>
<td valign="top">
<!--
配置面板
-->
<div id="divSpeed">
<canvas id="cvsSpeed"width="120px" height="55px" ></canvas>
<select id="selSpeed">
<optionvalue="1000">1000</option>
<optionvalue="800">800</option>
<optionvalue="500">500</option>
<optionvalue="300">300</option>
<optionvalue="200">200</option>
</select>
</div>
 
<div id="divGameCtl">
<input id="btnStartGame"type="button" value="開始"></input>  
<input id="btnPauseGame"type="button" value="暫停"></input>
<br />
</div>
<br />
<div id="divPlayerName">
 
<canvas id="cvsName"width="50px" height="52px"></canvas><inputtype="text" id="txtName"style="width:120px;"></input>
<input id="btnRememberMe"value="記住我" type="button"></input>
</div>
 
<div>
<canvas id="cvsScore"></canvas>
</div>
 
 
</td>
</tr>
<table>
 
 
<divid="debug"></div>
 


<scripttype="text/javascript">
    
////遊戲畫板
var canvasGamePnl =document.getElementById("cvsPnl");
var context =canvasGamePnl.getContext("2d");
 
////分數
var canvasScore =document.getElementById("cvsScore");
var contxtScore =canvasScore.getContext("2d");
 
////速度
var canvasSpeed =document.getElementById("cvsSpeed");
var contxtSpeed =canvasSpeed.getContext("2d");
 
////姓名
var canvasName =document.getElementById("cvsName");
var contxtName =canvasName.getContext("2d");
 
////開始
$("btnStartGame").onclick=function(){
GameStart(context,contxtScore);
}
 
////暫停/繼續
$("btnPauseGame").onclick =function(){
          if($("btnPauseGame").value == "繼續"){
          RunGame(context,contxtScore);
          $("btnPauseGame").value = "暫停";
          gameStatus = 1;
          }
          else{
          PauseGame();
          $("btnPauseGame").value = "繼續";
          gameStatus = 2;
          }
}
 
////載入
          window.onload=function(){
          $("cvsPnl").width =screenWidth;
          $("cvsPnl").height=screenHeight;
    $("selSpeed").selectedIndex = 0;
 
          DrawFont(contxtSpeed,"選擇遊戲速度",120);
          DrawFont(contxtName,"姓名",50);
 
          $("txtName").value =GetPlayerName();
          }
 
 
 
////鍵盤事件handler
    document.onkeydown = function (){
     var key = document.all ? event.keyCode : arguments[0].keyCode;
           ////left
           if(key == 37){
           if(direction != "right"){
           direction = "left";
           }
           }
           ////up
           else if(key == 38){
           if(direction != "down"){
           direction ="up";
           }
           }
           ////right
           else if(key == 39){
           if(direction != "left"){
           direction = "right";
           }
           }
           ////down
           else if(key == 40){
           if(direction != "up"){
           direction = "down";
           }
           }
    }
 
          ////設定速度
          $("selSpeed").onchange=function(){
          if(gameStatus != 3){
          sleepTime =parseInt(GetSelectObj("selSpeed").value);
          }
 
          }
 
          /////記住我
          $("btnRememberMe").onclick =function(){
          ScorePlayerName($("txtName").value);
          alert("已儲存");
          }
 
          
 
 
////繪出文字
function DrawFont(context,txt,size){
 context.font='30px impact';
 context.fillStyle=fontColor;
 context.textAlign='left';
// context.shadowColor="#00ff00";
// context.shadowOffsetX = 15;
// context.shadowOffsetY=-10;
 context.fillText(txt,0,50,size);
}
</script>
</body>
 
 
</html>
 
Game.js:
說明:包含了遊戲的主幹邏輯,業務邏輯層的實現。
完整程式碼:
document.write("<scriptlanguage='javascript' src='config.js'></script>");
document.write("<scriptlanguage='javascript' src='utility.js'></script>");
document.write("<scriptlanguage='javascript' src='player.js'></script>");
document.write("<scriptlanguage='javascript' src='global.js'></script>");
////////////////////////
////遊戲入口////////////
////////////////////////
function GameStart(context,contxtScore){
        
InitGame(context,contxtScore);
RunGame(context,contxtScore);
}
 
 
////////////////////////
////初始化遊戲////////////
////////////////////////
function InitGame(context,contxtScore){
        
////貪吃蛇
for(var i = initSize ;i > 0;i --){
snakeArr[i - 1] = new Object();
snakeArr[i - 1].x = (initSize - i + 1) *unitSize;
snakeArr[i - 1].y = 0;
}
////方向
direction = "right";
////食物
food = new Object();
 
////繪製螢幕方格
DrawScreen(context);
////隨即食物
RandomFood(context);
////分數
DrawScore(contxtScore,score);
 
 
}
 
////////////////////////
////運行遊戲////////////
////////////////////////
function RunGame(context,contxtScore){
if(timer){
clearInterval(timer);
}
 
timer = setInterval(function(){
if(IsGameOver()){
         alert("gameover!");
clearInterval(timer);
return;
}
EatFoodHandler(context,contxtScore);
Refresh(context);
SetPosition();
DrawSnake(context);
 
},sleepTime);
}
 
 
////////////////////////
////重新整理////////////////
////////////////////////
function Refresh(context){
FillRect(context,snakeArr[snakeArr.length -1].x,snakeArr[snakeArr.length - 1].y,unitSize,unitSize,screenColor);
DrawRect(context,snakeArr[snakeArr.length -1].x,snakeArr[snakeArr.length - 1].y,unitSize,unitSize,lineColor);
}
 
 
////////////////////////
////畫蛇身//////////////
////////////////////////
function DrawSnake(context){
 
for(var i = 0;i < snakeArr.length;i ++){
FillRect(context,snakeArr[i].x,snakeArr[i].y,unitSize,unitSize,snakeColor);
DrawRect(context,snakeArr[i].x,snakeArr[i].y,unitSize,unitSize,lineColor);
}
}
 
////////////////////////
////畫螢幕//////////////
////////////////////////
function DrawScreen(context){
for(var i = screenLeft;i < screenLeft +screenWidth / unitSize;i ++){
for(var j = screenTop;j < screenTop +screenHeight / unitSize;j ++){
FillRect(context,i * unitSize,j *unitSize,unitSize,unitSize,screenColor);
DrawRect(context,i * unitSize,j *unitSize,unitSize,unitSize,lineColor);
}
}
}
 
////////////////////////
////設定座標////////////
////////////////////////
function SetPosition(){
 
for(var i = snakeArr.length - 2;i >= 0;i --){
snakeArr[i + 1].x = snakeArr[i].x;
snakeArr[i + 1].y = snakeArr[i].y;
 
}
if(direction == "left"){
snakeArr[0].x -= unitSize;
}
else if(direction == "right"){
snakeArr[0].x += unitSize;
}
else if(direction == "up"){
snakeArr[0].y -= unitSize;
}
else if(direction == "down"){
snakeArr[0].y += unitSize;
}
}
 
////////////////////////
////判斷是否結束遊戲///
////////////////////////
function IsGameOver(){
if(snakeArr[0].x < 0 ||snakeArr[0].x> screenWidth){
return true;
}
if(snakeArr[0].y < 0 ||snakeArr[0].y> screenHeight){
return true;
}
 
for(var i = 1;i < snakeArr.length;i ++){
if(snakeArr[0].x == snakeArr[i].x&& snakeArr[0].y == snakeArr[i].y){
         gameStatus= 3;
return true;
}
}
return false;
}
 
 
////////////////////////
////隨即食物////////////
////////////////////////
function RandomFood(context){
 
food.x = GetRandom((screenWidth / unitSize)- 1) * unitSize;
food.y = GetRandom((screenHeight /unitSize) - 1) * unitSize;
for(var i = 0;i < snakeArr.length;i ++){
if(food.x == snakeArr[i].x &&food.y == snakeArr[i].y){
RandomFood(context);
}
}
 
FillRect(context,food.x ,food.y,unitSize,unitSize,foodColor);////utility.js
DrawRect(context,food.x ,food.y,unitSize,unitSize,lineColor);////utility.js
 
}
 
////////////////////////
///食物處理/////////////
////////////////////////
functionEatFoodHandler(context,contxtScore){
 
if(direction == "left"){
if((snakeArr[0].x - unitSize == food.x)&& snakeArr[0].y == food.y){
 
         IncreaseLen(contxtScore);
         ClearFood(context);
         RandomFood(context);
}
}
else if(direction == "right"){
if(snakeArr[0].x + unitSize == food.x&& snakeArr[0].y == food.y){
 
         IncreaseLen(contxtScore);
         ClearFood(context);
         RandomFood(context);
}
}
else if(direction == "up"){
if(snakeArr[0].x == food.x &&(snakeArr[0].y - unitSize == food.y)){
        
         IncreaseLen(contxtScore);
         ClearFood(context);
         RandomFood(context);
}
}
else if(direction == "down"){
if(snakeArr[0].x == food.x &&snakeArr[0].y + unitSize == food.y){
        
         IncreaseLen(contxtScore);
         ClearFood(context);
         RandomFood(context);
}
}
 
}
 
////////////////////////
////清除食物////////////
////////////////////////
function ClearFood(context){
FillRect(context,food.x,food.y,unitSize,unitSize,screenColor);
DrawRect(context,food.x,food.y,unitSize,unitSize,lineColor);
 
}
 
////////////////////////
////增加長度////////////
////////////////////////
function IncreaseLen(contxtScore){
 
var newObj = new Object();
newObj.x = food.x;
newObj.y = food.y;
snakeArr.unshift(newObj);
 
////分數增加
IncreaseScore(contxtScore);////player.js
 
}
 
////暫停
function PauseGame(){
         clearInterval(timer);
}
 
Utility.js:
說明:提供了一些工具方法,工具層。
完整程式碼:
 
////返回客戶端物件
function $(clientId){
return document.getElementById(clientId);
}
 
////獲得SELECT選中項
function GetSelectObj(clientId){
var obj = $(clientId);
 
var index = obj.selectedIndex; // 選中索引
return obj.options[index];
}
 
////除錯使用
function DebugVar(param){
$("debug").innerHTML=param;
}
 
function DebugTxt(text){
$("debug").innerHTML = text;
}
 
////畫方塊
functionDrawRect(context,left,right,width,height,color){
                   //設定填充樣式
                   context.strokeStyle= color;
                   context.strokeRect(left,right,width, height);
}
 
////填充方塊
functionFillRect(context,left,right,width,height,color){
                   //設定填充樣式
                   context.fillStyle= color;
                   context.fillRect(left,right,width,height);
}
 
////繪畫文字
function DrawScore(context,txt){
 
 context.moveTo(0,0);
 context.clearRect(0,0,500,500);
 
 context.font='60px impact';
 context.fillStyle=fontColor;
 context.textAlign='center';
// context.shadowColor="#00ff00";
// context.shadowOffsetX = 15;
// context.shadowOffsetY=-10;
txt = "分數:" + txt;
 context.fillText(txt,100,100,fontSize); 
 
}
 
////繪製漸變
function ScreenGradient(context){
 
var grd =context.createLinearGradient(0,0,screenWidth,screenHeight);
grd.addColorStop(0,"#FFCC00");
grd.addColorStop(1,"#99FFFF");
context.fillStyle = grd;
context.fillRect(0,0,screenWidth,screenHeight);
}
 
////生產隨機數
function GetRandom(n){returnMath.floor(Math.random()*n+1)}
 
////儲存鍵值對
function addKV(k,v){
localStorage.setItem(k,v);
 
}
 
////取得鍵值對的值
function getV(k){
return localStorage.getItem(k);
}
 
////獲得本地儲存的所有值並轉化為字串
function getAllValueToStr(){
var content = "";
 for(var i=0;i<localStorage.length;i++){
 //key(i)獲得相應的鍵,再用getItem()方法獲得對應的值
  content += localStorage.key(i)+ " : " +localStorage.getItem(localStorage.key(i)) + "<br />";
}
}
 
Player.js:
說明:包含了玩家的一些操作,game.js下面一層,屬於業務邏輯輔助層。
完整實現:
 
function GetPlayerName(){
         varname = getV("userName");
return name != null ? name : "newplayer" ;
}
 
function IncreaseScore(context){
score += 10;
DrawScore(context,score);////utility.js
}
 
function ScorePlayerName(name){
addKV("userName",name);
}
 
Config.js:
說明:遊戲相關配置以及變數,系統配置層。
完整程式碼:
////////////////////////
////變數、配置引數//////
////////////////////////
 
 
var screenWidth = 800;////螢幕寬度
var screenHeight = 500;////螢幕高度
var unitSize = 20;////單元格大小
var initSize = 3;////初始長度
var screenLeft = 0;////螢幕橫起始座標
var screenTop = 0;////螢幕縱起始座標
var snakeArr = new Array();////貪吃蛇陣列
var food;////食物
var snakeColor = "#009999";////蛇身顏色
var direction;////蛇的方向
 
 
var screenColor = "#99CCFF";////螢幕顏色
var lineColor = "#ffffff";////線條顏色(方格)
var lineWidth = 3;////線條寬度
var foodColor = "#FFCC00"////食物顏色
 
var fontColor = "#996600";////分數顏色
var fontSize = 300;////分數字體大小
 
 
var timer;////定時器
var sleepTime = 200;////休眠時間
var level=0;////級別
var score=0;////分數
var currentPlayer;////當前玩家
 
var gameStatus = 0;////0:未開始 1:執行 2:暫停 3:已結束
 
global.js:(暫時沒有用到,用於擴充套件),系統全域性控制,例如場景繪製