js實(shí)現(xiàn)簡單貪吃蛇游戲
本文實(shí)例為大家分享了js實(shí)現(xiàn)簡單貪吃蛇游戲的具體代碼,供大家參考,具體內(nèi)容如下
上下左右鍵控制方向使貪吃蛇吃葡萄
吃5個葡萄,游戲結(jié)束時左上角為總得分。
運(yùn)行結(jié)果:

界面和css代碼這里就不加贅述了,主要貼js代碼(加了注釋):
var config = {
width: 20, //一個格子的寬度
height: 20, //一個格子的高度
tr: 30, //行數(shù)
td: 30 //列數(shù)
}
var snake = null, //Snake的實(shí)例
food = null, //Food的實(shí)例
game = null; //游戲的實(shí)例
//我們把蛇移動的整個區(qū)域設(shè)置成一個具有30列30行的網(wǎng)格坐標(biāo)
//方塊(格子)坐標(biāo)位置
/**
0,0 (0,0)
20,0 (1,0)
40,0 (2,0)
*/
function Square(x, y, className) {
this.x = x*config.width;
this.y = y*config.height;
this.className = className;
this.contentDom = document.createElement('div');//該位置的方塊對應(yīng)的DOM元素
this.contentDom.className = this.className;
this.parent = document.getElementsByClassName("innerSnake")[0];
}
Square.prototype.create = function() { //創(chuàng)建方塊并添加到頁面
this.contentDom.style.position = 'absolute';
this.contentDom.style.width = config.width + 'px';
this.contentDom.style.height = config.height + 'px';
this.contentDom.style.left = this.x + 'px';
this.contentDom.style.top = this.y + 'px';
this.parent.appendChild(this.contentDom);
};
Square.prototype.remove = function() { //移除方塊
this.parent.removeChild(this.contentDom);
};
//蛇
function Snake() {
this.head = null; //蛇頭
this.tail = null; //蛇尾
this.pos = []; //二維數(shù)組,存儲蛇身上每個節(jié)點(diǎn)(方塊)
this.directionKey = { //存儲蛇走的方向
left: { //往左走
x: -1, //橫坐標(biāo)減1,一個坐標(biāo)表示一個格子
y: 0, //縱坐標(biāo)不變
rotate: 90
},
right: { //往右走
x: 1,
y: 0,
rotate: -90
},
up: { //往上走
x: 0,
y: -1,
rotate: 180
},
down: { //往下走
x: 0,
y: 1,
rotate: 0 //蛇頭圖片方向,順時針為正
}
}
}
Snake.prototype.init = function() { //初始化蛇
//蛇頭
var snakeHead = new Square(2,0,"head");
snakeHead.create(); //將蛇頭添加到界面
this.head = snakeHead; //存儲蛇頭信息
this.pos.push([2,0]); //存儲蛇頭坐標(biāo)
//蛇的第1節(jié)身體
var snakeBody1 = new Square(1,0,"body");
snakeBody1.create(); //將蛇的第一節(jié)身體添加到界面
this.pos.push([1,0]);
//蛇的尾巴
var snakeTail = new Square(0,0,"body");
snakeTail.create(); //將蛇尾添加到界面
this.tail = snakeTail; //存儲蛇尾信息
this.pos.push([0,0]);
//形成鏈表關(guān)系
snakeHead.prev = null; //蛇頭的前面沒有元素,指向null
snakeHead.next = snakeBody1; //蛇頭的后面有一節(jié)身體,其.next指針指向后面那節(jié)身體
snakeBody1.prev = snakeHead; //蛇的第一節(jié)身體,.prev指向前面的蛇頭snakeHead
snakeBody1.next = snakeTail; //蛇的第一節(jié)身體,.next指向后面的身體,此時是蛇尾snakeTail
snakeTail.prev = snakeBody1; //蛇尾,.prev指向前面的蛇身體snakeBody1
snakeTail.next = null; //蛇尾后面沒有元素,指向Null
//初始蛇的走向,后面想改變蛇的走向即改變this.direction
this.direction = this.directionKey.right; //默認(rèn)向右走
};
//獲取蛇頭下一個位置對應(yīng)的元素,根據(jù)元素做下一個動作
Snake.prototype.getNextPos = function() {
var nextPos = [ //獲取蛇頭走的下一個點(diǎn)的坐標(biāo)
this.head.x / config.width + this.direction.x,
this.head.y / config.height + this.direction.y
];
//判斷下一個點(diǎn)是自己or食物or圍墻or無障礙?
var self = false; //設(shè)置下一個點(diǎn)是否是自己
this.pos.forEach(function(val) { //val即二位數(shù)組中的一個坐標(biāo)
if(val.toString() === nextPos.toString()) { //下一個坐標(biāo)等于蛇全部身體的一個,即下一個點(diǎn)是自己
self = true;
}
});
if(self) {
// console.log('撞到自己了!');
this.collide.end.call(this); //game over
return;
} else if(nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > config.td-1 || nextPos[1] > config.tr-1) {
// console.log('撞到墻壁了!');
this.collide.end.call(this); //game over
return;
} else if (food && food.pos[0] === nextPos[0] && food.pos[1] === nextPos[1]) {
console.log('撞到食物了!');
this.collide.eat.call(this);
} else {
// console.log('啥都沒遇到!');
this.collide.move.call(this, false); //注意:.call(this)重新設(shè)置this指向,使其指向當(dāng)前實(shí)例對象Snake
}
};
//處理碰撞后的事件
Snake.prototype.collide = {
/*
碰到自己or墻壁,游戲結(jié)束end();
碰到食物,eat();
啥都沒遇到,move();
*/
move: function(isEat) { //isEat 是否吃了食物,不是則刪除蛇尾
/*
掐頭去尾:
create新蛇頭,remove舊蛇頭;
create一個新身體,放在(替代)舊蛇頭的位置;
remove蛇尾,蛇尾prev的元素變成新蛇尾
*/
var x = this.head.x / config.width + this.direction.x,
y = this.head.y / config.height + this.direction.y;
//聲明一個新身體
var newBody = new Square(this.head.x/config.width, this.head.y/config.height, "body");
//更新鏈表關(guān)系
newBody.next = this.head.next;
newBody.next.prev = newBody;
newBody.prev = null;
this.head.remove(); //刪除舊蛇頭
newBody.create(); //添加蛇身體,替代在舊蛇頭位置
//聲明一個新蛇頭(下一個走的點(diǎn))
var newHead = new Square(x, y, "head");
//更新鏈表關(guān)系
newHead.prev = null;
newHead.next = newBody;
newBody.prev = newHead;
this.pos.unshift([x, y]); //更新蛇節(jié)點(diǎn)的坐標(biāo)this.pos
this.head = newHead; //更新this.head的信息
newHead.contentDom.style.transform = `rotate(${this.direction.rotate}deg)`
newHead.create(); //添加蛇頭
//刪除蛇尾:吃食物則不刪
if(!isEat) { //沒有吃食物,刪除蛇尾
this.tail.remove();
this.tail = this.tail.prev;
this.pos.pop(); //更新蛇節(jié)點(diǎn)坐標(biāo)
}
// console.log(this.pos); //打印數(shù)組,驗(yàn)證
},
eat: function() {
this.collide.move.call(this, true); //傳參true,表示此時為吃操作
food.remove(); //刪除被吃掉的食物
game.score ++; //記錄分?jǐn)?shù)
createFood(); //此時再隨機(jī)產(chǎn)生一個食物
},
end: function() {
console.log('end');
game.gameOver();
}
}
snake = new Snake();
//創(chuàng)建食物
function createFood() {
var x = null, y = null;
var include = true; //表示食物的位置是否在蛇身上
var random = function(max, min) { //產(chǎn)生一個隨機(jī)數(shù)
return Math.floor(Math.random()*(max - min + 1))
};
while(include) {
x = random(config.tr - 1, 0);
y = random(config.td - 1, 0);
snake.pos.forEach(function(val) {
if(x != val[0] && y != val[1]) {
include = false;
}
});
}
//生成食物
food = new Square(x, y, "food");
food.pos = [x, y]; //記錄食物坐標(biāo)
food.create();
}
//游戲邏輯
function Game() {
this.score = 0; //分?jǐn)?shù)
this.timer = null; //計(jì)時器
}
Game.prototype.init = function() {
snake.init();
// snake.getNextPos(); //獲取下一個點(diǎn)坐標(biāo)
createFood();
document.onkeydown = function(event) {
if(event.which == 37 && snake.direction != snake.directionKey.right) {
//鼠標(biāo)左鍵,蛇不能是正在往右走
snake.direction = snake.directionKey.left;
} else if (event.which == 38 && snake.direction != snake.directionKey.down) {
//鼠標(biāo)上鍵
snake.direction = snake.directionKey.up;
} else if (event.which == 39 && snake.direction != snake.directionKey.left) {
//鼠標(biāo)右鍵
snake.direction = snake.directionKey.right;
} else if (event.which == 40 && snake.direction != snake.directionKey.up) {
//鼠標(biāo)下鍵
snake.direction = snake.directionKey.down;
}
}
this.start();
};
game = new Game();
//開始游戲
Game.prototype.start = function() {
this.timer = setInterval(function() {
snake.getNextPos(); //獲取下一個坐標(biāo)點(diǎn),做下一步動作
}, 200);
};
//游戲結(jié)束
Game.prototype.gameOver = function() {
console.log("gameOver");
clearInterval(this.timer);
var gameOver = document.querySelector('.gameOver');
var gameScore = document.querySelector('.gameOver .score');
gameOver.style.display = 'block'; //顯示游戲結(jié)束界面
gameScore.innerHTML = `${this.score}`; //將分?jǐn)?shù)記入該界面
};
//開啟游戲
function startGame() {
var startBtn = document.querySelector('.btn button');
var snakeWrap = document.querySelector('.snakeWrap');
startBtn.onclick = function() {
startBtn.parentNode.style.display = 'none'; //隱藏開始游戲界面
snakeWrap.style.display = 'block'; //顯示進(jìn)入游戲的界面
game.init();
}
}
startGame();
主要用到鏈表數(shù)據(jù)結(jié)構(gòu)
更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專題,也分享給大家:
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
淺析JavaScript中的特殊函數(shù)及用法小結(jié)
JavaScript中的函數(shù)本質(zhì)上是一個對象,我們可以將這個對象賦值給一個變量,這就使JavaScript中的函數(shù)變得非常的靈活,現(xiàn)在就來淺看一下JavaScript中函數(shù)的一些用法,需要的朋友可以參考下2022-06-06
關(guān)于__defineGetter__ 和__defineSetter__的說明
關(guān)于__defineGetter__ 和__defineSetter__的說明...2007-05-05
js中用window.open()打開多個窗口的name問題
這篇文章主要介紹了js中用window.open()打開多個窗口的問題,需要的朋友可以參考下2014-03-03
小程序如何寫動態(tài)標(biāo)簽的實(shí)現(xiàn)方法
這篇文章主要介紹了小程序如何寫動態(tài)標(biāo)簽的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-02-02
JavaScript組件焦點(diǎn)與頁內(nèi)錨點(diǎn)間傳值的方法
這篇文章主要介紹了JavaScript組件焦點(diǎn)與頁內(nèi)錨點(diǎn)間傳值的方法,涉及輸入框與錨點(diǎn)的操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02

