学写前端原生贪吃蛇
看了人家視頻上寫的貪吃蛇,瞬間覺得自己low爆了。。。。就學(xué)他寫了三遍,以我的記性,覺得還是有必要記錄下過程,以便記憶。
先看下截圖:
首先html分析:
注:下列的id是用在js里的,class是用在css里的
上述是貪吃蛇的全部html代碼,將貪吃蛇游戲的大致界面劃分出來。
接下來是css代碼:
還有部分css代碼,在js代碼編輯的時候一同寫出,現(xiàn)在上述的css算是將貪吃蛇游戲的頁面背景設(shè)置完畢。
接下來js代碼:
設(shè)置完初始值后,開始設(shè)置蛇和食物的初始狀態(tài)
function food(){ //食物的設(shè)置var food = document.createElement('div'); //生成一個div的食物foodfood.style.width = this.foodW + 'px'; //設(shè)置食物的寬高,等于上述函數(shù)中已經(jīng)設(shè)置好的默認(rèn)食物寬高food.style.height = this.foodH + 'px'; //同上food.style.position = 'absolute'; //設(shè)置食物的位置為絕對定位this.foodX = Math.floor(Math.random()*this.mapW/20); //食物的x坐標(biāo)的隨機(jī)位置,表示0到(游戲界面的寬除以食物自己的寬)的隨機(jī)數(shù)this.foodY = Math.floor(Math.random()*this.mapH/20); //食物的y坐標(biāo)的隨機(jī)位置,同上food.style.top = this.foodY * 20 + 'px'; //表示食物的上邊距距離為食物的y坐標(biāo)乘以自己的高food.style.left = this.foodX * 20 + 'px'; //同上this.mapDiv.appendChild(food).setAttribute('class','food'); //給每個食物div都設(shè)置上名為food的class,再到css中設(shè)置食物的大小和載入圖片 }function snake(){ //蛇的設(shè)置for(var i = 0;i < this.snakeBody.length;i ++){ //用for循環(huán),i小于蛇身的長度,(初始時的length為3)var snake = document.createElement('div'); //生成一個div的蛇snakesnake.style.width = this.snakeW + 20 + 'px'; //設(shè)置生成的蛇的寬高snake.style.height = this.snakeH + 20 + "px";snake.style.position = 'absolute'; //設(shè)置蛇的絕對位置snake.style.top = this.snakeBody[i][1] * 20 + 'px'; //設(shè)置每節(jié)蛇的距離上邊距的位置snake.style.left = this.snakeBody[i][0] * 20 + 'px'; //設(shè)置每節(jié)蛇的距離左邊距的位置snake.classList.add(this.snakeBody[i][2]); //給每節(jié)蛇添加class,這里的class為上述的snakeBody中設(shè)置的第3個位置上的‘head’和’body‘,因此又需要對head和body設(shè)置css代碼,用來區(qū)分蛇頭和蛇身this.mapDiv.appendChild(snake).classList.add('snake'); //在html中添加上snake的div,并加上class = ‘snake’switch(this.direct){ //蛇頭的轉(zhuǎn)向(注:由于我找的蛇頭的方向默認(rèn)為右邊)case 'right': //由于默認(rèn)圖片蛇頭向右所以不需要改變操作break;case 'left' : //將蛇頭的方向轉(zhuǎn)向左邊snake.style.transform = 'rotate(180deg)';break;case 'up' : //將蛇頭方向旋轉(zhuǎn)到上邊snake.style.transform = 'rotate(270deg)';break;case 'down' : //將蛇頭方向旋轉(zhuǎn)到下方snake.style.transform = 'rotate(90deg)';break;default :break;}} }食物和蛇的css代碼:
.food{background-image: url('img/pg.png'); //加入食物的圖片background-size: 100% 100%; }.head{background-image: url('img/s.png'); //加入蛇頭的圖片background-size: 100% 100%; }.body{background-image: url('img/she.png'); //加入蛇身的圖片background-size: 100% 100%; }設(shè)置完蛇和食物的狀態(tài)后,設(shè)置游戲開始時的界面:
var startPage = document.getElementById('startPage'); //從html中獲取到id = startPage的元素節(jié)點(diǎn),startPage表示開始游戲的按鈕 var startP = document.getElementById('startP'); //同上,startP表示暫停的按鈕function startGame(){ //游戲開始startPage.style.display = 'none'; // 將該節(jié)點(diǎn)設(shè)置為不顯示startP.style.display = 'block'; //使該節(jié)點(diǎn)顯示food(); //調(diào)用food函數(shù)snake(); //調(diào)用snake函數(shù) }接下來設(shè)置蛇的運(yùn)動狀態(tài)js:
var scoreBox = document.getElementById('score'); //獲取用于計(jì)分的節(jié)點(diǎn) function move(){for(var i = this.snakeBody.length-1;i > 0;i --){ //for循環(huán),表示蛇運(yùn)動時,后一節(jié)蛇的位置是前一節(jié)蛇之前所在的位置this.snakeBody[i][0] = this.snakeBody[i-1][0];this.snakeBody[i][1] = this.snakeBody[i-1][1];}switch(this.direct){ //表示蛇頭的轉(zhuǎn)動位置情況case 'right' :this.snakeBody[0][0] +=1; //右邊時,蛇頭的x位置加1break;case 'left' :this.snakeBody[0][0] -=1; //左邊時,蛇頭的x位置減1,break;case 'up' :this.snakeBody[0][1] -=1; //上邊時,蛇頭的y位置減1break;case 'down' :this.snakeBody[0][1] +=1; //下邊時,蛇頭的y位置加1default:break;}removeClass('snake'); //刪除class = ‘snake’的節(jié)點(diǎn)snake(); //重新調(diào)用snake函數(shù)if(this.snakeBody[0][0] == this.foodX && this.snakeBody[0][1] == this.foodY){ //當(dāng)蛇吃到食物時var snakeEndX = this.snakeBody[this.snakeBody.length-1][0]; //表示吃到食物后,蛇尾的x坐標(biāo)為蛇的長-1var snakeEndY = this.snakeBody[this.snakeBody.length-1][1]; //同上switch(this.direct){case 'right':this.snakeBody.push([snakeEndX ,snakeEndY,'body']); //蛇頭向右時,蛇尾的x位置需要+1break;case 'left':this.snakeBody.push([snakeEndX ,snakeEndY,'body']); //蛇頭向左時,蛇尾的x位置需要-1break;case 'up':this.snakeBody.push([snakeEndX,snakeEndY ,'body']); //蛇頭向上時,蛇尾的y位置需要-1break;case 'down':this.snakeBody.push([snakeEndX,snakeEndY ,'body']); //蛇頭向下時,蛇尾的y位置需要+1break;default:break;} //注:當(dāng)蛇吃到食物時,添加的尾巴會在原來的尾巴的位置上加上,直到蛇頭離開食物的位置,此時的尾巴就會變成真正的尾巴this.score += 1; //吃到食物,分?jǐn)?shù)+1scoreBox.innerHTML = this.score; //使html中的id = ‘scoreBox’的節(jié)點(diǎn)上加上此時的分?jǐn)?shù)removeClass('food'); //蛇吃到食物后,所吃的食物消失food(); //又重新出現(xiàn)新的食物的位置}if(this.snakeBody[0][0] < 0 || this.snakeBody[0][0] > this.mapW/20){ //當(dāng)蛇頭x碰到邊界時,游戲結(jié)束reloadGame(); //結(jié)束游戲,重新加載游戲}if(this.snakeBody[0][1] < 0 || this.snakeBody[0][1] > this.mapH/20){ //當(dāng)蛇頭y碰到邊界時,游戲結(jié)束reloadGame(); //結(jié)束游戲,重新加載游戲}var snakeHX = this.snakeBody[0][0]; //得到蛇頭xvar snakeHY = this.snakeBody[0][1]; //得到蛇頭yfor(var i = 1;i < this.snakeBody.length;i++){ //當(dāng)蛇頭碰到自己的身體時,游戲結(jié)束if(snakeHX == snakeBody[i][0] && snakeHY == snakeBody[i][1]){reloadGame();}} }接下來是刪除節(jié)點(diǎn)的函數(shù):
function removeClass(className){ //給一個class類名var ele = document.getElementsByClassName(className); //用ele得到html中有該class類名的節(jié)點(diǎn)while(ele.length > 0){ //當(dāng)節(jié)點(diǎn)長度大于0時,即存在該節(jié)點(diǎn)ele[0].parentNode.removeChild(ele[0]); //刪除該節(jié)點(diǎn)} }然后是重新加載游戲的js代碼:
var loseScore = document.getElementById('loseScore'); function reloadGame(){removeClass('snake'); //刪除class = ‘snake’的節(jié)點(diǎn),即刪除蛇removeClass('food'); //刪除食物,同上clearInterval(snakeMove); //清除snakeMove每隔時間間隔長度運(yùn)動this.snakeBody = [[4,1,'head'],[3,1,'body'],[2,1,'body']]; //再添加上默認(rèn)初始的蛇身坐標(biāo)this.direct = 'right'; //初始方向this.right = false; this.left = false;this.up = true;this.down = true;lose.style.display = 'block'; //使id = ‘lose’的節(jié)點(diǎn)出現(xiàn),即出現(xiàn)游戲結(jié)束后的圖片loseScore.innerHTML = this.score; //記錄游戲結(jié)束后的最終得分this.score = 0; //記錄后,清0scoreBox.innerHTML = this.score; //同時將游戲開始時的動態(tài)積分也清0startGameBool = true;startPauseBool = true;startP.setAttribute('src','./img/begin.png'); //改變id = ‘startP’節(jié)點(diǎn)的圖片內(nèi)容 }關(guān)于操作蛇時的上下左右按鍵設(shè)置:
function setDirect(code){ //給該函數(shù)一個表示對應(yīng)按鍵數(shù)字switch(code){case 37: //表示左,方向?yàn)樽髸r,上下的按鍵可觸發(fā)但是左右的按鍵不可以觸發(fā)if(this.left){this.direct = 'left';this.left = false;this.right = false;this.up = true;this.down = true;}break;case 38: //上 ,同上if(this.up){this.direct = 'up';this.left = true;this.right = true;this.up = false;this.down = false;}break;case 39: //右 ,同上if(this.right){this.direct = 'right';this.left = false;this.right = false;this.up= true;this.down = true;}break;case 40: //下 ,同上if(this.down){this.direct = 'down';this.left = true;this.right = true;this.up = false;this.down = false;}break;default:break;} }接下來是關(guān)于游戲的開始和暫停的設(shè)置:
var startGameBool = true; //表示該鑰匙是開著時 var startPauseBool = true; var snakeMove; var speed = 200;function startAndPush(){if(startPauseBool){ //關(guān)于暫停的鑰匙if(startGameBool){ //關(guān)于游戲剛開啟時的鑰匙startGame(); //游戲開始,啟動游戲開始的界面startGameBool = false; //游戲開始后,不需要再出現(xiàn)這個過程,將該鑰匙鎖住}startP.setAttribute('src','./img/kk.png'); //為html中的id = ‘startP’設(shè)置插入圖片document.onkeydown = function(e){ //觸發(fā)按鍵發(fā)生的時間var code = e.keyCode; //得到所觸發(fā)按鍵所表示的數(shù)字setDirect(code); //調(diào)用上述的按鍵方向函數(shù)}snakeMove = setInterval(function(){ 表示每隔speed時間啟用一次move(); 調(diào)用move函數(shù),表示每隔speed時間,執(zhí)行一次move函數(shù)事件},speed);startPauseBool = false; //執(zhí)行過后,需要上鎖,防止該事件在游戲過程中被啟用出錯}else{ //當(dāng)鑰匙關(guān)閉時,執(zhí)行的事件startP.setAttribute('src','./img/zanting.png'); //改變id = startP的節(jié)點(diǎn)中的圖片內(nèi)容clearInterval(snakeMove); //清除snakeMove每隔speed時間的執(zhí)行document.onkeydown = function(e){ //表示禁止按鍵啟用e.returnValue = false;return false;}startPauseBool = true; //執(zhí)行上述事件后,將鎖打開} }之后是關(guān)于主體啟用鍵盤按鍵和鼠標(biāo)按鍵事件:
var lose = document.getElementById('lose'); var close = document.getElementById('close'); var startBtn = document.getElementById('startBtn');function bindEvent(){document.onkeydown = function(e){ //同上述描述,是按鍵的數(shù)字獲取和啟用方向事件var code = e.keyCode;setDirect(code)}close.onclick = function(){ //表示游戲結(jié)束后右上角的關(guān)閉按鍵的觸發(fā)事件lose.style.display = 'none'; //使游戲結(jié)束界面不顯示}startBtn.onclick = function(){ //表示剛啟動游戲時的開始按鈕startAndPush(); }startP.onclick = function(){ //表示游戲中的暫停和解除暫停的鼠標(biāo)按鍵事件startAndPush();} }上述就是所有的js代碼。。。。
看下成果圖:
注:上述代碼如有解釋錯誤的,請大佬幫忙改善,謝謝,有不清楚的也可以留言,本人會盡量及時回復(fù)的
總結(jié)
- 上一篇: 创客教育的起源和内涵的基本理念
- 下一篇: 2017年html5行业报告,云适配发布