日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何用不到200行代码实现经典小游戏贪吃蛇,附源代码及详细实现思路

發(fā)布時(shí)間:2024/3/12 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何用不到200行代码实现经典小游戏贪吃蛇,附源代码及详细实现思路 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

不多廢話,直接上鏈接

鏈接:https://pan.baidu.com/s/1ZKtVNhzR4fIzNZSGWgFKQw?pwd=zglt?
提取碼:zglt

有需要的好兄弟們可以直接取用,想要了解一下編程思路的朋友們可以繼續(xù)往下看,如有任何問題可以在評論區(qū)留言。

首先貪吃蛇小游戲主要需要實(shí)現(xiàn)一下幾個(gè)功能:

(1)小蛇不斷向前移動(dòng)

(2)小蛇根據(jù)鍵盤按鍵改變移動(dòng)方向

(3)小蛇撞墻或撞到自己后游戲結(jié)束

(4)地圖內(nèi)隨機(jī)生成蘋果

(5)小蛇吃到蘋果后增加一格

接下來我們逐條實(shí)現(xiàn)

首先在頁面內(nèi)生成一個(gè)div,劃出800*800的區(qū)域,并使其居中,將其class名設(shè)置為back

back的內(nèi)容如下:

.back {border: 2px solid black;width: 800px;height: 800px;margin: 0 auto;}

生成效果:

?然后在.back中添加兩個(gè)屬性 display: flex;和?flex-wrap: wrap;

.back {border: 2px solid black;width: 800px;height: 800px;margin: 0 auto;display: flex;flex-wrap: wrap;}

這兩個(gè)屬性是彈性盒子的內(nèi)容,第一個(gè)屬性設(shè)置為flex值將back聲明為彈性盒子,第二個(gè)屬性設(shè)置該盒子內(nèi)容自動(dòng)換行,設(shè)置這兩個(gè)屬性的原因我們接下來講。

然后我們聲明一個(gè)css樣式名為.box,設(shè)置.box的寬高為40,并設(shè)置為怪異盒子

.box {width: 40px;height: 40px;box-sizing: border-box;}

box-sizing: border-box;用于將元素設(shè)置為怪異盒子,怪異盒子的特殊之處在于其總寬高固定,設(shè)置邊框不會(huì)增加其實(shí)際寬高。

左為怪異盒子,右為普通盒子,給予20像素邊框右者實(shí)際大小為140*140

這時(shí)頁面中并沒有叫.box的元素,接下來我們使用JavaScript代碼給大背景添加小格子。

首先獲取clas名為back的大背景。

var back = document.querySelector(".back");

接下來寫一個(gè)執(zhí)行400次的for循環(huán),每次循環(huán)都用.creatElement()函數(shù)生成一個(gè)新的div標(biāo)簽,并將該標(biāo)簽的class名設(shè)置為box,然后使用.appendChild方法添加進(jìn)大背景中:

for (let i = 0; i < 400; i++) { //添加地圖格子var box = document.createElement("div");box.className = "box";back.appendChild(box);}

由于大背景寬高為800,小格子寬高為40,這樣大背景中一共可以塞下20*20=400個(gè)小格子,由于我們給父元素設(shè)置為了彈性盒子且自動(dòng)換行,這時(shí)當(dāng)?shù)谝恍斜恍「褡尤麧M時(shí)多余的小格子就自動(dòng)填充到下一行中(類似于浮動(dòng)),這樣逐行填充后就生成了一個(gè)400格的棋盤。

為了方便演示,我們給小格子添加一個(gè)邊框,這是最終效果:

?接下來我們開始畫蛇,首先用querySelectAll()方法獲取大背景中的400個(gè)小格子,并命名為box

var box = document.querySelectorAll(".box"); //獲取所有格子

然后給格子添加顏色,需要注意的是,由于游戲開始時(shí)蛇頭的位置是朝右的,所以蛇頭一格并不是box[0],而是box[2],這里我設(shè)置蛇頭為青色,身體為灰色。

//聲明初始蛇樣式box[0].style.background = "grey";box[1].style.background = "grey";box[2].style.background = "cyan";

最終效果:

?現(xiàn)在我們有了一條三格長的小蛇,接下來就是如何讓小蛇動(dòng)起來,這里當(dāng)然需要用到計(jì)時(shí)器

var timer = setInterval(move, 200);

setInterval()為間隔計(jì)時(shí)器,內(nèi)部傳入兩個(gè)參數(shù),第一個(gè)為調(diào)用的函數(shù)名,第二個(gè)為間隔時(shí)間(單位為毫秒),當(dāng)前該計(jì)時(shí)器會(huì)每隔200毫秒調(diào)用一次函數(shù),即讓小蛇一秒走五次,如果覺得太慢也可以把這個(gè)值調(diào)小,這樣小蛇會(huì)移動(dòng)得更快。

然后我們需要寫讓小蛇動(dòng)起來的函數(shù)move(),不過在此之前,先將小蛇的頭和尾位置以及整體位置存儲一下。

//聲明蛇,并以行和列的形式存儲蛇每一格的位置var snake = [{hang:0,lie: 0}, {hang:0,lie: 1}, {hang:0,lie: 2}];var head = {}; //聲明蛇頭head.hang = snake[2].hang;//獲取當(dāng)前蛇頭位置head.lie = snake[2].lie;var tail = {}; //聲明蛇尾tail.hang = snake[0].hang;//獲取當(dāng)前蛇尾位置tail.lie = snake[0].lie;

接下來我們來寫函數(shù)move(),首先我們要理解一點(diǎn),想讓小蛇前進(jìn)一個(gè)其實(shí)并不需要讓小蛇每一段身體都前進(jìn),只需要讓頭部的位置前移一格,讓原本頭部的位置變?yōu)樯眢w,再刪除最后一節(jié)尾部即可。

?這樣我們就有了基本的實(shí)現(xiàn)思路,接下來就是如何用代碼實(shí)現(xiàn)。

首先在移動(dòng)前,我們需要判斷蛇頭是否撞墻,若撞墻則游戲直接結(jié)束無需再進(jìn)行移動(dòng),判斷是否撞墻,即判斷新的頭部位置行和列數(shù)值是否大于-1且小于20,不過向右移動(dòng)時(shí)只需要判斷右側(cè)即可。

function move() {if (head.lie + 1 < 20) { //判斷是否向右撞墻} else {alert("游戲結(jié)束"); //撞墻,游戲結(jié)束;clearInterval(timer);//清除定時(shí)器,讓小蛇停止移動(dòng)};}

由于頭部遇到的情況比較復(fù)雜(撞墻,吃蘋果,撞自己等),所以這里我們將頭部移動(dòng)單獨(dú)封裝成一個(gè)函數(shù)moveHead(),不過在調(diào)用該函數(shù)前,先設(shè)置好新頭部的位置。

function move() {if (head.lie + 1 < 20) { //判斷是否向右撞墻head.列 += 1;//向右移動(dòng)即頭部列位置+1moveHead();//調(diào)用頭部移動(dòng)函數(shù)} else {alert("游戲結(jié)束"); //撞墻,游戲結(jié)束;clearInterval(timer); //清除定時(shí)器,讓小蛇停止移動(dòng)};}function moveHead() {}//聲明頭部移動(dòng)函數(shù)

接下來正式開始移動(dòng)小蛇,首先獲取到新的頭部位置在數(shù)組中的下標(biāo),由于地圖每行為20格,那么位置下標(biāo)=行數(shù)值*20+列數(shù)值,獲取后將新頭部格子刷成青色。

function moveHead() { //聲明頭部移動(dòng)函數(shù)//獲取頭部位置在數(shù)組中的下標(biāo),并儲存為positonvar position = head.hang * 20 + head.lie;//利用下標(biāo)在box數(shù)組中定位新的頭位置,并將其刷成青色box[position].style.background = "cyan";}

當(dāng)前效果:

?然后我們需要將原蛇頭位置的青色變?yōu)榛疑?#xff0c;原蛇頭位置即當(dāng)前snake數(shù)組中的最后一位,即數(shù)組長度-1的位置(數(shù)組下標(biāo)從0開始,所以減一)。

function moveHead() { //聲明頭部移動(dòng)函數(shù)//獲取新頭部位置在數(shù)組中的下標(biāo),并儲存為positonvar position = head.hang * 20 + head.lie;//利用下標(biāo)在box數(shù)組中定位新的頭位置,并將其刷成青色box[position].style.background = "cyan";//獲取原有頭部位置的下標(biāo),并儲存為positonposition = snake[snake.length - 1].hang * 20 + snake[snake.length - 1].lie;//將原蛇頭位置刷成灰色box[position].style.background = "grey";}

當(dāng)前效果:

接下來就是刪除蛇尾,蛇尾位置即snak[0]存儲的位置。

function moveHead() { //聲明頭部移動(dòng)函數(shù)//獲取新頭部位置在數(shù)組中的下標(biāo),并儲存為positonvar position = head.hang * 20 + head.lie;//利用下標(biāo)在box數(shù)組中定位新的頭位置,并將其刷成青色box[position].style.background = "cyan";//獲取原有頭部位置的下標(biāo),并儲存為positonposition = snake[snake.length - 1].hang * 20 + snake[snake.length - 1].lie;//將原蛇頭位置刷成青色box[position].style.background = "grey";//獲取蛇尾位置position = snake[0].hang * 20 + snake[0].lie;//刪除蛇尾顏色box[position].style.background = "";}

?最終效果:

?這時(shí)我們還需要做最后的處理工作,雖然頁面中的snake位置已經(jīng)變化了,但是snake數(shù)組中存儲的位置并沒有改變,所以現(xiàn)在我們要修改snake數(shù)組中的內(nèi)容。

var newhead = { //處理對象淺復(fù)制問題"hang": head.hang,"lie": head.lie};snake.push(newhead) //將新的頭位置添加進(jìn)數(shù)組末尾snake.shift() //刪除數(shù)組中尾部位置

由于這里涉及到對象淺復(fù)制問題,所以每次添加都需要聲明一個(gè)新對象,感興趣的朋友們可以自行了解一下。

最終效果:

?這樣小蛇的移動(dòng)就完成了,接下來我們來控制小蛇的移動(dòng)方向。

首先我們聲明一個(gè)變量,設(shè)置其數(shù)值為ArrowRight,為什么是這個(gè)值我們接下來講。

var ahead = "ArrowRight"; //聲明蛇的前進(jìn)方向

然后我們給頁面添加一個(gè)監(jiān)聽事件,監(jiān)聽鼠標(biāo)按下,并傳入一個(gè)參數(shù)e。

var ahead = 39; //聲明蛇的前進(jìn)方向document.addEventListener("keydown", (e) => {})//添加鍵盤按下的監(jiān)聽事件并傳入e

這里傳入的e可以簡單理解為事件本身,其內(nèi)部存儲了觸發(fā)該事件時(shí)的一系列數(shù)據(jù),這里我們需要用到其中的一個(gè)數(shù)據(jù).key,該屬性存儲了觸發(fā)事件的按鍵名稱。

打印e.key時(shí)分別點(diǎn)擊小鍵盤上下左右四個(gè)鍵時(shí)返回的名稱:

?這就是我們設(shè)置ahead的值為ArrowRight的原因,在JavaScript中不同的按鍵有不同的名稱,我們只需要根據(jù)名稱就可以利用分支語句決定小蛇前進(jìn)的方向,同時(shí)我們還可以添加一個(gè)判斷語句,防止小蛇出現(xiàn)180度調(diào)頭的情況(這里使用了JavaScript的三目運(yùn)算,感興趣的朋友們可以自行了解)。

document.addEventListener("keydown", (e) => { //添加鍵盤按下的監(jiān)聽事件并傳入eswitch (e.key) { //添加分支語句,設(shè)置移動(dòng)方向case "ArrowUp": //判斷e.key是否等于該關(guān)鍵字ahead != "ArrowDown" ? ahead = e.key : ""; //判斷并給ahead賦新值break; //結(jié)束Switch執(zhí)行,防止下方的代碼影響結(jié)果case "ArrowRight":ahead != "ArrowLeft" ? ahead = e.key : ""; //判斷并給ahead賦新值break;case "ArrowDown":ahead != "ArrowUp" ? ahead = e.key : ""; //判斷并給ahead賦新值break;case "ArrowLeft":ahead != "ArrowRight" ? ahead = e.key : ""; //判斷并給ahead賦新值break;}console.log(e.key);})

然后再給前面的move()函數(shù)也添加一個(gè)Switch分支語句,通過ahead的值判斷頭部向哪個(gè)方向移動(dòng),向上移動(dòng)時(shí)頭部行位置減一,向下移動(dòng)時(shí)頭部行位置加一,向左和向右則為頭部列位置減一和加一。

function move() {switch (ahead) { //通過ahead判斷移動(dòng)方向case "ArrowUp": //是否向上if (head.hang - 1 > -1) {head.hang -= 1; //向上移動(dòng)即頭部行位置-1moveHead();} else {alert("游戲結(jié)束");clearInterval(timer);};break;case "ArrowDown": //是否向下if (head.hang + 1 < 20) {head.hang += 1; //向下移動(dòng)即頭部行位置-1moveHead();} else {alert("游戲結(jié)束");clearInterval(timer);};break;case "ArrowLeft": //是否向左if (head.lie - 1 > -1) {head.lie -= 1; //向左移動(dòng)即頭部列位置-1moveHead();} else {alert("游戲結(jié)束");clearInterval(timer);};break;case "ArrowRight": //是否向右if (head.lie + 1 < 20) {head.lie += 1; //向右移動(dòng)即頭部列位置+1moveHead();} else {alert("游戲結(jié)束");clearInterval(timer);};break;}}

由于目前我們可以通過按鍵來改變ahead的值,而move()函數(shù)的移動(dòng)方向由ahead決定,所以我們就間接實(shí)現(xiàn)了通過按鍵控制小蛇的移動(dòng)方向,效果如下:

?下一步就是聲明蘋果了,首先我們創(chuàng)建函數(shù)addApple(),并聲明對象apple存儲蘋果的位置

var apple = {};function addapple() {}

接下來我們需要用到一個(gè)數(shù)學(xué)方法Math.random(),該方法的作用是聲明一個(gè)0到1之間的隨機(jī)浮點(diǎn)數(shù),由于我們的地圖大小為20*20格,所以我們將生成的數(shù)字乘20并取整,這樣就得到了一個(gè)0到20之間的隨機(jī)整數(shù)(向下取整所以不含20)。

function addapple() { //隨機(jī)生成蘋果函數(shù)apple.hang = parseInt(Math.random() * 20); //隨機(jī)生成行apple.lie = parseInt(Math.random() * 20); //隨機(jī)生成列var position = apple.lie + apple.hang * 20 //通過行和列隨機(jī)生成蘋果box[position].style.background = "red"; //在隨機(jī)確定的位置刷紅色}

這時(shí)我們調(diào)用函數(shù),蘋果就會(huì)出現(xiàn)在地圖中

?不過由于目前蘋果的位置完全隨機(jī),所以有可能會(huì)直接生成在小蛇身上,這是我們需要避免的問題,即當(dāng)隨機(jī)生成的蘋果位置有顏色時(shí)重新生成,這里我們可以通過使用一個(gè)簡單的遞歸來解決該問題。

var apple = {}; //聲明對象存儲蘋果位置function addapple() { //隨機(jī)生成蘋果函數(shù)apple.hang = parseInt(Math.random() * 20); //隨機(jī)生成行apple.lie = parseInt(Math.random() * 20); //隨機(jī)生成列var position = apple.lie + apple.hang * 20 //通過行和列隨機(jī)生成蘋果if (box[position].style.background != "") { //判斷隨機(jī)生成的蘋果位置是否有顏色addapple(); //若有顏色重新調(diào)用該函數(shù)生成} else {box[position].style.background = "red"; //若無顏色則刷紅}}

這時(shí)當(dāng)生成的隨機(jī)位置有顏色時(shí)該函數(shù)就會(huì)重新被調(diào)用,生成一個(gè)新的蘋果位置,若沒有顏色則結(jié)束遞歸,并在該位置刷紅色。

然后就是最后一步,當(dāng)小蛇吃到蘋果時(shí)變長一格,同時(shí)生成新的蘋果位置,其實(shí)這一功能很好實(shí)現(xiàn),我們在移動(dòng)小蛇時(shí)會(huì)刪除小蛇的尾部,現(xiàn)在只需要讓小蛇頭部碰到蘋果時(shí)尾部不刪除即可增加一格長度,所以我們需要對movehead()函數(shù)進(jìn)行修改:

function moveHead() {//獲取新頭部位置在數(shù)組中的下標(biāo),并儲存為positonvar position = head.hang * 20 + head.lie;if (box[position].style.background == "red") { //判斷新的頭部位置是否為紅色snake.unshift({"hang": snake[0].hang,"lie": snake[0].lie}); //若為紅色則復(fù)制一份蛇尾,刪除時(shí)便會(huì)保留蛇尾addapple(); //調(diào)用函數(shù),生成新蘋果}box[position].style.background = "cyan";position = snake[snake.length - 1].hang * 20 + snake[snake.length - 1].lie;box[position].style.background = "grey";position = snake[0].hang * 20 + snake[0].lie;box[position].style.background = "";var newhead = {"hang": head.hang,"lie": head.lie};snake.push(newhead)snake.shift() //刪除數(shù)組中尾部位置}

同時(shí)這里我們還可以添加一個(gè)判斷,若新蛇頭位置為灰色,則說明小蛇撞到了自己,這時(shí)可以直接結(jié)束游戲:

function moveHead() {//獲取新頭部位置在數(shù)組中的下標(biāo),并儲存為positonvar position = head.hang * 20 + head.lie;if (box[position].style.background == "red") { //判斷新的頭部位置是否為紅色snake.unshift({"hang": snake[0].hang,"lie": snake[0].lie}); //若為紅色則復(fù)制一份蛇尾,刪除時(shí)便會(huì)保留蛇尾addapple(); //調(diào)用函數(shù),生成新蘋果} else if (box[position].style.background == "grey") {//判斷新的頭部位置是否為灰色alert("游戲結(jié)束");//若為灰色則直接結(jié)束游戲clearInterval(timer);}box[position].style.background = "cyan";position = snake[snake.length - 1].hang * 20 + snake[snake.length - 1].lie;box[position].style.background = "grey";position = snake[0].hang * 20 + snake[0].lie;box[position].style.background = "";var newhead = {"hang": head.hang,"lie": head.lie};snake.push(newhead)snake.shift() //刪除數(shù)組中尾部位置}

到這里一款可以正常游玩的貪吃蛇小游戲就算基本完工了,刪除注釋的話總代碼量可能都不到150行,雖然有很多細(xì)節(jié)有待優(yōu)化;

那么本期的內(nèi)容就到這里,如有任何問題歡迎在評論區(qū)留言,up都會(huì)盡量解答。

----------------------------------------------分割線-----------------------------------------------

后續(xù)我又對代碼進(jìn)行了一點(diǎn)優(yōu)化,首先是添加了分?jǐn)?shù)和規(guī)則

規(guī)則不難寫,分?jǐn)?shù)的話只需要在全局聲明一個(gè)變量number?來存儲分?jǐn)?shù),每次撞到蘋果后該數(shù)值加一即可。

var p = document.querySelector("p");//獲取第一行,分?jǐn)?shù)行 var number = 0; //存儲當(dāng)前分?jǐn)?shù)function moveHead() { //聲明頭部移動(dòng)函數(shù).....if (box[position].style.background == "red") { //判斷新的頭部位置是否為紅色snake.unshift({"hang": snake[0].hang,"lie": snake[0].lie}); //若為紅色則復(fù)制一份蛇尾,刪除時(shí)便會(huì)保留蛇尾addapple(); //調(diào)用函數(shù),生成新蘋果number++; //number加一分p.innerHTML = number + "分"; //改變p標(biāo)簽內(nèi)容} else if (box[position].style.background == "grey") { //判斷新的頭部位置是否為灰色alert("游戲結(jié)束"); //若為灰色則直接結(jié)束游戲clearInterval(timer);}.....}

然后是暫停功能,只需要在addEventListener監(jiān)聽事件的Switch分支中添加一個(gè)空格分支,單擊空格時(shí)彈出一個(gè)窗口即可暫停,當(dāng)瀏覽器顯示窗口時(shí)計(jì)時(shí)器是停止運(yùn)行的。

document.addEventListener("keydown", (e) => { //添加鍵盤按下的監(jiān)聽事件并傳入eswitch (e.key) { //添加分支語句,設(shè)置移動(dòng)方向.....case " ":alert("暫停中。。。");}console.log(e.key);});

最后我把蛇和蘋果的顏色放到了代碼最上方,這樣可以直接修改所有代碼中的顏色。

總結(jié)

以上是生活随笔為你收集整理的如何用不到200行代码实现经典小游戏贪吃蛇,附源代码及详细实现思路的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。