JavaScript 精美貪吃蛇實現(xiàn)流程
這篇文章不簡單??!
今天博主嘔心瀝血寫了一個貪吃蛇的小游戲,整個過程從無到有簡直扣人心弦。
接下來本博主就來好好說到說到這個過程??!
話不多說,我們還是先來看看最后的呈現(xiàn)效果吧。

看完了才知道什么叫做操作,簡直傳奇?。?/p>
接下來不吹牛來講講實際操作 !
首先我們要知道所謂的貪吃蛇無非就是在表格上面行走的顏色!最初的效果也就是如下圖所示

當然在這個地方是用數(shù)組來操作的,也是用構造函數(shù)來封裝的。

在這個地方封裝了三個 js 文件,分別用來寫 食物、蛇、還有我們的中介者 Game.js 文件!
我剛剛也說了,寫貪吃蛇是一個從無到有的過程,所以最開始在我們的 index.html 里面什么都沒有,就只有一個 div 盒子,其他的表格、蛇、食物都是后期用函數(shù)創(chuàng)建的。
一、創(chuàng)建html結構
以下是我們 body 里面最開始的代碼:
<body>
<div id="app">
</div>
<script src="js/Snake.js"></script>
<script src="js/Food.js"></script>
<script src="js/Game.js"></script>
<script>
var game=new Game();
</script>
</body>
二、創(chuàng)建表格
從無到有第一步,當然是先把我們的表格追加到頁面上,得有一個大體的框架??!這樣就能看到剛剛上面圖中所示的表格了,看到這仿佛就覺得接下來的每一步都是值得的!
function Game() {
this.row = 25; // 行數(shù)
this.col = 25; // 列數(shù)
this.init(); //初始化節(jié)點
}
Game.prototype.init = function () {
this.dom = document.createElement('table'); // 創(chuàng)建表格
var tr, td;
// 遍歷行和列
for (var i = 0; i < this.row; i++) {
tr = document.createElement('tr'); // 創(chuàng)建行
for (var j = 0; j < this.col; j++) {
td = document.createElement('td'); // 創(chuàng)建列
tr.appendChild(td); // 把列追加到行
}
this.dom.appendChild(tr); // 把行追加到表格
}
document.querySelector('#app').appendChild(this.dom); //把表格追加到div里
}
三、創(chuàng)建蛇頭、蛇身
從無到有第二步,蛇頭蛇頭蛇頭、蛇身蛇身蛇身!看到這覺得學到知道是多么重要的環(huán)節(jié)。
function Snake() {
// 蛇的初始化身體
this.body = [
{ 'row': 3, 'col': 5 },
{ 'row': 3, 'col': 4 },
{ 'row': 3, 'col': 3 },
{ 'row': 3, 'col': 2 }
];
}
Snake.prototype.render = function () {
// 蛇頭的渲染
game.setColorHead(this.body[0].row, this.body[0].col);
// 蛇身的渲染
for (var i = 1; i < this.body.length; i++) {
game.setColor(this.body[i].row, this.body[i].col, '#649c49')
}
}
Snake 里面調用 中介者 Game 原型對象里面的屬性!
Game.prototype.setColor = function (row, col, color) {
this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.background = color;
}
四、創(chuàng)建食物
從無到有第三步,食物食物食物! 看到這,我們的基本形態(tài)就算是全都有了!
function Food(gameSnake) {
var self = this;
// 下面的 do-while 循環(huán)語句作用是先創(chuàng)建一個 row 和 col 然后判斷這個 row 和 col 是否在蛇的身上
do {
// 食物的位置
this.row = parseInt(Math.random() * gameSnake.row)
this.col = parseInt(Math.random() * gameSnake.col)
} while ((function () {
// 遍歷蛇的 row col 然后和 food 新隨機出來的 row col 進行判斷,是否重合
for (var i = 0; i < gameSnake.snake.body.length; i++) {
if (self.row == gameSnake.snake.body[i].row && self.col == gameSnake.snake.body[i].col) {
return true;
}
}
return false;
})());
}
Food.prototype.render = function () {
game.setHTML(this.row, this.col);
}
五、讓蛇動起來
從無到有第四步,動起來動起來動起來!這里用數(shù)組的頭增尾刪簡直就是天作之合!
// 蛇的運動
Snake.prototype.update = function () {
this.direction = this.willDirection;
switch (this.direction) {
case 'R': //右
this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col + 1 });
break;
case 'D': //下
this.body.unshift({ 'row': this.body[0].row + 1, 'col': this.body[0].col });
break;
case 'L': //左
this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col - 1 });
break;
case 'U': //上
this.body.unshift({ 'row': this.body[0].row - 1, 'col': this.body[0].col });
break;
}
// 死亡的判斷,超出了表格邊緣的部分
if (this.body[0].col > game.col - 1 || this.body[0].col < 0 || this.body[0].row > game.row - 1 || this.body[0].row < 0) {
alert('撞到墻了哦,一共吃掉了' + game.score + '顆草莓');
this.body.shift();
clearInterval(game.timer);
location.reload();
}
// 自己撞到自己的時候會判定死亡
for (var i = 1; i < this.body.length; i++) {
// 如果當前蛇的頭部和身體的某一個部位的 row 和 col 完全重合的時候
if (this.body[0].row == this.body[i].row && this.body[0].col == this.body[i].col) {
alert('撞到自己了,吃掉了' + game.score + '顆草莓');
this.body.shift();
clearInterval(game.timer);
location.reload();
}
}
// 蛇吃食物
// 判斷如果當前的蛇的頭部沒有和食物進行重合,就代表此時沒有吃到食物,此時就進行尾部刪除,如果重合了就代表遲到了,此時我們不進行刪除尾部
if (this.body[0].row == game.food.row && this.body[0].col == game.food.col) {
// 此時情況是只有頭部增加了,尾部沒有刪除
game.food = new Food(game); //創(chuàng)建新的食物
game.score++;
game.f = 0;
} else {
this.body.pop(); //刪除數(shù)組最后一個元素
}
}
六、控制蛇的方向
從無到有第五步,蛇的方向! 做到這里,回望過去的每一步,都是浮云?。?/p>
// 蛇的方向改變,防止的是在一次渲染之前會出現(xiàn)調頭的情況
Snake.prototype.changeDirection = function (d) {
this.willDirection = d;
}
// 設置鍵盤的事件監(jiān)聽
Game.prototype.bindEvent = function () {
var self = this;
document.addEventListener('keydown', function (e) {
// 用ASCII碼值判斷鍵盤方向
switch (e.keyCode) {
case 37: //左
if (self.snake.direction == 'R') return; // 先進行判斷,如果當前的方向是向右移動,此時我們不能按左鍵
self.snake.changeDirection('L');
self.d = 'L';
break;
case 38: //上
if (self.snake.direction == 'D') return; // 先進行判斷,如果當前的方向是向下移動,此時我們不能按上鍵
self.snake.changeDirection('U');
self.d = 'U';
break;
case 39: //右
if (self.snake.direction == 'L') return; // 先進行判斷,如果當前的方向是向左移動,此時我們不能按右鍵
self.snake.changeDirection('R');
self.d = 'R';
break;
case 40: //下
if (self.snake.direction == 'U') return; // 先進行判斷,如果當前的方向是向上移動,此時我們不能按下鍵
self.snake.changeDirection('D');
self.d = 'D';
break;
}
})
}
最后按照我們喜歡的樣子設置樣式就好啦,這里我按我自己喜歡粉色設置相應的顏色以及插入我喜換的食物的樣子??!
七、完整代碼
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>貪吃蛇</title>
<style>
* {
padding: 0;
margin: 0;
}
#app {
position: relative;
border: 20px solid #f8bbd0;
background-color: #fce4ec;
width: 500px;
height: 500px;
margin: 15px auto;
}
table {
border-collapse: collapse;
background-color: #fce4ec;
}
td {
position: relative;
background-size: 100% 100%;
border-radius: 50%;
width: 20px;
height: 20px;
text-align: center;
/* background-color: #fce4ec; */
/* border: 1px solid #aaa; */
}
td .snake {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.start,
.suspend {
cursor: pointer;
position: absolute;
width: 150px;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.suspend {
display: none;
z-index: 2;
}
</style>
</head>
<body>
<!-- <h3 id="f">幀編號:0</h3>
<h3 id="score">分數(shù):0</h3> -->
<div id="app">
<img src="images/start.gif" alt="" class="start">
<img src="images/suspended.png" alt="" class="suspend">
</div>
<!-- <script src="js/last.js"></script> -->
<script src="js/Snake.js"></script>
<script src="js/Food.js"></script>
<script src="js/Game.js"></script>
<script>
var game = null;
var flag = true;
var suspend = document.querySelector('.suspend');
document.querySelector('.start').addEventListener('click', function () {
// document.querySelector('#app').style.backgroundColor='white';
this.style.display = 'none';
game = new Game();
document.querySelector('table').addEventListener('click', function () {
clearInterval(game.timer);
suspend.style.display = 'block';
})
suspend.addEventListener('click', function () {
suspend.style.display = 'none';
game.timer = setInterval(function () {
game.f++;
// document.getElementById('f').innerHTML = '幀編號:' + game.f;
// document.getElementById('score').innerHTML = '分數(shù):' + game.score;
// 清屏
game.clear();
// 蛇的運動(更新)
// 蛇的更新速度,當蛇變長的時候,速度要加快
var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
game.f % during == 0 && game.snake.update();
// game.snake.update();
// 渲染蛇
game.snake.render();
// 渲染食物
game.food.render();
}, 10)
})
})
</script>
</body>
</html>
Game.js
function Game() {
this.row = 25; // 行數(shù)
this.col = 25; // 列數(shù)
this.score = 0; //分數(shù)
this.init(); //初始化節(jié)點
this.snake = new Snake(); //實例化蛇類
this.food = new Food(this); //初始化食物
// this.last = new Last();
this.start(); //執(zhí)行定時器任務
this.bindEvent(); //鍵盤的事件監(jiān)聽
this.d = 'R';
}
Game.prototype.init = function () {
this.dom = document.createElement('table'); // 創(chuàng)建表格
var tr, td;
// 遍歷行和列
for (var i = 0; i < this.row; i++) {
tr = document.createElement('tr'); // 創(chuàng)建行
for (var j = 0; j < this.col; j++) {
td = document.createElement('td'); // 創(chuàng)建列
tr.appendChild(td); // 把列追加到行
}
this.dom.appendChild(tr); // 把行追加到表格
}
document.querySelector('#app').appendChild(this.dom); //把表格追加到div里
}
// 遍歷表格,清除表格上的顏色
Game.prototype.clear = function () {
for (var i = 0; i < this.row; i++) {
for (var j = 0; j < this.col; j++) {
this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].style.background = '';
this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].innerHTML = '';
}
}
}
// 設置顏色的方法 讓表格的第幾行,第幾列設置什么顏色
Game.prototype.setColor = function (row, col, color) {
this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.background = color;
}
// 設置蛇頭
Game.prototype.setColorHead = function (row, col) {
var img = document.createElement('img');
img.src = 'images/snake.png';
img.className = 'snake';
this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].appendChild(img);
// this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundColor='transparent'
switch (this.d) {
case 'R': //右
break;
case 'D': //下
img.style.transform = 'rotate(90deg)';
break;
case 'L': //左
img.style.transform = 'rotate(180deg)';
break;
case 'U': //上
img.style.transform = 'rotate(-90deg)';
break;
}
}
// 渲染食物
Game.prototype.setHTML = function (row, col) {
this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundImage = 'url(./images/food.png)';
}
// 設置鍵盤的事件監(jiān)聽
Game.prototype.bindEvent = function () {
var self = this;
document.addEventListener('keydown', function (e) {
// 用ASCII碼值判斷鍵盤方向
switch (e.keyCode) {
case 37: //左
if (self.snake.direction == 'R') return; // 先進行判斷,如果當前的方向是向右移動,此時我們不能按左鍵
self.snake.changeDirection('L');
self.d = 'L';
break;
case 38: //上
if (self.snake.direction == 'D') return; // 先進行判斷,如果當前的方向是向下移動,此時我們不能按上鍵
self.snake.changeDirection('U');
self.d = 'U';
break;
case 39: //右
if (self.snake.direction == 'L') return; // 先進行判斷,如果當前的方向是向左移動,此時我們不能按右鍵
self.snake.changeDirection('R');
self.d = 'R';
break;
case 40: //下
if (self.snake.direction == 'U') return; // 先進行判斷,如果當前的方向是向上移動,此時我們不能按下鍵
self.snake.changeDirection('D');
self.d = 'D';
break;
}
})
}
Game.prototype.start = function () {
// 幀編號
this.f = 0;
// 定時器里面的核心就是游戲的渲染本質:清屏-更新-渲染
this.timer = setInterval(function () {
game.f++;
// document.getElementById('f').innerHTML = '幀編號:' + game.f;
// document.getElementById('score').innerHTML = '分數(shù):' + game.score;
// 清屏
game.clear();
// 蛇的運動(更新)
// 蛇的更新速度,當蛇變長的時候,速度要加快
var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
game.f % during == 0 && game.snake.update();
// game.snake.update();
// 渲染蛇
game.snake.render();
// 渲染食物
game.food.render();
}, 10)
}
Snake.js
function Snake() {
// 蛇的初始化身體
this.body = [
{ 'row': 3, 'col': 5 },
{ 'row': 3, 'col': 4 },
{ 'row': 3, 'col': 3 },
{ 'row': 3, 'col': 2 }
];
this.direction = 'R'; //信號量,設置運動方向
this.willDirection = 'R'; //即將改變的方向,目的就是為了方向出現(xiàn)原地調頭的情況
}
Snake.prototype.render = function () {
// 蛇頭的渲染
game.setColorHead(this.body[0].row, this.body[0].col);
// 蛇身的渲染
for (var i = 1; i < this.body.length; i++) {
game.setColor(this.body[i].row, this.body[i].col, '#649c49')
}
}
// 蛇的運動
Snake.prototype.update = function () {
this.direction = this.willDirection;
switch (this.direction) {
case 'R': //右
this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col + 1 });
break;
case 'D': //下
this.body.unshift({ 'row': this.body[0].row + 1, 'col': this.body[0].col });
break;
case 'L': //左
this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col - 1 });
break;
case 'U': //上
this.body.unshift({ 'row': this.body[0].row - 1, 'col': this.body[0].col });
break;
}
// 死亡的判斷,超出了表格邊緣的部分
if (this.body[0].col > game.col - 1 || this.body[0].col < 0 || this.body[0].row > game.row - 1 || this.body[0].row < 0) {
alert('撞到墻了哦,一共吃掉了' + game.score + '顆草莓');
this.body.shift();
clearInterval(game.timer);
location.reload();
}
// 自己撞到自己的時候會判定死亡
for (var i = 1; i < this.body.length; i++) {
// 如果當前蛇的頭部和身體的某一個部位的 row 和 col 完全重合的時候
if (this.body[0].row == this.body[i].row && this.body[0].col == this.body[i].col) {
alert('撞到自己了,吃掉了' + game.score + '顆草莓');
this.body.shift();
clearInterval(game.timer);
location.reload();
}
}
// 蛇吃食物
// 判斷如果當前的蛇的頭部沒有和食物進行重合,就代表此時沒有吃到食物,此時就進行尾部刪除,如果重合了就代表遲到了,此時我們不進行刪除尾部
if (this.body[0].row == game.food.row && this.body[0].col == game.food.col) {
// 此時情況是只有頭部增加了,尾部沒有刪除
game.food = new Food(game); //創(chuàng)建新的食物
game.score++;
game.f = 0;
} else {
this.body.pop(); //刪除數(shù)組最后一個元素
}
}
// 蛇的方向改變,防止的是在一次渲染之前會出現(xiàn)調頭的情況
Snake.prototype.changeDirection = function (d) {
this.willDirection = d;
}
Food.js
function Food(gameSnake) {
var self = this;
// 下面的 do-while 循環(huán)語句作用是先創(chuàng)建一個 row 和 col 然后判斷這個 row 和 col 是否在蛇的身上
do {
// 食物的位置
this.row = parseInt(Math.random() * gameSnake.row)
this.col = parseInt(Math.random() * gameSnake.col)
} while ((function () {
// 遍歷蛇的 row col 然后和 food 新隨機出來的 row col 進行判斷,是否重合
for (var i = 0; i < gameSnake.snake.body.length; i++) {
if (self.row == gameSnake.snake.body[i].row && self.col == gameSnake.snake.body[i].col) {
return true;
}
}
return false;
})());
}
Food.prototype.render = function () {
game.setHTML(this.row, this.col);
}
八、圖片
接下里我把我用的圖片放到這個地方,喜歡的寶寶們也可以直接拿去用!




九、總結
看到最后的朋友們有沒有覺得其實還是很簡單的!感興趣的趕緊去試試叭!!

到此這篇關于JavaScript 精美貪吃蛇實現(xiàn)流程的文章就介紹到這了,更多相關JavaScript 貪吃蛇內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
childNodes.length與children.length的區(qū)別
childNodes.length與children.length的值常不一樣。2009-05-05

