javascript實(shí)現(xiàn)貪吃蛇經(jīng)典游戲
js面向?qū)ο缶幊讨澇陨?,供大家參考,具體內(nèi)容如下
首先:面向?qū)ο缶幊?,我們要找到?xiàng)目中具體的對(duì)象,此處為(食物(food),蛇(snake),游戲本身(game))也可不把游戲本身作為對(duì)象,邏輯體現(xiàn)出來(lái)即可。
接著分析每個(gè)對(duì)象的具體的屬性及方法:
1)food 對(duì)象:屬性有:位置,大小,顏色;方法有:渲染在頁(yè)面,隨機(jī)不同位置生成;
2)snake對(duì)象:屬性有:位置,大小,總節(jié)數(shù)(計(jì)分方便),顏色;方法有:渲染在頁(yè)面,移動(dòng)(移動(dòng)過(guò)程中判斷其它)。
3)game對(duì)象:游戲邏輯的編寫(xiě);
ok 開(kāi)敲:
1)簡(jiǎn)單的靜態(tài)頁(yè)面編寫(xiě)(地圖)
(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(如果用邊框來(lái)作為限制的邊界,那么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ì)象編寫(xiě)(細(xì)節(jié)處含注釋)
//cwen加載頁(yè)面所有元素 window.addEventListener('load', function() { //cwen自調(diào)用函數(shù),開(kāi)啟一個(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() { //為了刪除干凈,從索引最大的開(kāi)始循環(huán)刪除 for (var i = elements.length - 1; i >= 0; i--) { //刪除遍歷到的div elements[i].parentNode.removeChild(elements[i]); //刪除數(shù)組中的元素1)第幾個(gè)開(kāi)始,2)要?jiǎng)h除個(gè)數(shù) elements.splice(i, 1); } } //把Food開(kāi)放出去 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ì)象編寫(xiě)()
window.addEventListener('load', function() { (function() { //記錄蛇的每一節(jié) var elements = []; //cwen立即執(zhí)行函數(shù),開(kāi)啟新的作用于,避免命名沖突 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ì)象編寫(xiě),其中一個(gè)為無(wú)敵版(含細(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.游戲邏輯編寫(xiě) //讓蛇動(dòng)起來(lái) //判斷地圖邊界 // runSnake(); //todo判斷玩法(兩種模式,原理一樣) goInput(); //通過(guò)鍵盤(pán)控制蛇頭方向 //! keydown(); //蛇頭碰到食物時(shí)處理 //在snake.js中判斷 } function goInput() { var it = prompt('try:\n 經(jīng)典玩法請(qǐng)按1\n 無(wú)敵玩法請(qǐng)輸入(博主最帥)\n') if (it == 1) { runSnake(); keydown(); } else if (it == '博主最帥') { runSnake1(); keydown1(); } else { alert('you input could not be found!!!'); goInput(); } } //讓蛇動(dòng)起來(lái) 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) } //無(wú)敵版本蛇運(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) } //通過(guò)鍵盤(pán)控制蛇頭方向 function keydown() { document.addEventListener('keydown', function(e) { //通過(guò)事件對(duì)象判斷按了哪個(gè)鍵 37left,38top,39right,40bottom // console.log(e.keyCode); //其在走的同時(shí)按下反方向無(wú)用 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) { //通過(guò)事件對(duì)象判斷按了哪個(gè)鍵 37left,38top,39right,40bottom // console.log(e.keyCode); //無(wú)敵版本四面八方任你行 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開(kāi)放 window.Game = Game; })() })
5)main開(kāi)啟游戲
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文件寫(xiě)在同一個(gè)js文件中,可以大大提高加載速度。注意在每個(gè)立即執(zhí)行函數(shù)前加上‘ ;',以免出錯(cuò)。
小編還為大家準(zhǔn)備了精彩的專題:javascript經(jīng)典小游戲匯總
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
javascript鼠標(biāo)滑動(dòng)評(píng)分控件完整實(shí)例
這篇文章主要介紹了javascript鼠標(biāo)滑動(dòng)評(píng)分控件實(shí)現(xiàn)方法,以完整實(shí)例形式詳細(xì)分析了javascript操作鼠標(biāo)事件及頁(yè)面元素樣式實(shí)現(xiàn)評(píng)分效果的方法,需要的朋友可以參考下2015-05-05JavaScript省市區(qū)三級(jí)聯(lián)動(dòng)菜單效果
這篇文章主要為大家詳細(xì)介紹了JavaScript省市區(qū)三級(jí)聯(lián)動(dòng)菜單效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09jsonp跨域及實(shí)現(xiàn)百度首頁(yè)聯(lián)想功能的方法
這篇文章主要介紹了jsonp跨域及實(shí)現(xiàn)百度首頁(yè)聯(lián)想功能的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08IE和Firefox的Javascript兼容性總結(jié)[推薦收藏]
長(zhǎng)久以來(lái)JavaScript兼容性一直是Web開(kāi)發(fā)者的一個(gè)主要問(wèn)題。在正式規(guī)范、事實(shí)標(biāo)準(zhǔn)以及各種實(shí)現(xiàn)之間的存在的差異讓許多開(kāi)發(fā)者日夜煎熬2011-10-10JScript中的"this"關(guān)鍵字使用方式補(bǔ)充材料
JScript中的"this"關(guān)鍵字使用方式補(bǔ)充材料...2007-03-03JavaScript之json_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了JavaScript之json,JSON它是一種數(shù)據(jù)交換格式。有興趣的可以了解一下2017-06-06js點(diǎn)擊按鈕實(shí)現(xiàn)帶遮罩層的彈出視頻效果
這篇文章主要介紹了js點(diǎn)擊按鈕實(shí)現(xiàn)帶遮罩層的彈出視頻效果,需要的朋友可以參考下2015-12-12js將URL網(wǎng)址轉(zhuǎn)為16進(jìn)制加密與解密函數(shù)
這篇文章主要介紹了js將URL網(wǎng)址轉(zhuǎn)為16進(jìn)制加密與解密函數(shù),很多朋友喜歡將網(wǎng)址轉(zhuǎn)換為16進(jìn)制,網(wǎng)上實(shí)在找不到轉(zhuǎn)換為\x這樣的工具,于是手工改一下2020-03-03