亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JS學習筆記之貪吃蛇小游戲demo實例詳解

2024-05-06 16:51:33
字體:
來源:轉載
供稿:網友

本文實例講述了JS學習筆記之貪吃蛇小游戲demo實例。分享給大家供大家參考,具體如下:

最近跟著視頻教程打了一個貪吃蛇,

來記錄一下實現思路,

先上代碼
靜態頁

<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8" />  <title>貪吃蛇</title></head><style>*{  margin: 0;  padding: 0;}  .map{    width:800px;    height: 600px;    background-color: #ccc;    position:relative;  }</style><body><!-- 畫出地圖,設置樣式 --> <div class="map"> </div></body><script src="food.js"></script><script src="snake.js"></script><script src="game.js"></script></html>

food.js

//食物就是一個對象,寬高橫縱坐標,先定義構造函數,然后創建對象(function (){  var elements=[];//用來保存每個小方塊食物  function Food(x,y,width,height,color){    //橫縱坐標    this.x=x||0;    this.y=y||0;    this.width=width||20;    this.height=height||20;    //背景顏色    this.color=color||"green";  }  //為原型添加初始化的方法(作用:在頁面上取顯示這個食物)  //因為食物要在地圖上顯示,所以,需要地圖這個參數  Food.prototype.init=function(map){    //先刪除這個食物    //外部無法訪問的函數    remove()    var div=document.createElement("div");    //把這個div加到map中    map.appendChild(div);    //設置div的樣式    div.style.width=this.width+"px";    div.style.height=this.height+"px";    div.style.backgroundColor=this.color;    // div.style.left=this.x+"px";    //先脫離文檔流    div.style.position="absolute";    //隨機橫縱坐標    this.x=parseInt(Math.random()*(map.offsetWidth/this.width))*this.width;    this.y=parseInt(Math.random()*(map.offsetHeight/this.height))*this.height;    div.style.left=this.x+"px";    div.style.top=this.y+"px";    // Food.prototype.init=function(map){    // }    //把div加入到數組elements中    elements.push(div);  }  function remove(){    //elements數組中有這個食物    for(var i=0;i<elements.length;i++){      var ele=elements[i]      //找到這個子元素的父級元素,然后刪除這個子元素      ele.parentNode.removeChild(ele);      //再次把elements中的這個子元素也要刪除      elements.splice(i,1)    }  }  //把Food暴露給Window,外部可以使用  window.Food=Food;}());

snake.js
 

//蛇(function(){  var elements=[];//存放小蛇的每個身體部分  //蛇的構造函數  function Snake(width,height,direction){    //小蛇的每個部分的寬    this.width=width||20;    this.height=height||20;    //身體    this.body=[      {x:3,y:2,color:"red"},      {x:2,y:2,color:"orange"},      {x:1,y:2,color:"orange"}    ];    this.direction=direction||"right";  }//蛇的初始化  Snake.prototype.init=function(map){    remove()    //循環遍歷創建div    for(var i=0;i<this.body.length;i++){      var obj=this.body[i];      //創建div      var div=document.createElement("div");      //把div加入到map地圖中      map.appendChild(div);      //設置div的樣式;      div.style.position="absolute";      div.style.width=this.width+"px";      div.style.height=this.height+"px";      div.style.left=obj.x*this.width+"px";      div.style.top=obj.y*this.height+"px";      div.style.backgroundColor=obj.color;      //把div加入到elements數組中--目的是刪除      elements.push(div)    }  }  //蛇的移動  Snake.prototype.move=function(food,map){    //改變蛇身體位置    var i=this.body.length-1; //2    for(;i>0;i--){      this.body[i].x=this.body[i-1].x;      this.body[i].y=this.body[i-1].y;    }    //判斷方向---改變小蛇的頭的坐標位置    switch (this.direction){      case "right":        this.body[0].x+=1;        break;      case "left":        this.body[0].x-=1;        break;      case "top":        this.body[0].y-=1;        break;      case "bottom":        this.body[0].y+=1;        break;    }    //判斷有沒有吃到食物    //小蛇的頭的坐標和食物位置    var headX=this.body[0].x*this.width;    var headY=this.body[0].y*this.height;    //食物的橫縱坐標    var foodX=food.x;    var foodY=food.y;    if(headX==foodX&&headY==foodY){      //獲取蛇的最后尾巴      var last=this.body[this.body.length-1];      //把最后的蛇尾復制一份      this.body.push({        x:last.x,        y:last.y,        color:last.color      })      //重新初始化食物      food.init(map);    }  }  //刪除小蛇的私有函數  function remove(){    //獲取數組    var i=elements.length-1;    for(;i>=0;i--){      //先從當前的子元素中找到該子元素的父級元素,然后再弄死這個子元素      var ele=elements[i];      //從map地圖上刪除這個子元素div      ele.parentNode.removeChild(ele);      elements.splice(i,1);    }  }  window.Snake=Snake;}());//蛇(function(){  var elements=[];//存放小蛇的每個身體部分  //蛇的構造函數  function Snake(width,height,direction){    //小蛇的每個部分的寬    this.width=width||20;    this.height=height||20;    //身體    this.body=[      {x:3,y:2,color:"red"},      {x:2,y:2,color:"orange"},      {x:1,y:2,color:"orange"}    ];    this.direction=direction||"right";  }//蛇的初始化  Snake.prototype.init=function(map){    remove()    //循環遍歷創建div    for(var i=0;i<this.body.length;i++){      var obj=this.body[i];      //創建div      var div=document.createElement("div");      //把div加入到map地圖中      map.appendChild(div);      //設置div的樣式;      div.style.position="absolute";      div.style.width=this.width+"px";      div.style.height=this.height+"px";      div.style.left=obj.x*this.width+"px";      div.style.top=obj.y*this.height+"px";      div.style.backgroundColor=obj.color;      //把div加入到elements數組中--目的是刪除      elements.push(div)    }  }  //蛇的移動  Snake.prototype.move=function(food,map){    //改變蛇身體位置    var i=this.body.length-1; //2    for(;i>0;i--){      this.body[i].x=this.body[i-1].x;      this.body[i].y=this.body[i-1].y;    }    //判斷方向---改變小蛇的頭的坐標位置    switch (this.direction){      case "right":        this.body[0].x+=1;        break;      case "left":        this.body[0].x-=1;        break;      case "top":        this.body[0].y-=1;        break;      case "bottom":        this.body[0].y+=1;        break;    }    //判斷有沒有吃到食物    //小蛇的頭的坐標和食物位置    var headX=this.body[0].x*this.width;    var headY=this.body[0].y*this.height;    //食物的橫縱坐標    var foodX=food.x;    var foodY=food.y;    if(headX==foodX&&headY==foodY){      //獲取蛇的最后尾巴      var last=this.body[this.body.length-1];      //把最后的蛇尾復制一份      this.body.push({        x:last.x,        y:last.y,        color:last.color      })      //重新初始化食物      food.init(map);    }  }  //刪除小蛇的私有函數  function remove(){    //獲取數組    var i=elements.length-1;    for(;i>=0;i--){      //先從當前的子元素中找到該子元素的父級元素,然后再弄死這個子元素      var ele=elements[i];      //從map地圖上刪除這個子元素div      ele.parentNode.removeChild(ele);      elements.splice(i,1);    }  }  window.Snake=Snake;}());

game.js

//游戲(function(){   var that=null;  //游戲的構造函數  function Game(map){    this.food=new Food();    this.snake=new Snake();    this.map=map;//地圖    that=this;  }  Game.prototype.init=function(){    //初始化游戲    //食物初始化    this.food.init(this.map);    this.snake.init(this.map);    this.runSnake(this.food,this.map)    this.bindKey();  }  Game.prototype.runSnake=function(food,map){    //自動的去移動    var timeId=setInterval(function(){      //此時的this是window      //蛇的移動      this.snake.move(food,map);      //初始化蛇      this.snake.init(map);      //橫坐標最大值      var maxX=map.offsetWidth/this.snake.width;      //獲取縱坐標的最大值      var maxY=map.offsetHeight/this.snake.height;      //蛇頭的坐標      var headX=this.snake.body[0].x;      var headY=this.snake.body[0].y;      //判斷橫坐標      if(headX<0||headX>=maxX){        clearInterval(timeId)        alert("游戲結束")      }      //判斷縱坐標      if(headY<0||headY>maxY){        clearInterval(timeId)        alert("游戲結束")      }      console.log(headX)    }.bind(that),150)  }  Game.prototype.bindKey=function(){    //獲取用戶的按鍵,改變小蛇的方向    document.addEventListener("keydown",function(e){      //獲取案件的值      switch(e.keyCode){        case 37:          this.snake.direction="left";          break;        case 38:          this.snake.direction="top";          break;        case 39:          this.snake.direction="right";          break;        case 40:          this.snake.direction="bottom";          break;      }    }.bind(that),false)  }  window.Game=Game;}());//初始化游戲對象var gm=new Game(document.querySelector(".map"));gm.init()

這里加一個小插曲,關于匿名函數自調用的三種寫法

第一種

JS,貪吃蛇,小游戲

第二種

JS,貪吃蛇,小游戲

第三種

JS,貪吃蛇,小游戲

注意!注意! 注意! 匿名函數的最后不要忘記加封號;  因為如果忘了加,系統很容易與后面的代碼混淆 造成各種很奇葩的報錯;

這里我推薦第三種寫法,比較清晰明了

好,代碼貼完了,我們來分析一下實現思路

首先 第一步

建立一個畫布

設置畫布的寬度為800px   高度為600px  因為小蛇 需要在畫布內任意移動,需要脫離標準文檔流,所以需要設置絕對定位, 因此我給畫布添加了position:relative;  ,再給背景添加一個顏色 ,灰色#ccc

好,畫布創建好了,我們可以開始編寫邏輯代碼了

Food.js 代碼分析

首先我們需要創建一個貪吃蛇 吃的“食物”,因此我們需要創建一個食物的對象,這里我在food.js中創建了一個自定義構造函數

定義了 “食物Food”的 x值、y值、寬度、高度、顏色

JS,貪吃蛇,小游戲

這里我利用 || 運算設置了默認值,如果 || 左邊為false 則會自動取右邊的值,所以當實例化對象時若未傳參時 自動取 “||” 運算符右邊的值

然后在"Food"的原型上定義了一個 init 初始化方法

首先創建一個div ,并將此對象保存在 div變量中

然后 在地圖中 添加上這個 div  再逐步給這個 div元素 加上他的寬度、高度、背景顏色、并且設置絕對定位

那我們怎么定位呢?

這里我們可以把整個地圖看成是一個坐標系,把地圖的寬度除以 “食物”的寬度 來切分這個地圖 ,x=1則相當于1個“食物寬度”的單位長,x=3 則相當于3個“食物寬度的單位長”

高度同理

這里我取了隨機數  乘以  地圖被切分的總份數   這樣就會的到 隨機的 X和Y   然后乘以 寬度和高度 就的到了不會超出地圖的隨機坐標 ,舉例 :  因為Math.random(0,5)  是不包括5的

JS,貪吃蛇,小游戲

因為“食物”是會被貪吃蛇 “吃”掉的

所以我們必須創建一個方法來“消滅”這個“食物”,因此我定義了一個 remove 函數

并且 上方創建了一個 數組elements用于存放 創建出來的 "食物" 這個div元素 的對象,方便用來刪除,每次初始化“食物” 時,將對象追加入elements 數組 

JS,貪吃蛇,小游戲

我們遍歷 elements 數組, 通過數組中每個div對象 先找到其父級,然后通過removeChild 方法將其自身刪除JS,貪吃蛇,小游戲

因為有保存在elements 數組中,那我們想要刪除“食物就很方便了”,每次初始化之前我們秩序要調用一次 remove函數就是實現了“消滅”食物,然后再生成新的食物

因為此處的所有函數都寫在了一個 自調用的匿名函數中,所以內部的Food 對象,在外部是訪問不到的,

那怎么辦呢?

這里我調用了window 對象,將配置好的Food 對象暴露給window ,這樣,我們再其他的地方有需要時也可以實例化 Food了 

Snake.js 代碼分析

其實 “貪吃蛇”身體的實現和 “食物”的實現原理大體相同 ,首先我也同樣建立了一個elements數組,用于存放之后小蛇移動時所產生的舊的“身體”,用于刪除,因為都是局部變量,所以雖然兩個數組名字相同,但不會沖突

這里我也給小蛇設置了寬、高,寬高我設定為默認和食物相同,并且還設置了方向direction 這用來控制小蛇的移動方向,這里我默認給了“right”向右移動,

并且,因為當游戲開始時,小蛇必當有一個初始的長度,我給了它一個腦袋 二節身體,腦袋設置成了紅色,方便識別

所以我之后如果需要讓小蛇增加長度,體現越吃越長的感覺 ,只需要在 body這個數組中追加對象就可以了

JS,貪吃蛇,小游戲

 

好,小蛇的基本屬性配置完了,我們下一步就是要初始化小蛇 

同樣的,上方也提到了,我創建過一個elements數組,用于存放“小蛇”的舊身體,所以在初始化之前,我們需要調用remove函數,遍歷elements數組,和刪除“食物”一樣的方法,將舊的“蛇身”都給刪除了

JS,貪吃蛇,小游戲

執行完刪除之后呢,我們就可以專心初始化了,

蛇身這么長,那我們該怎么知道蛇身的每一節到底該在哪里呢

這時就用到了我們上方定義的  body 這個數組了,它存放了小蛇的身體的所有部分

我們只需要遍歷它,根據其中每個對象的屬性都進行創建新的div對象,同意設置其寬、高、left、top,并且,將創建好的對象又存入elements數組中,方便下一次刪除

JS,貪吃蛇,小游戲

定義完初始化的方法后,我們就得考慮小蛇的移動該怎么實現了,

既然是貪吃蛇游戲,我們肯定需要與玩家互動,讓玩家來操控小蛇的走向,

對了,我們自定義構造函數的時候不是設置過一個direction 屬性嗎,我們就得利用起來,依據此來判斷小蛇的走向

至于更改方向,我們放在之后的代碼中實現

這里我們定義了一個move 函數 ,并傳入兩個參數 food "食物對象" 和 map“地圖對象”  

那為什么要傳呢,

雖然我們這個demo里面只有一條小蛇,但這樣的寫法保留了同時開啟多個游戲的可能性

  首先我們獲取 body 數組的長度 存入i 中,然后倒序倒序倒序遍歷 i  ,根據 i 作為索引, 從蛇尾巴開始向蛇腦袋遍歷,大家想象一下,貪吃蛇的蛇身是不是都是按部就班的沿著腦袋走過的路徑走的? 你給它繞個直角、或者正方形它總是老老實實的走完,所以我們每次移動,只需要控制蛇腦袋移動,讓蛇身體讓它他們挨個獲取他們前面那一節身體的坐標就可以了

所以,這里我們倒序遍歷,將第 i 節身體賦值前一節身體的 x 屬性和 y 屬性

蛇身的重新賦值做完了,我們判斷一下蛇頭的移動方向,因為是固定的4個方向,所以這里使用switch較為方便,

根據 上、下、左、右不一樣的情況對 頭部的x和y增加或減少

既然是貪吃蛇,我們食物也創建好了,需要實現貪吃蛇吃食物這個過程

首先我們分別計算出 蛇腦袋和食物的X和Y

然后,我們判斷一下,

當蛇腦袋的x,y 和食物的x,y都相等的時候,

我們延長一節蛇身,這里我復制了一份最后一節蛇身體 然后追加入body數組,注意!

因為對象是引用類型,所以必須這樣拆開賦值

最后,再調用一次食物的初始化,產生新的食物

JS,貪吃蛇,小游戲

同樣的,這里我也將,Snake 對象暴露給window,供下方的Game.js中的代碼調用

JS,貪吃蛇,小游戲

Game.js 代碼分析

在Game.js中,開頭就定義了that 

用來保存this 的指向,供后面使用

我們分別實例化一個 “食物”對象和一個“貪吃蛇”對象

傳入地圖對象,并賦值

JS,貪吃蛇,小游戲

屬性設置好了

那既然是游戲那我們是不是應該設定點游戲規則,

當我們的小蛇到達地圖邊界時,小蛇就會一頭撞死了,游戲結束,

并且我們也沒有實現小蛇的移動,讓我們來接著實現吧

這里我定義了一個runSnake函數,傳入 food 和map 對象

首先,定義一個計時器,存入timeId這個變量中

調用一個蛇的 move(移動) 和 init (初始化函數)

在小蛇成功移動之后,我們再判斷一下,小蛇是否已經走到邊界了,

計算出,地圖寬度最多能被蛇頭的寬度分為幾份,高度同理

取出蛇頭自身的x和y

判斷 如果蛇頭x<0 說明越過左邊界,超過maxX則說明超過右邊界,

y同理

如果越過邊界,則清除定時器,執行一個彈框

注意,我在這個定時器中的方法后加個一個bind 并傳入了開始定義的 that ,也就是提前保存的this 指向,如果不加,這里的代碼多處用到了this ,因為setInterVal 的指向為window 所以會導致代碼出現錯誤,無法找到這些方法和屬性

JS,貪吃蛇,小游戲

接下來我們再來實現一下如何用鍵盤控制小蛇的移動

根據keycode 來更改 snake對象的 direction ,

同樣的,此處的this 指向也不正確,指向的是 觸發該事件的對象,這是無法調用snake對象的,所以我們必須改變它,在bind中傳入(that)

然后將Game 對象暴露給 window

JS,貪吃蛇,小游戲

接著定義初始化游戲的函數

分別調用food對象的初始化函數、小蛇的初始化函數,調用runSnake函數開啟定時器讓小蛇跑起來

最后綁定上keydown 事件

JS,貪吃蛇,小游戲

最后的最后

實例化一個Game對象

調用gm 的init  貪吃蛇小demo就實現了

JS,貪吃蛇,小游戲

效果展示

JS,貪吃蛇,小游戲

希望本文所述對大家JavaScript程序設計有所幫助。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲在线观看视频| 国产视频欧美视频| 久久久精品在线观看| 欧美一区二区三区免费观看| 亚洲成av人影院在线观看| 亚洲国产91色在线| 91av视频在线免费观看| 亚洲国产一区二区三区四区| 亚洲美腿欧美激情另类| 亚洲成人激情在线观看| 欧美日韩激情视频8区| 91av在线精品| 亚洲欧美日本伦理| 精品视频在线播放色网色视频| 91极品女神在线| 国产精品69精品一区二区三区| 精品视频在线播放| 亚洲国产欧美一区二区三区同亚洲| 国产精品免费久久久久影院| 欧美性xxxx极品hd满灌| 欧美日本精品在线| 色老头一区二区三区在线观看| 在线观看欧美成人| 日韩欧中文字幕| 一区二区国产精品视频| 久久精品国产亚洲7777| 97久久精品人人澡人人爽缅北| 国内伊人久久久久久网站视频| 国产精品视频自在线| 精品视频在线播放| 91国产精品视频在线| 日产精品99久久久久久| 日韩av快播网址| 九九热精品视频| 日韩在线观看免费全| 欧美激情奇米色| 国产精品久久久久久久久久久不卡| 国产精品久久久久久久久久久久久久| 亚洲成人在线网| 久久久精品免费视频| 色偷偷av亚洲男人的天堂| 久久久久久国产精品三级玉女聊斋| 日韩大胆人体377p| 国产精品欧美激情在线播放| 日韩av一区二区在线观看| 欧美福利视频在线| 国产精品自产拍高潮在线观看| 久久久中精品2020中文| 综合网日日天干夜夜久久| 自拍偷拍免费精品| 国产成人一区二区三区小说| 欧美在线一区二区三区四| 九九热这里只有精品6| 欧美精品www在线观看| 欧美成年人视频网站欧美| 精品久久久久久久久久久久久| 97视频com| 欧美国产欧美亚洲国产日韩mv天天看完整| 久久久精品国产亚洲| 在线视频欧美性高潮| 久久亚洲影音av资源网| 色偷偷88888欧美精品久久久| 一区二区三区高清国产| 欧美第一页在线| 中文日韩在线视频| 亚洲伊人第一页| 97在线精品视频| 欧美亚洲日本黄色| 国产亚洲精品久久| 国产精品v日韩精品| 国产一区二区三区久久精品| 久久久人成影片一区二区三区| 91在线免费视频| 成人欧美在线视频| 国产精品极品美女粉嫩高清在线| 欧美激情第6页| 成人免费自拍视频| 日韩国产中文字幕| 亚洲色图狂野欧美| 色爱av美腿丝袜综合粉嫩av| 亚洲天堂男人的天堂| 欧美超级免费视 在线| 美女黄色丝袜一区| 欧美午夜影院在线视频| 亚洲精品v欧美精品v日韩精品| 97在线日本国产| 色无极亚洲影院| 国产精品久久久久久搜索| 国产亚洲精品激情久久| 欧美性开放视频| 国产精品丝袜白浆摸在线| 日韩视频在线观看免费| 日韩国产一区三区| 欧美成人在线网站| 国产精品尤物福利片在线观看| 久久香蕉国产线看观看av| 国产精品美乳一区二区免费| 欧美高清激情视频| 亚洲无限乱码一二三四麻| 性欧美暴力猛交69hd| 日韩视频在线免费观看| 亚洲第一精品自拍| 成人精品一区二区三区电影黑人| 欧美在线性视频| 一区二区三区四区视频| 亚洲午夜精品久久久久久久久久久久| 国产一区二区精品丝袜| 成人国产精品久久久久久亚洲| 国产成人精品在线| 国产性猛交xxxx免费看久久| 91国内免费在线视频| 久久手机精品视频| 国产亚洲美女久久| 亚洲伦理中文字幕| 日韩美女激情视频| 亚洲老板91色精品久久| 久久人人爽亚洲精品天堂| 久久亚洲精品毛片| 欧美在线观看视频| 国产日韩欧美在线视频观看| 亚洲综合大片69999| 国语对白做受69| www国产亚洲精品久久网站| 成人性生交大片免费看小说| 亚洲人成在线播放| 久久国产精品久久精品| 亚洲性生活视频在线观看| 日韩成人在线视频网站| 在线日韩第一页| 91欧美视频网站| 久久精品国产亚洲精品| 成人黄色生活片| 国产视频亚洲精品| 欧美贵妇videos办公室| 欧美精品激情视频| 欧美另类在线播放| 欧美视频中文字幕在线| 欧美在线视频观看| 91在线视频九色| 一区二区三区日韩在线| 亚洲国产精品久久久久久| 少妇高潮久久久久久潘金莲| 亚洲国产古装精品网站| 亚洲精品免费一区二区三区| 日韩精品中文字幕有码专区| 成人免费自拍视频| 日韩av网站大全| 欧美电影免费在线观看| 国产91色在线免费| 亚洲精品乱码久久久久久金桔影视| 亚洲欧美日韩高清| 亚洲精品美女视频| 亚洲国产精品一区二区三区| 亚洲精品国产精品国产自| 91精品国产乱码久久久久久蜜臀| 欧美成人免费视频| 日韩视频在线免费观看| 91精品视频免费| 国产精品久久一区主播| 国产小视频国产精品| 国产成人精品在线播放| 狠狠做深爱婷婷久久综合一区| 亚洲欧美成人网| 欧美午夜女人视频在线|