<html xmlns=”http://www.w3.org/1999/xhtml”>
<head>
<meta http-equiv=”Content-Type” content=”text/html; charset=utf-8″ />
<title>貪吃蛇 – by CNwander</title>
<style type=”text/css”>
* { margin:0; padding:0 }
body { background:#000; -moz-user-select:none; text-align:center; font-size:12px } /*防止滑鼠拖拉*/
table { margin:80px auto 10px auto; overflow:hidden; border-collapse:collapse }
td { width:20px; height:20px; border:1px solid #eee; background:#f4f4f4 }
.cover { background:#39c } /*蛇身:淺藍色*/
.food { background:#093 } /*食物:綠色*/
.block { background:#333 } /*障礙:灰色*/
.brake { background:#f00 } /*刹車:紅色*/
.skate { background:#00f } /*滑板:藍色*/
#say { margin-top:50px; color:white }
#help { width:420px; margin:0 auto; line-height:17px; color:white }
#help span { float:left; margin-right:10px }
#help .box { width:15px; height:15px; margin-right:5px; border:1px solid white }
#btnStart { font-weight:bold; clear:both; width:100px; margin-left: 65px; height:30px; margin-top:10px; padding:0; background:#bbb; color:#222; border:1px solid #fff; border-bottom-color:#000; border-right-color:#000; cursor:pointer }
</style>
<script type=”text/javascript”>
//code by CNwander.
//website at http://www.webjx.com/javascript/jsajax-16454.html
//common
function $(str) {
return document.getElementById(str);
}
function $tag(str, target) {
target = target || document;
return target.getElementsByTagName(str);
}
//創建二維陣列
function multiArray(m, n) {
var arr = new Array(n); //創建Array物件構造器, n=陣列最大下標長度
for(var i = 0; i < m; i++) {
arr[i] = new Array(m); //二維
}
return arr;
}
//global
//const
var WIDTH = 20, //網格寬度
HEIGHT = 20, //網格高度
SAY = [“讚!雖說和玩家還不是一個級別的。”, “Ya!再加點油都可以和玩家媲美了。”, “牛!連玩家都甘拜下風了。”, “行!別把遊戲玩爆了。”]; //對話
var len, //蛇的長度
speed, //爬行速度
gridElems = multiArray(WIDTH, HEIGHT), //儲存格對象,UI元件指標陣列
carrier = multiArray(WIDTH, HEIGHT), //承載對象(遮蓋cover、食物food、障礙block、滑板skate、刹車brake),紀錄陣列值得2D陣列
snake, //蛇每節的座標點
info, //交互對話
topScore, //最高分
btnStart, //開始按鈕
snakeTimer, //蛇行走計時器
brakeTimers = [], //隨機刹車
skateTimers = [], //隨機滑板
directkey; //方向鍵值 37-40(左、上、右、下)
function initGrid() {
//var body = $tag(“body”)[0];
var table = document.createElement(“table”);//建立HTML的table元件放在記憶體中,當時體化後會受到CSS影響
var tbody = document.createElement(“tbody”); //tbody為HTML檔的表格元素(element),用於設置表格內容
for(var j = 0; j < HEIGHT; j++) {
var col = document.createElement(“tr”);//建立列元素
for(var i = 0; i < WIDTH; i++) {
var row = document.createElement(“td”);//建立一列有幾個元素
gridElems[i][j] = col.appendChild(row);//把每一個HTML的最小單元存放在記憶體中->當指標用
}
tbody.appendChild(col);//把每一列依序放到表格身體中的記憶體中
}
table.appendChild(tbody);//把建立好的表格身體放到表格的記憶體中
$(“snakeWrap”).appendChild(table); //div 利用function $(str)函數把記憶體內的表格實現出來(不是用jquery的選擇器)
}
//元件文字輸出資訊(使用Javascript)
function trace(sth, who) {
who = who || info;
if(document.all) { //相容判斷是否是IE流覽器
who.innerText = sth; //Internet Explorer
} else {
who.textContent = sth; //Firefox
}
}
//產生指定範圍隨機點
function randomPointer(startX, startY, endX, endY) {
startX = startX || 0;
startY = startY || 0;
endX = endX || WIDTH;
endY = endY || HEIGHT;
var p = [],
x = Math.floor(Math.random() * (endX – startX)) + startX, //Math.floor=返回小於等於x的最大整數
y = Math.floor(Math.random() * (endY – startY)) + startY;
if(carrier[x][y]) { //查證承載物件是否已有物品
return randomPointer(startX, startY, endX, endY);//如果已放物品就利用遞迴重新計算
}
p[0] = x;
p[1] = y;
return p;
}
//清除畫面
function clear() {
for(var y = 0; y < gridElems.length; y++) {
for(var x = 0; x < gridElems[y].length; x++) {
gridElems[x][y].className = “”; //儲存格對象=移除CSS的className[使用在建立表格實體時的指標來時做物件存取]
}
}
}
//創建蛇
function initSnake() {
var len1 = len – 1;
var pointer = randomPointer(len1, len1, WIDTH / 2, HEIGHT / 2);
for(var i = 0; i < len; i++) {
var x = pointer[0] – i,
y = pointer[1];
snake.push([x, y]); //向陣列末尾添加一個或多個元素,並返回陣列的長度
carrier[x][y] = “cover”;
}
}
//添加物品
function addObject(name) {
/*
“block”-添加障礙物
“food”-添加食物
“brake”-添加煞車
“skate”-添加加速
*/
var p = randomPointer();
carrier[p[0]][p[1]] = name;
gridElems[p[0]][p[1]].className = name;//利用指標新增元件的CSS的class
}
//獲取資訊-抓取目前的提示在UI上的文字
function getText(target) {
if(document.all) {
return target.innerText;
} else {
return target.textContent;
}
}
//最高分累加顯示
function dispscore(addscore) {
topScore += addscore;
trace(topScore, $(“score”)); //最高分,先透過function $(str)取得元件,之後再用trace函數設定顯示文字
}
//蛇行走目標點
function step() {//實體動作函數
var speedup = false;
//獲取目標點
//蛇頭位置
var headX = snake[0][0],
headY = snake[0][1];
//方向鍵
switch(directkey) {//按照鍵盤輸入,改變蛇頭位置
case 37: //左
headX -= 1;
break;
case 38: //上
headY -= 1;
break;
case 39: //右
headX += 1;
break;
case 40: //下
headY += 1;
break;
}
//碰到邊界WIDTH or HEIGHT、障礙物block,則結束遊戲
var carrierXY = carrier[headX][headY];
if(headX >= WIDTH || headX < 0 || headY >= HEIGHT || headY < 0 || carrierXY == “block” || carrierXY == “cover” ) {
if(getText($(“score”)) * 1 < len) {
trace(len, $(“score”));
}
btnStart.removeAttribute(“disabled”); //按鈕致能
btnStart.style.color = “#000”; //按鈕字體顏色復原
window.clearInterval(snakeTimer); //取消由setInterval()方法設置的計時器
for(var i = 0; i < brakeTimers.length; i++) {
window.clearTimeout(brakeTimers[i]); //刹車, 取消由setTimeout()方法設置的timeout及其帶來的行為
}
for(var i = 0; i < skateTimers.length; i++) {
window.clearTimeout(skateTimers[i]); //滑板, 取消由setTimeout()方法設置的timeout及其帶來的行為
}
trace(“GAME OVER!”);
return false; //停止Javascript的處理程式
}
//加速
if(len % 4 == 0 && speed < 60 && carrierXY == “food”) {
speed += 5;
walk();
speedup = true;
//trace(“加速!”);
topScore += 100;
}
//撿到刹車
if(carrierXY == “brake”) {
speed = 5;
walk();
trace(“恭喜!撿到刹車一個。”);
topScore += 10;
}
//遭遇滑板
if(carrierXY == “skate”) {
speed += 20;
walk();
trace(“遭遇滑板!”);
topScore += 100;
}
//添加障礙物
if(len % 6 == 0 && len < 60 && carrierXY == “food”) {
addObject(“block”);
}
//對話: 鼓勵
if(len <= 40 && len % 10 == 0) {
var cheer = SAY[len / 10 – 1];
trace(cheer);
}
//吃東西
//吃-只加頭-移動和增長效果
//動-刪尾&加頭-移動效果
if(carrierXY != “food”) {
//單純移動
var snake1 = snake.length – 1;
var lastX = snake[snake1][0],
lastY = snake[snake1][1];//取出蛇尾
carrier[lastX][lastY] = false;//刪除蛇尾在2D資料內的紀錄
gridElems[lastX][lastY].className = “”;//刪除蛇尾在UI上
snake.pop(); //刪除陣列最後一個元素,並將該元素作為返回值返回。如果陣列的長度為0,則返回undefined
} else {
//吃到東西
carrier[headX][headY] = false;//刪除蛇尾在2D資料內的紀錄
addObject(“food”); //添加食物
topScore += 10;
(speedup) ? trace(“加速!”) : trace(“吃到食物!”);
}
snake.unshift([headX, headY]); //向陣列開頭添加一個元素,並返回新的陣列長度
carrier[headX][headY] = “cover”;//在2D資料內的紀錄蛇身
gridElems[headX][headY].className = “cover”;//蛇身在UI上
len = snake.length; //返回一個陣列的長度
trace(topScore, $(“score”)); //最高分
}
//蛇行走控制
function walk() {//建立TIMER,step實體動作函數
if(snakeTimer) {
window.clearInterval(snakeTimer); //取消由setInterval()方法設置的計時器
}
snakeTimer = window.setInterval(step, Math.floor(3000 / speed)); //按照指定的週期(以毫秒計)來調用函數或計算運算式, 參數1(step函數): 為重複動作的程式碼,參數2: 則是延遲時間
}
//產生隨機整數
function randowNum(start, end) {
return Math.floor(Math.random() * (end – start)) + start;
}
function randNum() {//產生0~3的變數
//Math.random()->0~1
//(Math.random() * 10)->0~9
//(Math.random() * 10) % 4->0~3
//Math.floor()->取整數
return Math.floor((Math.random() * 10) % 4);
}
//添加亂數量刹車和滑板
function addRandomBrake() {
var num = randowNum(1, 5);
for(var i = 0; i < num; i++) {
brakeTimers.push(window.setTimeout(function(){ addObject(“brake”) }, randowNum(10000, 100000))); //刹車, 按照一定週期調用計時函數
skateTimers.push(window.setTimeout(function(){ addObject(“skate”) }, randowNum(5000, 100000))); //滑板, 按照一定週期調用計時函數
}
}
//遊戲開始
function start() {//遊戲的開始
len = randNum() + 1; //蛇的隨機長度[1~4]
speed = 10; //蛇的爬行速度 = 10 (1000 ms = 1 second)
directkey = 36 + len; //隨機決定方向[37~40]
topScore = len; //分數
carrier = multiArray(WIDTH, HEIGHT); //承載物件 = 二維陣列(WIDTH, HEIGHT)
snake = new Array(); //宣告一個新的陣列
clear(); //清除畫布
initSnake(); //蛇初始化
addObject(“food”); //添加食物
walk(); //蛇行走[啟動TIMER]
addRandomBrake(); //添加刹車和滑板
trace(“GAME START…”); //顯示文字
trace(topScore, $(“score”)); //最高分
}
//添加鍵盤事件
function attachEvents(e) {//只把按鍵值記錄到變數,並回傳FALSE達到讓網頁不處理該按鍵事件(事件屏蔽)
e = e || event;
directkey = Math.abs(e.keyCode – directkey) != 2 && e.keyCode > 36 && e.keyCode < 41 ? e.keyCode : directkey; //非方向鍵、反向無效
return false; //停止Javascript的處理程式
}
window.onload = function() {//程式的進入點
info = $(“say”);
initGrid(); //網格初始化
document.onkeydown = attachEvents; //綁定方向事件
btnStart = $(“btnStart”);
btnStart.onclick = function (e) {
btnStart.blur(); //firefox中必須釋放焦點
btnStart.setAttribute(“disabled”, true);
btnStart.style.color = “#aaa”; //中等亮度的灰色陰影
start(); //遊戲開始
}
}
</script>
</head>
<body onSelectStart=”return false”><!–防止滑鼠拖拉–>
<div id=”say”>貪吃蛇</div>
<div id=”snakeWrap”></div>
<div id=”help”>
<span class=”box food”></span><span>綠色食物</span>
<span class=”box block”></span><span>灰色障礙</span>
<span class=”box skate”></span><span>藍色滑板</span>
<span class=”box brake”></span><span>紅色刹車</span>
<span style=”float:right”>最高分:<strong id=”score”>0</strong></span>
<input type=”button” id=”btnStart” value=”開始遊戲” />
</div>
</body>
</html>
|
One thought on “javascript+css 實作經典遊戲 [貪吃蛇(Snake)] 詳細註解版本”
複製你的程式去跑,撞到左右邊的牆不會死
版主回覆:(12/05/2017 05:12:59 AM)
他應該只有碰到自己才會死的設計
歡迎修改成碰到牆壁會死的版本跟我交流