需求剖析
天生輿圖。
- 將運用籠統成一個對象。
- 輿圖運用一個二維數組作為構造。
天生食品。
- 天生食品的局限。
- 食品不能和身材天生位置重合。
天生蛇,最先挪動。
- 蛇遇到牆壁,計算出穿過牆的局限.
- 蛇遇到本身的身材,Game Over .
- 蛇吃到食品,長度加一,並天生新的食品
監聽鍵盤事宜。
- 對上下左右挪動做出迴響反映。
代碼完成(也能夠檢察 github )
html (index.html)
<!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>
<link rel="stylesheet" href="./style/index.css">
</head>
<body>
<div class="wrap">
<div id="container">
</div>
</div>
<script src="./js/index.js" ></script>
</body>
</html>
css (./style/index.css)
* {
margin: 0;
padding: 0;
}
.wrap{
display: flex;
justify-content: center;
align-content: center;
}
#container{
width: 100%;
text-align: center;
}
#container div{
/* width: 20px;
height: 20px; */
float: left;
border: 1px solid #000;
}
js(./js/index.js)
(function(self){
function GreedySnake(gridXN,gridYN){
// 輿圖
this.gridXN = gridXN >= 10 ? gridXN : 10;
this.gridYN = gridYN >= 10 ? gridYN : 10;
this.gridSize = 20; //每一個格子的牢固大小
this.map = []; //保留輿圖中dom對象的二維數組
this.container = document.getElementById('container');
// 食品屬性
this.food = null;
this.foodX = null;
this.foodY = null;
// 蛇
this.snake = [];//將蛇籠統成一個二維列表,列為身材長度,排為坐標數組
this.snakeLen = null ; //默許蛇長為3
// 初始蛇頭坐標
this.snakeHead = []
// 蛇的挪動方向
this.direction = 'top'
// 速率
this.speed = 1 ;
this.timer = null
}
GreedySnake.prototype.init = function(){
this.initMap();
this.createSnake();
this.createFood();
this.snakeMove()
this.listenKeyBoardEvents()
}
GreedySnake.prototype.restart = function(gridXN,gridYN){
// 輿圖
this.gridXN = null
this.gridYN = null
this.gridSize = null
this.map = null
this.container = null
// 食品屬性
this.food = null;
this.foodX = null;
this.foodY = null;
// 蛇
this.snake = null;
this.snakeLen = null;
// 初始蛇頭坐標
this.snakeHead = null;
// 蛇的挪動方向
this.direction = null;
// 速率
this.speed = null;
}
// 初始化輿圖
GreedySnake.prototype.initMap = function(){
var gridYN = this.gridYN,
gridXN = this.gridXN,
w = gridXN * this.gridSize + gridXN + 1 ,
h = gridYN * this.gridSize + gridYN + 1;
this.container.style.width = w + "px";
this.container.style.height = h + 'px';
for(let y = 0 ; y < gridXN ; y++){
this.map[y] = [] //初始化二維數組
for(let x = 0 ; x < gridYN ; x++){
this.createGrid(x,y)
}
}
}
// 建立每一個格子,x軸格子索引,y軸格子索引
GreedySnake.prototype.createGrid = function(idxX,idxY){
// 當idxY > 0 時,對應的grid的向左挪動1px,將格子之間的線重合;
// 當idxX > 0 時,對應的grid的向上挪動1px,將格子之間的線重合;
let grid = document.createElement('div');
grid.style.width = this.gridSize + 'px';
grid.style.height = this.gridSize + "px";
this.map[idxY][idxX] = grid
if(idxX > 0 ){
grid.style.marginLeft = '-1px';
}
if(idxY > 0 ){
grid.style.marginTop = '-1px';
}
this.container.appendChild(grid);
}
// 建立食品:道理就是依據在局限內的格子數,天生兩個隨機數,作為元素的坐標
GreedySnake.prototype.createFood = function(){
var gridYN = this.gridYN,
gridXN = this.gridXN,
temp = null ,
flag = true;
this.foodX = Math.floor(Math.random() * gridXN); //緩存
this.foodY = Math.floor(Math.random() * gridYN);
for(var i = 0 ; i<this.snake.length ; i++){
temp = this.snake[i]
// 檢測食品是不是和蛇的身材重合
while(temp[0] == this.foodY && temp[1] == this.foodX){
flag = false
this.createFood();
}
}
if(flag){
this.food = this.map[this.foodY][this.foodX];
this.food.style.backgroundColor = '#f00';
}
}
// 天生蛇
GreedySnake.prototype.createSnake = function(){
this.snakeLen = 3 ; //默許蛇長為3
let i = this.snakeLen - 1;
for(i ; i >= 0; i--){
this.snake.push([this.gridYN - 1 - i ,this.gridXN - 1 - 3])
this.map[this.gridYN - 1 - i][this.gridXN - 1 - 3].style.backgroundColor = 'blue'
}
// 初始蛇頭坐標
this.snakeHead = this.snake[0]
// console.log(this.snake)
}
// 最先挪動,挪動后蛇頭坐標 +-1
GreedySnake.prototype.snakeMove = function(){
let _this = this,
sH = this.snakeHead,
y = null,
x = null,
tempH = null,
last = null,
alive = true
function common(){
_this.map[tempH[0]][tempH[1]].style.backgroundColor = 'blue'
_this.snake.unshift(tempH);
_this.snakeHead = tempH;
// 檢測蛇頭是不是和蛇的身材相撞
for(var i = 1 ; i < _this.snake.length;i++){
if(_this.snakeHead[0] == _this.snake[i][0] && _this.snakeHead[1] == _this.snake[i][2]){
alert('GAME OVER');
alive = false
return false
}
}
// 當蛇吃到食品后再從新建立食品
if(sH[0] === _this.foodY && sH[1] === _this.foodX){
_this.createFood()
return false
}
last = _this.snake.pop();
_this.map[last[0]][last[1]].style.backgroundColor = ''
}
switch(this.direction){
case 'top':
y = sH[0] //緩存
tempH = [--y , sH[1] ];
if(tempH[0] < 0){
tempH = [this.gridYN - 1 , sH[1]]
}
common();
break;
case 'bottom':
y = sH[0]
tempH = [++y , sH[1] ];
// 邊境推斷
if(tempH[0] > this.gridYN - 1){
tempH = [ 0 , sH[1]]
}
common()
break;
case 'left':
x = sH[1]
tempH = [sH[0] , --x ];
if(tempH[1] < 0){
tempH = [ sH[0] , this.gridXN - 1]
}
common()
break;
case 'right':
x = sH[1]
tempH = [sH[0] , ++x ];
if(tempH[1] > this.gridXN - 1){
tempH = [ sH[0] , 0 ]
}
common()
break;
}
alive && setTimeout(function(){
_this.snakeMove()
},500 / this.speed)
}
// 註冊鍵盤事宜
GreedySnake.prototype.listenKeyBoardEvents = function(){
let _this = this
self.onkeyup = function(e){
let dir = _this.direction
switch(e.keyCode){
case 37:
if(dir != 'right'){
_this.direction = 'left';
}
break;
case 38:
if(dir != 'bottom'){
_this.direction = 'top';
}
break;
case 39:
if(dir != 'left'){
_this.direction = 'right';
}
break;
case 40:
if(dir != 'top'){
_this.direction = 'bottom';
}
break;
}
}
}
GreedySnake.prototype.print = function(){
return this.map
}
// 參數寄義:x軸,y軸上的格子數目
var greedySnake = new GreedySnake(20,20);
greedySnake.init()
})(window)