用 JavaScript 來做個貪吃蛇

講師:Arashi

日期:2021/03/31

Outline

  • 流程圖
  • 實作 - Base
  • 實作 - Start & Addfood
  • 實作 - draw table and snake
  • 實作 - move
  • 實作 - eat
  • 實作 - dead
  • 參考資源

流程圖

start()
addfood()
move()

drawtable()

isEat()
isDead()

初始化遊戲
添加食物
移動

更新畫布

判斷有沒有吃到食物
判斷有沒有死亡

使用函數

實作 - Base

<!DOCTYPE html>
<html>
<head>
	<title>貪吃蛇</title>
	<meta charset="UTF-8">
	<meta name="keywords" content="貪吃蛇">
	<meta name="Description" content="這是一個初學者用來學習的小遊戲">
	<style type="text/css">
	*{margin:0;}
	.map{margin:50px auto;
		height:600px;
		width:900px;
		background:#00D0FF;
		border:10px solid #AFAEB2;
		border-radius:8px;
	}
	</style>

</head>

<body>
<div class="map">
<canvas id="canvas" height="600" width="900">
</canvas>
</div>
</body>
</html>

網頁基本架構

展示畫面

實作 - Start & AddFood

後續內容全部加在 body 的 scrpit 內

<body>
  <div class="map">
    <canvas id="canvas" height="600" width="900">
    </canvas>
  </div>
  <script type="text/javascript">
    後續程式碼加在此處!!!
  </script>
</body>

宣告所需的變數

var c = document.getElementById("canvas"); //取得畫布
var ctx = c.getContext("2d"); //跟畫布宣告說接下來要畫上去的圖為2D

// 初始化食物的資料
var foodx = 0;
var foody = 0;

// 初始化蛇的資料
var snake = [];
var snakeCount = 4;

// 判斷方向
var togo =0;
// 初始化
function start()
{
  addfood();//在start中呼叫新增食物函式
}

function addfood()
{
  foodx = Math.floor(Math.random()*60)*15;
  foody = Math.floor(Math.random()*40)*15;
  ctx.fillRect(foodx,foody,15,15); //繪製一個圓形,位置在(foodx, foody),長寬皆為15

}

//當載入網頁的時候,呼叫以下函式
window.onload = function()
{ 
  start();
}

初始化與增加食物

展示畫面

Math.random() //回傳0~1之間的數字,不含1
Math.floor() //回傳整數部分
假設隨機出來的數字是0.5

Math.random() * 60
=> 0.54 * 60 = 32.4

Math.floor() * 15
=> 取32 * 15 = 480

Math 相關函式

舉例

(0,0)

x

y

程式中的座標

//繪製方形
ctx.fillRect(x軸,y軸,長,寬);

//繪製圓形
ctx.arc(圓心x軸, 圓心y軸, 半徑, 起始點弧度, 結束點弧度, anticlockwise);
anticlockwise = true //順時鐘畫圖
anticlockwise = false //逆時鐘畫圖

實作 - draw table and snake

初始化蛇的資料

(0, 0)

(15, 0)

(30, 0)

(45, 0)

//定義蛇的座標
function start()
{
  for(var k = 0;k < snakeCount;k++)
  {
    // 定義每一節身體的位置
    snake[k]={x:k * 15, y:0};		
  }
  addfood();
}
//畫地圖的函式
function drawtable()
{  	
  for(var k = 0;k < snakeCount;k++)//畫蛇的身體
  {
    ctx.fillStyle = "#000";
    if (k == snakeCount-1)
    {
      ctx.fillStyle="red";//將蛇頭的顏色設定為紅色
    }
    ctx.fillRect(snake[k].x,snake[k].y,15,15);

  }
  //繪製食物
  ctx.fillStyle ="black";
  ctx.fillRect(foodx,foody,15,15);
  ctx.fill(); //將顏色填滿圖形

}

將蛇畫上地圖

//當載入網頁的時候,呼叫以下函式
window.onload = function()
{ 
  start();
  drawtable(); // 增加繪製地圖
}

在載入網頁時便開始畫地圖

function addfood()
{
  foodx = Math.floor(Math.random() * 60) * 15;
  foody = Math.floor(Math.random() * 40) * 15;
  // ctx.fillRect(foodx, foody, 15, 15);

}

刪除 addfood() 內的繪製方形

展示畫面

寫法 => {key1 : value, key2 : value......}

snake[
  {x:0, y:0},
  {x:15, y:0},
  {x:30, y:0},
  {x:45, y:0}
]

snake[1].x => 15

dict 字典

(0, 0)

(15, 0)

(30, 0)

(45, 0)

實作 - move

function keydown(e)
{
  switch(e.keyCode)
  {
    case 37: togo=1; break;
    case 38: togo=2; break;
    case 39: togo=3; break;
    case 40: togo=4; break;
    case 65: togo=5; break;
    case 68: togo=6; break;
  }
}

document.onkeydown=function(e)
{
  keydown(e);

}

監控按鍵操作

switch(參數)
{
  case 37:
    執行的事情
    break;
  case 38: 
    執行的事情
    break;
  case 39: 
    執行的事情
    break;
}

switch case

當參數符合 case 的條件時,則執行該 case 要執行的內容
function move()
{
  switch (togo)
  {
    case 1: snake.push({x:snake[snakeCount-1].x-15,y:snake[snakeCount-1].y}); break; //向左走
    case 2: snake.push({x:snake[snakeCount-1].x,y:snake[snakeCount-1].y-15}); break; //向上
    case 3: snake.push({x:snake[snakeCount-1].x+15,y:snake[snakeCount-1].y}); break; //向右
    case 4: snake.push({x:snake[snakeCount-1].x,y:snake[snakeCount-1].y+15}); break; //向下
    case 5: snake.push({x:snake[snakeCount-1].x-15,y:snake[snakeCount-1].y-15}); break; //向左上
    case 6: snake.push({x:snake[snakeCount-1].x+15,y:snake[snakeCount-1].y+15}); break; //向右下
    default: snake.push({x:snake[snakeCount-1].x+15,y:snake[snakeCount-1].y});
  }
  snake.shift();//刪除陣列第一個元素
  ctx.clearRect(0,0,900,600);//清除畫布重新繪製
  drawtable();
} 			

window.onload = function()
{ 
  start();
  setInterval(move,150); // 每0.15秒呼喚一次 move函式
  drawtable();
}

(0, 0)

(15, 0)

(30, 0)

(45, 0)

(15, 0)

(30, 0)

(45, 0)

(60, 0)

(0, 0)

(15, 0)

(30, 0)

(45, 0)

(60, 0)

實作 - eat

function move()
{
  ......
  isEat() // 增加這行
  drawtable();
}
//吃到食物後長度加1
function isEat()
{
  if(snake[snakeCount-1].x == foodx&&snake[snakeCount-1].y==foody)
  {
    addfood();
    snakeCount++;
    snake.unshift({x:-15,y:-15}); //增加一節身體
  }
}

實作 - dead

function move()
{
  ......
  isDead(); // 增加這行
  drawtable();
}

function isDead()
{
  if (snake[snakeCount-1].x > 885 || snake[snakeCount-1].y > 585 || snake[snakeCount-1].x < 0 || snake[snakeCount-1].y < 0)
  {
    alert("You are dead,GAME OVER!!!");
    snake = []; //清空蛇的資料避免重複判斷
    window.location.reload(); //重新整理頁面
  }
}

參考資源

Made with Slides.com