javascript實(shí)現(xiàn)貪吃蛇經(jīng)典游戲
js面向?qū)ο缶幊讨澇陨?,供大家參考,具體內(nèi)容如下
首先:面向?qū)ο缶幊蹋覀円业巾?xiàng)目中具體的對(duì)象,此處為(食物(food),蛇(snake),游戲本身(game))也可不把游戲本身作為對(duì)象,邏輯體現(xiàn)出來即可。
接著分析每個(gè)對(duì)象的具體的屬性及方法:
1)food 對(duì)象:屬性有:位置,大小,顏色;方法有:渲染在頁(yè)面,隨機(jī)不同位置生成;
2)snake對(duì)象:屬性有:位置,大小,總節(jié)數(shù)(計(jì)分方便),顏色;方法有:渲染在頁(yè)面,移動(dòng)(移動(dòng)過程中判斷其它)。
3)game對(duì)象:游戲邏輯的編寫;
ok 開敲:
1)簡(jiǎn)單的靜態(tài)頁(yè)面編寫(地圖)
(1)html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" href="css/index.css" > <script src="js/food.js"></script> <script src="js/snake.js"></script> <script src="js/game.js"></script> <script src="js/main.js"></script> <title>貪吃蛇</title> </head> <body> <div class="map"></div> </body> </html>
(2)css(如果用邊框來作為限制的邊界,那么box-sizing屬性是必不可少的(以免食物和蛇頭坐標(biāo)之間存在誤差))
* {
margin: 0;
padding: 0;
}
.map {
position: relative;
height: 600px;
width: 800px;
border: 1px solid #333;
margin: 0 auto;
/* 盒子模型去除邊框 */
box-sizing: border-box;
}
2)food對(duì)象編寫(細(xì)節(jié)處含注釋)
//cwen加載頁(yè)面所有元素
window.addEventListener('load', function() {
//cwen自調(diào)用函數(shù),開啟一個(gè)新的作用域,避免命名沖突
(function() {
//cwen定義全局變量
//實(shí)物數(shù)組
var elements = [];
//cwen實(shí)物
function Food(options) {
options = options || {};
this.x = options.x || 0;
this.y = options.y || 0;
this.width = options.width || 20;
this.height = options.height || 20;
this.color = options.color || 'yellow';
}
//cwen隨機(jī)數(shù)函數(shù)
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
//cwen渲染
Food.prototype.render = function(map) {
//刪除之前的食物
remove();
//todo動(dòng)態(tài)創(chuàng)建div實(shí)物
var div = document.createElement('div');
map.appendChild(div);
//把div添加給數(shù)組
elements.push(div);
//todo隨機(jī)設(shè)置x,y的值(實(shí)物的位置)-----在map中生成隨機(jī)位置
// ! 值 = Math.floor(Math.random() * 可能值得總數(shù) + 第一個(gè)可能的值)
this.x = getRandom(0, map.offsetWidth / this.width - 1) * this.width;
this.y = getRandom(0, map.offsetHeight / this.height - 1) * this.height;
div.style.position = 'absolute';
div.style.left = this.x + 'px';
div.style.top = this.y + 'px';
div.style.width = this.width + 'px';
div.style.height = this.height + 'px';
div.style.backgroundColor = this.color;
}
function remove() {
//為了刪除干凈,從索引最大的開始循環(huán)刪除
for (var i = elements.length - 1; i >= 0; i--) {
//刪除遍歷到的div
elements[i].parentNode.removeChild(elements[i]);
//刪除數(shù)組中的元素1)第幾個(gè)開始,2)要?jiǎng)h除個(gè)數(shù)
elements.splice(i, 1);
}
}
//把Food開放出去
window.Food = Food;
})()
//cwen測(cè)試
// var map = document.querySelector('.map');
// var options = { x: 20, y: 20, width: 30, height: 30, color: 'green' };
// //todo不傳值默認(rèn)為自定義food
// var food = new Food();
// food.render(map);
})
3)snake對(duì)象編寫()
window.addEventListener('load', function() {
(function() {
//記錄蛇的每一節(jié)
var elements = [];
//cwen立即執(zhí)行函數(shù),開啟新的作用于,避免命名沖突
function Snake(options) {
options = options || {};
//對(duì)象(蛇)每節(jié)的大小
this.width = options.width || 20;
this.height = options.height || 20;
//cwen蛇的總節(jié)數(shù)(計(jì)分)
this.mark = options.mark || 0;
//對(duì)象的移動(dòng)方向
this.direction = options.direction || 'right';
//對(duì)象的身體(蛇節(jié))
this.kont = [{ x: 3, y: 2, color: 'red' }, { x: 2, y: 2, color: 'black' }, { x: 1, y: 2, color: 'black' }];
}
//cwen渲染對(duì)象
Snake.prototype.render = function(map) {
//移除之前的蛇
remove();
//循環(huán)輸出對(duì)象的身體(蛇節(jié))
for (var i = 0, len = this.kont.length; i < len; i++) {
var obj = this.kont[i];
var div = document.createElement('div');
map.appendChild(div);
//將蛇節(jié)添加入數(shù)組
elements.push(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;
}
}
//cwen控制蛇移動(dòng)的方法
//todo傳參food,map 在game中調(diào)用move方法也要傳入相應(yīng)參數(shù)
Snake.prototype.move = function(food, map) {
//控制蛇節(jié)的移動(dòng)(當(dāng)前蛇節(jié)到下一個(gè)蛇節(jié)的位置)
for (var i = this.kont.length - 1; i > 0; i--) {
this.kont[i].x = this.kont[i - 1].x;
this.kont[i].y = this.kont[i - 1].y;
}
//判斷并控制蛇頭移動(dòng),判斷蛇頭移動(dòng)方向
var head = this.kont[0];
switch (this.direction) {
case 'right':
head.x += 1;
break;
case 'left':
head.x -= 1;
break;
case 'top':
head.y -= 1;
break;
case 'bottom':
head.y += 1;
break;
}
//蛇頭碰到食物時(shí)處理
// cwen判斷蛇頭是否和食物坐標(biāo)重合
var headX = head.x * this.width;
var headY = head.y * this.height;
if (headX == food.x && headY == food.y) {
//1,增加蛇節(jié)(找到最后一根蛇節(jié),然后添加給創(chuàng)建的蛇數(shù)組)
var last = this.kont[this.kont.length - 1];
this.kont.push({ x: last.x, y: last.y, color: last.color });
//cwen求出蛇節(jié)的總個(gè)數(shù)(計(jì)分)
var mark = this.mark++;
//2,重新渲染食物
food.render(map);
}
}
//刪除之前的蛇
function remove() {
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].parentNode.removeChild(elements[i]);
elements.splice(i, 1);
}
}
//把Snake構(gòu)造函數(shù)暴露出去
window.Snake = Snake;
})()
//測(cè)試
// var map = document.querySelector('.map');
// var snake = new Snake();
// snake.render(map);
})
4)game對(duì)象編寫,其中一個(gè)為無敵版(含細(xì)節(jié)注釋)
window.addEventListener('load', function() {
(function() {
//改變計(jì)時(shí)器內(nèi)this指向
var that;
function Game(map) {
// var options = { x: 20, y: 20, width: 30, height: 30, color: 'green' };
this.food = new Food();
this.snake = new Snake();
this.map = map;
that = this;
}
//cwen渲染
Game.prototype.start = function() {
// 1.把食物和蛇渲染到頁(yè)面
this.food.render(this.map);
this.snake.render(this.map);
// 2.游戲邏輯編寫
//讓蛇動(dòng)起來
//判斷地圖邊界
// runSnake();
//todo判斷玩法(兩種模式,原理一樣)
goInput();
//通過鍵盤控制蛇頭方向
//! keydown();
//蛇頭碰到食物時(shí)處理
//在snake.js中判斷
}
function goInput() {
var it = prompt('try:\n 經(jīng)典玩法請(qǐng)按1\n 無敵玩法請(qǐng)輸入(博主最帥)\n')
if (it == 1) {
runSnake();
keydown();
} else if (it == '博主最帥') {
runSnake1();
keydown1();
} else {
alert('you input could not be found!!!');
goInput();
}
}
//讓蛇動(dòng)起來
function runSnake() {
var timeId = setInterval(function() {
// var a = mark;
that.snake.move(that.food, that.map);
that.snake.render(that.map);
//判斷地圖邊界
var maxX = (that.map.offsetWidth) / that.snake.width;
var maxY = (that.map.offsetHeight) / that.snake.height;
var headX = that.snake.kont[0].x;
var headY = that.snake.kont[0].y;
if (headX < 0 || headX >= maxX) {
alert('Game Over ' + '得分為 ' + that.snake.mark);
clearInterval(timeId);
} else if (headY < 0 || headY >= maxY) {
alert('Game Over ' + '成績(jī)?yōu)?' + that.snake.mark);
clearInterval(timeId);
}
}, 150)
}
//無敵版本蛇運(yùn)動(dòng)
function runSnake1() {
var timeId1 = setInterval(function() {
that.snake.move(that.food, that.map);
that.snake.render(that.map);
//判斷地圖邊界
var maxX = (that.map.offsetWidth - that.snake.width) / that.snake.width;
var maxY = (that.map.offsetHeight - that.snake.height) / that.snake.height;
var headX = that.snake.kont[0].x;
var headY = that.snake.kont[0].y;
if (headX < 0) {
that.snake.kont[0].x = (that.map.offsetWidth - that.snake.width) / that.snake.width;
} else if (headX > maxX) {
that.snake.kont[0].x = 0;
} else if (headY < 0) {
that.snake.kont[0].y = (that.map.offsetHeight - that.snake.height) / that.snake.height;
} else if (headY > maxY) {
that.snake.kont[0].y = 0;
}
}, 50)
}
//通過鍵盤控制蛇頭方向
function keydown() {
document.addEventListener('keydown', function(e) {
//通過事件對(duì)象判斷按了哪個(gè)鍵 37left,38top,39right,40bottom
// console.log(e.keyCode);
//其在走的同時(shí)按下反方向無用
if (e.keyCode == 37 && that.snake.direction != 'right') {
that.snake.direction = 'left';
} else if (e.keyCode == 38 && that.snake.direction != 'bottom') {
that.snake.direction = 'top';
} else if (e.keyCode == 39 && that.snake.direction != 'left') {
that.snake.direction = 'right';
} else if (e.keyCode == 40 && that.snake.direction != 'top') {
that.snake.direction = 'bottom';
}
});
}
function keydown1() {
document.addEventListener('keydown', function(e) {
//通過事件對(duì)象判斷按了哪個(gè)鍵 37left,38top,39right,40bottom
// console.log(e.keyCode);
//無敵版本四面八方任你行
if (e.keyCode == 37) {
that.snake.direction = 'left';
} else if (e.keyCode == 38) {
that.snake.direction = 'top';
} else if (e.keyCode == 39) {
that.snake.direction = 'right';
} else if (e.keyCode == 40) {
that.snake.direction = 'bottom';
}
});
}
//把Game開放
window.Game = Game;
})()
})
5)main開啟游戲
window.addEventListener('load', function() {
(function(window, undefind) {
//測(cè)試
var map = document.querySelector('.map');
var game = new Game(map);
game.start();
})(window, undefined)
})
last but not least
*建議把所有js文件寫在同一個(gè)js文件中,可以大大提高加載速度。注意在每個(gè)立即執(zhí)行函數(shù)前加上‘ ;',以免出錯(cuò)。
小編還為大家準(zhǔn)備了精彩的專題:javascript經(jīng)典小游戲匯總
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
微信小程序結(jié)合Storage實(shí)現(xiàn)搜索歷史效果
這篇文章主要為大家詳細(xì)介紹了微信小程序結(jié)合Storage實(shí)現(xiàn)搜索歷史效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-05-05
JSON格式的時(shí)間/Date(2367828670431)/格式轉(zhuǎn)為正常的年-月-日 格式的代碼
這篇文章主要介紹了JSON格式的時(shí)間/Date(2367828670431)/格式轉(zhuǎn)為正常的年-月-日 格式的代碼的相關(guān)資料,需要的朋友可以參考下2016-07-07
用jquery.sortElements實(shí)現(xiàn)table排序
實(shí)現(xiàn)table排序,網(wǎng)上有很多解決方案,很多都基于jQuery,最后我選擇用sortElements,實(shí)現(xiàn)很簡(jiǎn)單2014-05-05
JavaScript實(shí)現(xiàn)的簡(jiǎn)單拖拽效果
這篇文章主要介紹了JavaScript實(shí)現(xiàn)的簡(jiǎn)單拖拽效果,涉及javascript針對(duì)鼠標(biāo)事件與頁(yè)面樣式的操作技巧,需要的朋友可以參考下2015-06-06
uni-app禁用返回按鈕/返回鍵的具體實(shí)現(xiàn)
今天在使用uni-app開發(fā)登錄頁(yè)面時(shí)遇到一個(gè)需求,需要禁用返回按鈕,下面這篇文章主要給大家介紹了關(guān)于uni-app禁用返回按鈕/返回鍵的具體實(shí)現(xiàn),需要的朋友可以參考下2022-11-11
JS 各種網(wǎng)頁(yè)尺寸判斷實(shí)例方法
JS 各種網(wǎng)頁(yè)尺寸判斷實(shí)例方法,需要的朋友可以參考一下2013-04-04
讓你的網(wǎng)站可編輯的實(shí)現(xiàn)js代碼
可以讓你編輯瀏覽器中看到網(wǎng)頁(yè)可編輯的實(shí)現(xiàn)代碼。2009-10-10

