基于JavaScript實(shí)現(xiàn)貪吃蛇游戲
本文實(shí)例為大家分享了JavaScript實(shí)現(xiàn)貪吃蛇游戲的具體代碼,供大家參考,具體內(nèi)容如下
1.結(jié)構(gòu)
創(chuàng)建一個(gè)盒子box作為蛇的身體,當(dāng)前盒子中只有一個(gè)子元素,代表此時(shí)蛇的長(zhǎng)度為1.
在創(chuàng)建一個(gè)盒子food作為貪吃蛇的食物。
<div id="box"> <div></div> </div> <div id="food"></div>
2.CSS
設(shè)置蛇和食物的樣式,這里注意蛇和食物都是絕對(duì)定位。
<style>
*{
padding: 0px;
margin: 0px;
}
#box div{
width: 30px;
height: 30px;
box-sizing: border-box;
background: green;
border: 1px solid black;
position: absolute;
}
#food{
width: 30px;
height: 30px;
background: brown;
position: absolute;
}
</style>
3.腳本
獲取蛇的身體和每一個(gè)子元素
var box = document.getElementById("box");
var boxs = document.getElementById("box").children;
定義蛇頭的位置
var snackX = 0; var snackY = 0;
獲取屏幕寬度和高度,以此來(lái)設(shè)定墻的邊界,以限制蛇的移動(dòng)范圍。
var cw = document.documentElement.clientWidth; var ch = document.documentElement.clientHeight; var minsnackX = 0; var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth; var minsnackY = 0; var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;
定義初始的移動(dòng)方向。
var turn = "right";
獲取食物元素,并設(shè)置食物的位置坐標(biāo)。
var foodele = document.getElementById("food");
var foodX,foodY;
蛇的初始化
for(var i = 0; i <6 ; i++){
box.appendChild(boxs[0].cloneNode(true));
}
刷新食物
function food(){
//此處的坐標(biāo)要先獲取頁(yè)面最大支持的蛇身體的塊數(shù),然后在塊數(shù)中隨機(jī),然后乘以塊數(shù)的大小,
//因?yàn)樯叩囊苿?dòng)每一步都是固定的,想要判定食物和蛇頭重合就必須坐標(biāo)是整塊的倍數(shù)。
foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
//判定當(dāng)食物的產(chǎn)生位置和蛇的任何一個(gè)位置重合時(shí)就重新生成食物。
for(var i = 0;i<boxs.length;i++){
if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
food();
}
}
foodele.style.left = foodX + "px";
foodele.style.top = foodY + "px";
}
調(diào)用food()方法 生成第一個(gè)食物
food();
設(shè)置定時(shí)器 每次執(zhí)行一次蛇的運(yùn)行方法
var timer = setInterval(function(){
snackMOve();
},150)
封裝一個(gè)蛇的運(yùn)動(dòng)方法
//移動(dòng)和判定邊界
function snackMOve(){
//此處為判定方向 根據(jù)判定的方向,向改方向前進(jìn)一個(gè)方塊
switch(turn){
case "right":snackX +=30;break;
case "left":snackX -=30;break;
case "bottom":snackY +=30;break;
case "top":snackY -=30;break;
}
//如果蛇越過(guò)了墻就從另一端出現(xiàn)
if(snackX > maxsnackX){
snackX = 0;
}
if(snackX < minsnackX){
snackX = maxsnackX;
}
if(snackY > maxsnackY){
snackY = 0;
}
if(snackY < minsnackY){
snackY = maxsnackY;
}
//從最后一個(gè)開始,每個(gè)元素跟隨上一個(gè)元素的位置
for(var i = boxs.length-1; i >0 ; i--){
boxs[i].style.left = boxs[i-1].style.left;
boxs[i].style.top = boxs[i-1].style.top ;
}
//第一個(gè)也就是蛇頭的位置,永遠(yuǎn)是根據(jù)方向獲取的位置
boxs[0].style.left = snackX + "px";
boxs[0].style.top = snackY + "px" ;
//判定吃到食物 就長(zhǎng)大和刷新
//當(dāng)蛇頭位置移動(dòng)之后與食物重合 那么刷新食物,并且在蛇的身體中插入一個(gè)克隆的元素,相當(dāng)于長(zhǎng)度+1
if(snackX === foodX && snackY === foodY){
food();
box.appendChild(boxs[0].cloneNode(true));
}else{
//判定撞死
//當(dāng)蛇頭與身體中的任何一個(gè)元素重合,那么判定結(jié)束游戲,停止定時(shí)器
for(var i = 1;i<boxs.length;i++){
if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
clearInterval(timer);
alert("失敗");
}
}
}
}
蛇的運(yùn)動(dòng)方向
document.onkeydown = function(eve){
var e = eve||event;
var keyCode = e.keyCode||e.which;
switch(keyCode){
case 37:if(turn === "right"){break;}turn = "left";break;
case 38:if(turn === "bottom"){break;}turn = "top";break;
case 39:if(turn === "left"){break;}turn = "right";break;
case 40:if(turn === "top"){break;}turn = "bottom";break;
}
}
全部代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
*{
padding: 0px;
margin: 0px;
}
#box div{
width: 30px;
height: 30px;
box-sizing: border-box;
background: green;
border: 1px solid black;
position: absolute;
}
#food{
width: 30px;
height: 30px;
background: brown;
position: absolute;
}
</style>
</head>
<body>
<div id="box">
<div></div>
</div>
<div id="food"></div>
<script>
var box = document.getElementById("box");
var boxs = document.getElementById("box").children;
var snackX = 0;
var snackY = 0;
var cw = document.documentElement.clientWidth;
var ch = document.documentElement.clientHeight;
var minsnackX = 0;
var maxsnackX = Math.floor(cw / boxs[0].offsetWidth)*boxs[0].offsetWidth;
var minsnackY = 0;
var maxsnackY = Math.floor(ch / boxs[0].offsetHeight)*boxs[0].offsetHeight;
var turn = "right";
var foodele = document.getElementById("food");
var foodX,foodY;
for(var i = 0; i <6 ; i++){
box.appendChild(boxs[0].cloneNode(true));
}
//隨機(jī)食物
function food(){
foodX = parseInt( Math.random()*Math.floor(cw / boxs[0].offsetWidth))*boxs[0].offsetWidth;
foodY = parseInt( Math.random()*Math.floor(ch / boxs[0].offsetHeight))*boxs[0].offsetHeight;
for(var i = 0;i<boxs.length;i++){
if(foodX + "px" === boxs[i].style.left && foodY + "px" === boxs[i].style.top){
food();
}
}
foodele.style.left = foodX + "px";
foodele.style.top = foodY + "px";
}
food();
//設(shè)置定時(shí)器 移動(dòng)
var timer = setInterval(function(){
snackMOve();
},150)
//移動(dòng)和判定邊界
function snackMOve(){
switch(turn){
case "right":snackX +=30;break;
case "left":snackX -=30;break;
case "bottom":snackY +=30;break;
case "top":snackY -=30;break;
}
//根據(jù)邊界歸零
if(snackX > maxsnackX){
snackX = 0;
}
if(snackX < minsnackX){
snackX = maxsnackX;
}
if(snackY > maxsnackY){
snackY = 0;
}
if(snackY < minsnackY){
snackY = maxsnackY;
}
for(var i = boxs.length-1; i >0 ; i--){
boxs[i].style.left = boxs[i-1].style.left;
boxs[i].style.top = boxs[i-1].style.top ;
}
boxs[0].style.left = snackX + "px";
boxs[0].style.top = snackY + "px" ;
//判定吃到食物 就長(zhǎng)大和刷新
if(snackX === foodX && snackY === foodY){
food();
box.appendChild(boxs[0].cloneNode(true));
}else{
//判定撞死 暫停計(jì)時(shí)器 刷新
for(var i = 1;i<boxs.length;i++){
// console.log(boxs[i].style.left);
if(snackX + "px" === boxs[i].style.left && snackY + "px" === boxs[i].style.top){
clearInterval(timer);
alert("失敗");
// console.log(1)
}
}
}
}
//方向
document.onkeydown = function(eve){
var e = eve||event;
var keyCode = e.keyCode||e.which;
switch(keyCode){
case 37:if(turn === "right"){break;}turn = "left";break;
case 38:if(turn === "bottom"){break;}turn = "top";break;
case 39:if(turn === "left"){break;}turn = "right";break;
case 40:if(turn === "top"){break;}turn = "bottom";break;
}
}
</script>
</body>
</html>
總結(jié)
貪吃蛇的思路主要是有以下幾個(gè)部分
1.食物的隨機(jī)出現(xiàn)(不能隨機(jī)在蛇身上)
2.定時(shí)器控制蛇的移動(dòng)
3.墻的判定
4.蛇的運(yùn)動(dòng)邏輯
5.運(yùn)動(dòng)方向的判定
6.吃到食物的判定
7.蛇頭與身體的判定(即游戲結(jié)束的判定)
小編還為大家準(zhǔn)備了精彩的專題:javascript經(jīng)典小游戲匯總
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用js在layui中實(shí)現(xiàn)上傳圖片壓縮
這篇文章主要介紹了使用js在layui中實(shí)現(xiàn)上傳圖片壓縮,layui 是一款采用自身模塊規(guī)范編寫的前端 UI 框架,js上傳圖片壓縮百度有很多方法,,需要的朋友可以參考下2019-06-06
給頁(yè)面渲染時(shí)間加速 干掉Dom Level 0 Event
我們?nèi)サ羰录壎ǖ倪壿?發(fā)現(xiàn)只渲染dom元素,不綁定事件的時(shí)間,僅僅125ms,可見事件綁定的時(shí)間消耗還是很大的 ,尤其是第一種方式,也就是Dom Level 0 Event,最為耗時(shí)2012-12-12
一個(gè)字符串反轉(zhuǎn)函數(shù)可實(shí)現(xiàn)字符串倒序
這篇文章主要介紹了一個(gè)字符串反轉(zhuǎn)函數(shù)可實(shí)現(xiàn)字符串倒序,很簡(jiǎn)單,但很實(shí)用,感興趣的朋友可以參考下2014-09-09
小程序角標(biāo)的添加及綁定購(gòu)物車數(shù)量進(jìn)行實(shí)時(shí)更新的實(shí)現(xiàn)代碼
這篇文章主要介紹了小程序角標(biāo)的添加及綁定購(gòu)物車數(shù)量進(jìn)行實(shí)時(shí)更新的實(shí)現(xiàn)代碼,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
ztree獲取當(dāng)前選中節(jié)點(diǎn)子節(jié)點(diǎn)id集合的方法
這篇文章主要介紹了ztree獲取當(dāng)前選中節(jié)點(diǎn)子節(jié)點(diǎn)id集合的方法,實(shí)例分析了ztree的方法transformToArray使用技巧,需要的朋友可以參考下2015-02-02
微信小程序嵌入H5頁(yè)面(webview)的基本用法和父子傳參數(shù)詳細(xì)說(shuō)明
微信小程序中嵌入H5頁(yè)面通常指的是在小程序中使用Web-view組件來(lái)加載外部的網(wǎng)頁(yè),下面這篇文章主要給大家介紹了關(guān)于微信小程序嵌入H5頁(yè)面(webview)的基本用法和父子傳參數(shù)的相關(guān)資料,需要的朋友可以參考下2024-08-08
JS數(shù)據(jù)雙向綁定原理與用法實(shí)例分析
這篇文章主要介紹了JS數(shù)據(jù)雙向綁定原理與用法,結(jié)合實(shí)例形式分析了JavaScript數(shù)據(jù)雙向綁定相關(guān)原理、實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下2019-11-11
JavaScript實(shí)現(xiàn)表格動(dòng)態(tài)變色
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)表格動(dòng)態(tài)變色,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
bootstrap自定義樣式之bootstrap實(shí)現(xiàn)側(cè)邊導(dǎo)航欄功能
bootstrap自帶的響應(yīng)式導(dǎo)航欄是向下滑動(dòng)的,有時(shí)滿足不了個(gè)性化的需求,需要做一個(gè)類似于android drawerLayout 側(cè)滑的菜單,這就是我要實(shí)現(xiàn)的bootstrap自定義側(cè)滑菜單。接下來(lái)通過(guò)本文給大家介紹bootstrap實(shí)現(xiàn)側(cè)邊導(dǎo)航欄功能,感興趣的朋友一起看看吧2018-09-09

