使用前端原生 js,貪吃蛇小遊戲
阿新 • • 發佈:2017-06-20
oct 新的 生成 方便 描述 logs turn asc 轉動
好久好久,真的是好久好久沒來寫過了,因為最近有點小忙。不過即使是忙,也也還是寫了兩個小遊戲,其中一個就是這個,貪吃蛇啦。
算是一個小練手了,這個是在有點太簡單了,只是第一次寫這種小遊戲,還是零零星星花了三五天時間,下面就是這個小遊戲的gif小動畫,比較簡單,對比過網上其他用來寫出來練手的貪吃蛇作品,這個在顏值還是功能上,都還是不錯的,霍霍。
這裏講解一下功能:
- 空格控制開始和暫停。
- 方向鍵控制移動方向。
- Q 鍵加速,再按一次恢復常規速度(在加速狀態時,按下或者方向鍵,或者吃到了白色小食物,速度自動恢復正常)。
這次我研究了 github,一個用來管理代碼版本的國外網站,不過使用它不需要FQ,它的一個功能,就是可以用來展示網站,比如我就把貪吃蛇放在裏 github 中,可以點擊後面的鏈接訪問,也就是可以直接玩耍:點擊這裏打開貪吃蛇
想描述一下技術要點。。。發現有點小忘了,不過一個難點還是記得的,當蛇的身子比較長後,容易和自己挨住,會連成一塊,看上去很不方便,所以我在中間添加了這條縫隙,如下圖所示,為添加前和添加後的效果:
這條縫隙的添加還是比較麻煩的,我的思路是,給組成蛇身的每個 li 元素小塊,都設置個 1px 的border背景色邊框,接著每一個 li 的後面跟一個寬度為 2px,高度和 li 等高的 span 標簽,背景顏色和li相同,再通過css設置好位置,正好可以補上蛇身中兩個正常相連的 li 小塊之間,那個 2px 的縫隙,為什麽是 2px 呢?因為前一個 li 和後一個 li,各都有 1px 的 border。
源代碼也放在下面吧,免得以後啥時候我改了 github 配置,上面那個鏈接不能使用了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>貪吃蛇</title> <style> * { padding: 0; margin: 0; } body { background-color: #090e20; } .big { width: 1000px; height: 600px; border: 1px dashed #fff; margin: 30px auto 0; position: relative; } p { margin-bottom: 10px; } .right span { position: absolute; width: 20px; height: 20px; background-color: #fff; border-radius: 30%; } ul li { list-style: none; position: absolute; width: 20px; height: 20px; background-color: #b5cad5; box-sizing: border-box; border: 1px solid #090e20; } ul li b { display:block; z-index: 100; width: 2px; height: 18px; background-color: #b5cad5; position: absolute; top: 0; left: 8px; transform-origin: 11px 9px; transform: translate(-10px,0) rotate(0deg); } ul li:first-child b { width: 4px; transform: translate(-12px,0) rotate(0deg); } ul li:last-child b { background-color: transparent; } ul li:nth-child(1) { border-radius: 0 50% 50% 0; /*transform:scale(2,2);*/ } ul li:nth-child(1):before { content: ‘‘; display: block; background-color: #090e20; width: 2px; height: 2px; position: absolute; bottom: 5px; right: 10px; z-index: 2; } ul li:nth-child(1):after { content: ‘‘; display: block; background-color: #090e20; width: 2px; height: 2px; position: absolute; top: 5px; right: 10px; } .explain { float: left; box-sizing: border-box; border-right: 1px dashed #fff; height: 100%; width: 260px; color: #fff; } .explain em { color: #b3c6ff; font-style: normal; } ol li { margin-left: 25px; } .right { width: 740px; float: right; height: 100%; position: relative; box-sizing: border-box; } </style> </head> <body> <div class="big"> <div class="explain"> <p>點擊<em>空格</em>開始或暫停</p> <p>可通過<em>WASD</em>或者<em>方向鍵</em>控制方向</p> <p>可通過<em>回車鍵</em>或者<em>Q</em>加速</p> <p>當改變方向,或者吃到小球,速度自動恢復正常</p> <br> <p>以下為每局吃掉的小球個數</p> <ol></ol> </div> <div class="right"> <span></span> <ul> </ul> </div> </div> </body> <script> window.onload = function () { //獲取元素節點 var big = document.querySelector(".big"); var span = document.querySelector("span"); var ul = document.querySelector("ul"); var ol = document.querySelector("ol"); var ol_lis; //預留的ol中的li標簽 var lis;//預留的ul中的li標簽,即貪吃蛇的身子 var times;//速度,初始為150 var arrall;//二維數組,每一項為一個數組,其中保存每個li的x軸y軸坐標和方向 var timer;//蛇運動時的定時器 var timers;//數組,蛇吃到小球,小球白點順著身子流動的定時器,之所以是數組,是因為可能上一個小球白點還沒到尾部,蛇又吃了一個 var index;//數組,和times綁定的 var direction; //現在蛇運動的方向 var flag; //判斷是否按下了方向鍵 var num;//用來記憶最初始有幾個li,計數吃掉幾個小球時減去 var stars = false;//判斷是否遊戲中true或者false var spanX;//保存食物小球的坐標 var spanY; star(); //初始化函數 function star() { times = 200; arrall = []; timers = []; index = []; ul.innerHTML = "<li></li><li></li><li></li><li></li>"; lis = document.querySelectorAll("ul li"); num = lis.length; //給每一個li定位,且記錄到arrall中 for (var i = lis.length - 1; i >= 0; i--) { var arr = [0, 20 * i, "right"]; arrall[arrall.length] = arr; lis[i].style.top = 0; lis[i].style.left = 20 * (lis.length - 1 - i) + "px"; var b = document.createElement(‘b‘); lis[i].appendChild(b); } //給arrall多造一個子元素,用來為吃到小點後新增的身子賦值; arrall[arrall.length] = [0, 20 * lis.length - 1, "right"]; spanPosition();//生成span小球事物 timer = null; direction = ‘right‘; flag = null; } //生成小白球函數 function spanPosition() { var temp; do { temp = false; spanX = Math.floor(Math.random() * 36) * 20; spanY = Math.floor(Math.random() * 29) * 20; //for循環來保證小白球不會出現在蛇身體的內部 for (var i = 0; i < lis.length; i++) { if (spanX == arrall[i][1] && spanY == arrall[i][0]) { temp = true; break; } } } while (temp); span.style.left = spanX + "px"; span.style.top = spanY + "px"; span.style.display = "block"; } //按下鍵盤按鍵 document.onkeydown = function (e) { //如果是紅的,則屏蔽所有按鍵 if (lis[0].style.backgroundColor === "red") return; //如果是空格鍵 if (e.keyCode == 32) { if (timer) { clearInterval(timer); timer = null; flag = true; } else { timer = setInterval(move, times); flag = false; //如果遊戲沒有運行,也就是初次啟動,而不是暫停後的啟動 if (!stars) { //如果是失敗了,蛇頭為紅色,此時也屏蔽空格 var li = document.createElement(‘li‘); li.innerHTML = "吃掉小球數量為:" + (arrall.length - 1 - num) + "枚!"; ol.appendChild(li); ol_lis = document.querySelectorAll("ol li"); stars = true; } } return; } //如果遊戲沒有開始開,則其他按鍵失效 if (!stars) return; //如果是回車或者Q if (e.keyCode == 13 || e.keyCode == 81) { if (timer) { clearInterval(timer); if (times == "50") times = 200; else times = 50; timer = setInterval(move, times); } else { if (times == "50") times = 200; else times = 50; } return; } if (flag) return; if (e.keyCode == 38 || e.keyCode == 87) { if (direction == "bottom" || direction == "top") { return; } flag = ‘top‘; } else if (e.keyCode == 37 || e.keyCode == 65) { if (direction == "right" || direction == "left") { return; } flag = ‘left‘; } else if (e.keyCode == 39 || e.keyCode == 68) { if (direction == "left" || direction == "right") { return; } flag = ‘right‘; } else if (e.keyCode == 40 || e.keyCode == 83) { if (direction == "top" || direction == "bottom") { return; } flag = ‘bottom‘; } else { returnValue = false; return; } times = 200; clearInterval(timer); move(); } //移動函數 function move() { //如果安了方向鍵,那麽為direction賦flag的值 if (flag) { direction = flag; } //用for循環依次移動每一個li for (var i = arrall.length - 1; i >= 0; i--) { if (i == arrall.length - 1) { var arrs = []; arrs[0] = arrall[i - 1][0]; arrs[1] = arrall[i - 1][1]; arrs[2] = arrall[i - 1][2]; arrall[i] = arrs; } else { //如果是第一個li,把它的方向信息及時更新 if (i == 0) { arrall[i][2] = direction; } else { //如果不是,把li移動的方向設置為前一個的 arrall[i][2] = arrall[i - 1][2]; } //根據方向來更新位置 switch (arrall[i][2]) { case "top" : arrall[i][0] -= 20; lis[i].style.top = arrall[i][0] + "px"; lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(270deg)"; break; case "right" : arrall[i][1] += 20; lis[i].style.left = arrall[i][1] + "px"; lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(0deg)"; break; case "bottom" : arrall[i][0] += 20; lis[i].style.top = arrall[i][0] + "px"; lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(90deg)"; break; case "left" : arrall[i][1] -= 20; lis[i].style.left = arrall[i][1] + "px"; lis[i].querySelector(‘b‘).style.transform = "translate(-10px,0) rotate(180deg)"; break; } } } lis[0].querySelector(‘b‘).style.transform= "translate(-12px,0) rotate(0deg)"; //再判斷是不是按下了方向鍵,用來轉動蛇頭 if (flag) { if (flag == "bottom") { lis[0].style.transform = "rotate(90deg)"; } else if (flag == "right") { lis[0].style.transform = "rotate(0deg)"; } else if (flag == "left") { lis[0].style.transform = "rotate(180deg)"; } else if (flag == "top") { lis[0].style.transform = "rotate(270deg)"; } flag = null; timer = setInterval(move, times); } //判斷是否吃掉了小球 if (arrall[0][0] == spanY && arrall[0][1] == spanX) { clearInterval(timer); times = 200; timer = setInterval(move, times); //新產生一枚小球點 span.style.display = "none"; spanPosition(); //下面兩個是啟動產生小白點的函數定時器 index[index.length] = 1; timers[timers.length] = setInterval(dingshi,20,timers.length); } //判斷有沒有碰到墻壁或自己 for (var i = 1; i < lis.length; i++) { if (arrall[0][0] == arrall[i][0] && arrall[0][1] == arrall[i][1] || arrall[0][0] < 0 || arrall[0][0] == 600 || arrall[0][1] < 0 || arrall[0][1] == 740) { clearInterval(timer); lis[0].style.zIndex = lis.length; lis[0].style.backgroundColor = "red"; stars = false; var tempTimer = setTimeout(function(){ lis[0].style.backgroundColor = "#b5cad5"; star(); },1000); break; } } } //吃掉小球,出現順著蛇身子移動的白點的函數 function dingshi(temp){ lis[index[temp]].style.backgroundColor = "#b5cad5"; if (index[temp] == lis.length-1) { clearInterval(timers[temp]); //新生成的li的數組,其位置和方向信息等於之前的最後一個li var arr = [arrall[arrall.length - 1][0], arrall[arrall.length - 1][1], arrall[arrall.length - 1][2]]; arrall[arrall.length] = arr; //創建新的li元素,並且用另一個函數,給這個li賦值位置和方向信息 var li = document.createElement("li"); var b = document.createElement(‘b‘); li.appendChild(b); ul.appendChild(li); lis = document.querySelectorAll("ul li"); lis[lis.length - 1].style.top = arr[0] + "px"; lis[lis.length - 1].style.left = arr[1] + "px"; ol_lis[ol_lis.length - 1].innerHTML = "吃掉小球數量為:" + (arrall.length - 1 - num) + "枚!"; return ; }; lis[index[temp]+1].style.backgroundColor = "#fff"; index[temp]++; } } </script> </html>
使用前端原生 js,貪吃蛇小遊戲