趁着周末,再赶一篇。这篇是关于贪吃蛇的。贪吃蛇的移动算法改了好几次,一开始出现了很搞笑的移动轨迹,调整了几次,总算是能够正常的爬了。
首先,还是说一下总体的思路。
1.游戏开始,生成游戏区,同样是个二维数组--m,我用的是20*20的。随机挑选坐标生成小蛇,用head对象记录蛇头,用tail对象记录蛇尾坐标(我设定的开局时蛇头蛇尾时同一个点),并把这个点放进记录蛇身的snake数组中。在界面中展示就是0。
2.生成食物。nullBox数组用来记录空白区域,即数组m中去掉数组snake中保存的坐标。其实就是数组m中值为0的坐标。然后在nullBox中随机找一个点,这个点就是新食物所在坐标。界面展示时我用的‘*’代替食物。//startPoint var rx = Math.floor(Math.random() *this.x), ry = Math.floor(Math.random() *this.y), rb = $('.box[x='+ rx + '][y='+ ry +']'); this.head.hx = rx; this.head.hy = ry; this.tail.tx = rx; this.tail.ty = ry; this.m[rx][ry] = 1; rb.text('0'); this.snake.push([rx,ry]);
3.监听方向变化。初始四个方向up,down,left,right都为false。当用户按下方向键时,改变方向状态。this.createFood = function () { this.nullBox = []; for(var i = 0;i < this.x;i++){ for(var j = 0;j < this.y;j++){ if(this.m[i][j] == 0){ this.nullBox.push([i,j]); } } } if(this.nullBox.length > 0){ var f = Math.floor(Math.random() *this.nullBox.length); this.food.fx = this.nullBox[f][0]; this.food.fy = this.nullBox[f][1]; } }
4.移动。移动我设置了个定时器,每隔0.5秒去检查移动方向的变化。show函数就是用来渲染界面的。window.addEventListener('keydown',function (e) { switch (e.which){ case 37: _this.left = true; _this.up = false; _this.right = false; _this.down = false; break; case 38: _this.left = false; _this.up = true; _this.right = false; _this.down = false; break; case 39: _this.left = false; _this.up = false; _this.right = true; _this.down = false; break; case 40: _this.left = false; _this.up = false; _this.right = false; _this.down = true; break; } })
5.具体的某个方向移动。以右移为例。第一步检查是否可移动。右移,所以检查蛇头的下一个坐标,也就是(head.hx,head.hy+1)是否还在游戏区,如果不在,就结束,清除定时器;如果还在游戏区,就向右移动。移动有两种情况:①下一个点是食物,则把食物点添加到snake数组的首位,更新蛇头坐标(head.hx,head.hy),生成新食物点。②下一个点不是食物,更新蛇头蛇尾坐标,更新snake数组。this.move = setInterval(function () { if(_this.up){ _this.moveUp(); }else if(_this.down){ _this.moveDown(); }else if(_this.left){ _this.moveLeft(); }else if(_this.right){ _this.moveRight(); } _this.show(); },500)
this.moveRight = function () { if(_this.goOn(_this.head.hx,_this.head.hy+1)){ if(_this.stepForward(_this.head.hx,_this.head.hy+1)){ } }else { _this.gameOver(); } }
this.goOn = function (i,j) { if(i >= 0 && i < _this.x && j >= 0 && j < _this.y && this.m[i][j] == 0){ return true; } return false; }this.stepForward = function (i,j) { if(i == _this.food.fx && j == _this.food.fy){ //eat _this.snake.unshift([i,j]); _this.m[i][j] = 1; _this.head.hx = i; _this.head.hy = j; _this.createFood(); }else{ //step _this.snake.unshift([i,j]); var len = _this.snake.length; var empty = _this.snake[len-1]; _this.snake.pop(); _this.m[empty[0]][empty[1]] = 0; _this.head.hx = _this.snake[0][0]; _this.head.hy = _this.snake[0][1]; _this.m[_this.head.hx][_this.head.hy] = 1; } }基本上就是这样了。谢谢大家的观看,欢迎提出宝贵意见。
最后还是附上所有代码吧,也可以访问我的GitHub:
JS:
/** * Created by PC on 2017/12/7. */ $(function () { var start = true; window.addEventListener('keydown',function () { if(start){ var game = new Game(); game.start(); start = false; } }) }) var Game = function () { this.x = 20; this.y = 20; this.m = []; this.snake = []; this.head = { hx : 0, hy : 0 } this.tail = { tx : 0, ty : 0 } //direction this.up = false; this.down = false; this.left = false; this.right = false; this.food = { fx : 0, fy : 0 } this.nullBox = []; _this = this; this.start = function () { this.createBox(); this.createFood(); window.addEventListener('keydown',function (e) { switch (e.which){ case 37: _this.left = true; _this.up = false; _this.right = false; _this.down = false; break; case 38: _this.left = false; _this.up = true; _this.right = false; _this.down = false; break; case 39: _this.left = false; _this.up = false; _this.right = true; _this.down = false; break; case 40: _this.left = false; _this.up = false; _this.right = false; _this.down = true; break; } }) this.move; } this.createBox = function () { for(var i = 0;i < this.x;i++){ this.m[i] = []; for(var j = 0;j < this.y;j++){ this.m[i][j] = 0; var box = "<div class='box' x='"+ i +"' y='"+ j +"'></div>"; $('#container').append(box); } $('#container').append("<br>") } //startPoint var rx = Math.floor(Math.random() *this.x), ry = Math.floor(Math.random() *this.y), rb = $('.box[x='+ rx + '][y='+ ry +']'); this.head.hx = rx; this.head.hy = ry; this.tail.tx = rx; this.tail.ty = ry; this.m[rx][ry] = 1; rb.text('0'); this.snake.push([rx,ry]); } this.createFood = function () { this.nullBox = []; for(var i = 0;i < this.x;i++){ for(var j = 0;j < this.y;j++){ if(this.m[i][j] == 0){ this.nullBox.push([i,j]); } } } if(this.nullBox.length > 0){ var f = Math.floor(Math.random() *this.nullBox.length); this.food.fx = this.nullBox[f][0]; this.food.fy = this.nullBox[f][1]; } } this.move = setInterval(function () { if(_this.up){ _this.moveUp(); }else if(_this.down){ _this.moveDown(); }else if(_this.left){ _this.moveLeft(); }else if(_this.right){ _this.moveRight(); } _this.show(); },500) this.moveUp = function () { if(_this.goOn(_this.head.hx-1,_this.head.hy)){ if(_this.stepForward(_this.head.hx-1,_this.head.hy)){ } }else { _this.gameOver(); } } this.moveDown = function () { if(_this.goOn(_this.head.hx+1,_this.head.hy)){ if(_this.stepForward(_this.head.hx+1,_this.head.hy)){ } }else { _this.gameOver(); } } this.moveLeft = function () { if(_this.goOn(_this.head.hx,_this.head.hy-1)){ if(_this.stepForward(_this.head.hx,_this.head.hy-1)){ } }else { _this.gameOver(); } } this.moveRight = function () { if(_this.goOn(_this.head.hx,_this.head.hy+1)){ if(_this.stepForward(_this.head.hx,_this.head.hy+1)){ } }else { _this.gameOver(); } } this.stepForward = function (i,j) { if(i == _this.food.fx && j == _this.food.fy){ //eat _this.snake.unshift([i,j]); _this.m[i][j] = 1; _this.head.hx = i; _this.head.hy = j; _this.createFood(); }else{ //step _this.snake.unshift([i,j]); var len = _this.snake.length; var empty = _this.snake[len-1]; _this.snake.pop(); _this.m[empty[0]][empty[1]] = 0; _this.head.hx = _this.snake[0][0]; _this.head.hy = _this.snake[0][1]; _this.m[_this.head.hx][_this.head.hy] = 1; // _this.tail.tx = _this.snake[len-1][0]; // _this.tail.ty = _this.snake[len-1][1]; // _this.m[_this.tail.tx][_this.tail.ty] = 1; } } this.goOn = function (i,j) { if(i >= 0 && i < _this.x && j >= 0 && j < _this.y && this.m[i][j] == 0){ return true; } return false; } this.gameOver = function () { alert('Over'); clearInterval(_this.move); } this.show = function () { for(var i = 0;i < this.x;i++){ for(var j = 0;j < this.y;j++){ if(this.m[i][j] != 0){ $('.box[x='+ i +'][y='+ j +']').text('0'); }else { $('.box[x='+ i +'][y='+ j +']').text(''); } } } var fx = this.food.fx, fy = this.food.fy; $('.box[x='+ fx +'][y='+ fy +']').text('*'); } }
html:<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Game-snake</title> <style> .box { display: inline-block; width: 40px; height: 40px; line-height: 40px; border: 1px solid #fff; background: #eee; cursor: pointer; text-align: center; vertical-align: middle; } </style> </head> <body style="text-align:center"> <div style="margin: 10px;"> <div id="container"></div> </div> <script src="jquery.min.js"></script> <script src="snake.js"></script> </body> </html>