0


JavaScript制作贪吃蛇小游戏

写了这么久的代码

是否你和我一样感到枯燥乏味了呢?

是否没有前进的动力了呢?

别忘了当时的你踌躇满志将前端Web一举拿下的斗志啊!

今天博主要给大家展现一个好玩的游戏

贪吃蛇小游戏!

嘿,你可别小瞧这东西!

制作过程是从无到有

等做完它

你就能从中体会到比玩游戏还快乐的居然是打代码!


效果展示

原理分析

我们制作前为了代码更清晰就分成几个js文档来编写。

其中Game.js可以看作是一个媒介的作用;Snake.js是当蛇初始化时在最左边向右走的状态;

贪吃蛇在游戏中的运动可以想象成这条蛇是在一张25*25的表格中运动:

如图所示

Game.js文档

📝所以我们在Game.js中添加表格节点

  1. function Game() {
  2. this.row = 25;
  3. this.col = 25;
  4. }
  5. Game.prototype.init = function() {
  6. this.dom = document.createElement('table');
  7. // 创建表格--父元素为document(页面中创建表格)
  8. // var tr, td;
  9. for (var i = 0; i < this.row; i++) { //追加行
  10. var tr = document.createElement('tr');
  11. for (var j = 0; j < this.td; j++) { //追加列
  12. var td = document.createElement('col');
  13. td.appendChild(tr);
  14. }
  15. }
  16. };

Snake.js文档

📝Snake.js中当蛇初始化时最左边向右走的状态

如图所示

  1. function Snake() {
  2. // 蛇的初始化身体
  3. this.body = [
  4. { 'row': 3, 'col': 5 },
  5. { 'row': 3, 'col': 4 },
  6. { 'row': 3, 'col': 3 },
  7. { 'row': 3, 'col': 2 }
  8. ];
  9. }
  10. Snake.prototype.render = function() {
  11. // 蛇头的渲染
  12. game.setColorHead(this.body[0].row, this.body[0].col.'pink');
  13. // 蛇身的渲染
  14. for (var i = 1; i < this.body.length; i++) {
  15. game.setColor(this.body[i].row, this.body[i].col, 'cyan')
  16. }
  17. }

蛇在运动的时候它的原理是“头增尾删”。

因为蛇的长度先是不变的,而我们改变的也是改变这个四个格子的颜色,走一格头部那一格颜色变为粉色,尾巴那一格的颜色变为白色。

✨接下来让蛇通过我们按键来进行运动:放在一个监听事件内

  1. // 设置键盘的事件监听
  2. Game.prototype.bindEvent = function() {
  3. var self = this;
  4. document.addEventListener('keydown', function(e) {
  5. // 用ASCII码值判断键盘方向
  6. switch (e.keyCode) {
  7. case 37: //左
  8. if (self.snake.direction == 'R') return; // 先进行判断,如果当前的方向是向右移动,此时我们不能按左键
  9. self.snake.changeDirection('L');
  10. self.d = 'L';
  11. break;
  12. case 38: //上
  13. if (self.snake.direction == 'D') return; // 先进行判断,如果当前的方向是向下移动,此时我们不能按上键
  14. self.snake.changeDirection('U');
  15. self.d = 'U';
  16. break;
  17. case 39: //右
  18. if (self.snake.direction == 'L') return; // 先进行判断,如果当前的方向是向左移动,此时我们不能按右键
  19. self.snake.changeDirection('R');
  20. self.d = 'R';
  21. break;
  22. case 40: //下
  23. if (self.snake.direction == 'U') return; // 先进行判断,如果当前的方向是向上移动,此时我们不能按下键
  24. self.snake.changeDirection('D');
  25. self.d = 'D';
  26. break;
  27. }
  28. })
  29. }

✨接下来我们判定蛇是否撞到墙而结束

  1. // 死亡的判断,超出了表格边缘的部分
  2. 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) {
  3. alert('撞到墙了哦,一共吃掉了' + game.score + '颗草莓');
  4. this.body.shift();
  5. clearInterval(game.timer);
  6. location.reload();
  7. }

✨接下来我们判定蛇是否撞到自己而结束

  1. // 自己撞到自己的时候会判定死亡
  2. for (var i = 1; i < this.body.length; i++) {
  3. // 如果当前蛇的头部和身体的某一个部位的 row 和 col 完全重合的时候
  4. if (this.body[0].row == this.body[i].row && this.body[0].col == this.body[i].col) {
  5. alert('撞到自己了,吃掉了' + game.score + '颗草莓');
  6. this.body.shift();
  7. clearInterval(game.timer);
  8. location.reload();
  9. }
  10. }

Food.js文档

📝食物food类,用来产生食物

  1. function Food(gameSnake) {
  2. // 食物的位置
  3. this.row = parseInt(Math.random() * gameSnake.row)
  4. this.col = parseInt(Math.random() * gameSnake.col)
  5. }
  6. Food.prototype.render = function() {
  7. game.setHTML(this.row, this.col);
  8. }

✨食物随机生成在单元格中,利用do...while来实现

  1. function Food(gameSnake) {
  2. var self = this;
  3. // 下面的 do-while 循环语句作用是先创建一个 row 和 col
  4. 然后判断这个 row col 是否在蛇的身上
  5. //do...while来创建食物
  6. do {
  7. // 食物的位置
  8. this.row = parseInt(Math.random() * gameSnake.row)
  9. this.col = parseInt(Math.random() * gameSnake.col)
  10. } while ((function() {
  11. // 遍历蛇的 row col 然后和 food 新随机出来的 row col 进行判断,是否重合
  12. for (var i = 0; i < gameSnake.snake.body.length; i++) {
  13. if (self.row == gameSnake.snake.body[i].row && self.col == gameSnake.snake.body[i].col) {
  14. return true;
  15. }
  16. }
  17. return false;
  18. })());
  19. }

附上源代码

index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>贪吃蛇</title>
  8. <style>
  9. * {
  10. padding: 0;
  11. margin: 0;
  12. }
  13. #app {
  14. position: relative;
  15. border: 20px solid #f8bbd0;
  16. background-color: #fce4ec;
  17. width: 500px;
  18. height: 500px;
  19. margin: 15px auto;
  20. }
  21. table {
  22. border-collapse: collapse;
  23. background-color: #fce4ec;
  24. }
  25. td {
  26. position: relative;
  27. background-size: 100% 100%;
  28. border-radius: 50%;
  29. width: 20px;
  30. height: 20px;
  31. text-align: center;
  32. /* background-color: #fce4ec; */
  33. /* border: 1px solid #aaa; */
  34. }
  35. td .snake {
  36. position: absolute;
  37. top: 0;
  38. left: 0;
  39. width: 100%;
  40. height: 100%;
  41. }
  42. .start,
  43. .suspend {
  44. cursor: pointer;
  45. position: absolute;
  46. width: 150px;
  47. top: 50%;
  48. left: 50%;
  49. transform: translate(-50%, -50%);
  50. }
  51. .suspend {
  52. display: none;
  53. z-index: 2;
  54. }
  55. </style>
  56. </head>
  57. <body>
  58. <!-- <h3 id="f">帧编号:0</h3>
  59. <h3 id="score">分数:0</h3> -->
  60. <div id="app">
  61. <img src="img/start.gif" alt="" class="start">
  62. <img src="img/stop.png" alt="" class="suspend">
  63. </div>
  64. <!-- <script src="js/last.js"></script> -->
  65. <script src="Snake.js"></script>
  66. <script src="Food.js"></script>
  67. <script src="Game.js"></script>
  68. <script>
  69. var game = null;
  70. var flag = true;
  71. var suspend = document.querySelector('.suspend');
  72. document.querySelector('.start').addEventListener('click', function() {
  73. // document.querySelector('#app').style.backgroundColor='white';
  74. this.style.display = 'none';
  75. game = new Game();
  76. document.querySelector('table').addEventListener('click', function() {
  77. clearInterval(game.timer);
  78. suspend.style.display = 'block';
  79. })
  80. suspend.addEventListener('click', function() {
  81. suspend.style.display = 'none';
  82. game.timer = setInterval(function() {
  83. game.f++;
  84. // document.getElementById('f').innerHTML = '帧编号:' + game.f;
  85. // document.getElementById('score').innerHTML = '分数:' + game.score;
  86. // 清屏
  87. game.clear();
  88. // 蛇的运动(更新)
  89. // 蛇的更新速度,当蛇变长的时候,速度要加快
  90. var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
  91. game.f % during == 0 && game.snake.update();
  92. // game.snake.update();
  93. // 渲染蛇
  94. game.snake.render();
  95. // 渲染食物
  96. game.food.render();
  97. }, 10)
  98. })
  99. })
  100. </script>
  101. </body>
  102. </html>

Game.js

  1. function Game() {
  2. this.row = 25; // 行数
  3. this.col = 25; // 列数
  4. this.score = 0; //分数
  5. this.init(); //初始化节点
  6. this.snake = new Snake(); //实例化蛇类--绑定到Game()中 原型链来找
  7. this.food = new Food(this); //初始化食物
  8. // this.last = new Last();
  9. this.start(); //执行定时器任务
  10. this.bindEvent(); //键盘的事件监听
  11. this.d = 'R';
  12. }
  13. //创建对象Game 里面写上它的属性(特征)↑
  14. Game.prototype.init = function() {
  15. this.dom = document.createElement('table');
  16. // 创建表格--父元素为document(页面中创建表格)
  17. var tr, td;
  18. // 遍历行和列
  19. for (var i = 0; i < this.row; i++) {
  20. tr = document.createElement('tr'); // 创建行
  21. for (var j = 0; j < this.col; j++) {
  22. td = document.createElement('td'); // 创建列
  23. tr.appendChild(td); // 把列追加到行
  24. }
  25. this.dom.appendChild(tr); // 把行追加到表格
  26. }
  27. document.querySelector('#app').appendChild(this.dom); //把表格追加到div里
  28. }
  29. // 遍历表格,清除表格上的颜色(画布上不停的渲染)
  30. Game.prototype.clear = function() {
  31. for (var i = 0; i < this.row; i++) {
  32. for (var j = 0; j < this.col; j++) {
  33. this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].style.background = '';
  34. this.dom.getElementsByTagName('tr')[i].getElementsByTagName('td')[j].innerHTML = '';
  35. }
  36. }
  37. }
  38. // 设置颜色的方法 让表格的第几行,第几列设置什么颜色
  39. Game.prototype.setColor = function(row, col, color) {
  40. this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.background = color;
  41. }
  42. // 设置蛇头
  43. Game.prototype.setColorHead = function(row, col) {
  44. var img = document.createElement('img');
  45. img.src = 'img/head.png';
  46. img.className = 'snake';
  47. this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].appendChild(img);
  48. // this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundColor='transparent'
  49. switch (this.d) {
  50. case 'R': //右
  51. break;
  52. case 'D': //下
  53. img.style.transform = 'rotate(90deg)';
  54. break;
  55. case 'L': //左
  56. img.style.transform = 'rotate(180deg)';
  57. break;
  58. case 'U': //上
  59. img.style.transform = 'rotate(-90deg)';
  60. break;
  61. }
  62. }
  63. // 渲染食物
  64. Game.prototype.setHTML = function(row, col) {
  65. this.dom.getElementsByTagName('tr')[row].getElementsByTagName('td')[col].style.backgroundImage = 'url(./img/food.png)';
  66. }
  67. // 设置键盘的事件监听
  68. Game.prototype.bindEvent = function() {
  69. var self = this;
  70. document.addEventListener('keydown', function(e) {
  71. // 用ASCII码值判断键盘方向
  72. switch (e.keyCode) {
  73. case 37: //左
  74. if (self.snake.direction == 'R') return; // 先进行判断,如果当前的方向是向右移动,此时我们不能按左键
  75. self.snake.changeDirection('L');
  76. self.d = 'L';
  77. break;
  78. case 38: //上
  79. if (self.snake.direction == 'D') return; // 先进行判断,如果当前的方向是向下移动,此时我们不能按上键
  80. self.snake.changeDirection('U');
  81. self.d = 'U';
  82. break;
  83. case 39: //右
  84. if (self.snake.direction == 'L') return; // 先进行判断,如果当前的方向是向左移动,此时我们不能按右键
  85. self.snake.changeDirection('R');
  86. self.d = 'R';
  87. break;
  88. case 40: //下
  89. if (self.snake.direction == 'U') return; // 先进行判断,如果当前的方向是向上移动,此时我们不能按下键
  90. self.snake.changeDirection('D');
  91. self.d = 'D';
  92. break;
  93. }
  94. })
  95. }
  96. Game.prototype.start = function() {
  97. // 帧编号
  98. this.f = 0;
  99. // 定时器里面的核心就是游戏的渲染本质:清屏-更新-渲染
  100. this.timer = setInterval(function() {
  101. game.f++;
  102. // document.getElementById('f').innerHTML = '帧编号:' + game.f;
  103. // document.getElementById('score').innerHTML = '分数:' + game.score;
  104. // 清屏
  105. game.clear();
  106. // 蛇的运动(更新)
  107. // 蛇的更新速度,当蛇变长的时候,速度要加快
  108. var during = game.snake.body.length < 30 ? 30 - game.snake.body.length : 1;
  109. game.f % during == 0 && game.snake.update();
  110. // game.snake.update();
  111. // 渲染蛇
  112. game.snake.render();
  113. // 渲染食物
  114. game.food.render();
  115. }, 10)
  116. }

Snake.js

  1. function Snake() {
  2. // 蛇的初始化身体
  3. this.body = [
  4. { 'row': 3, 'col': 5 },
  5. { 'row': 3, 'col': 4 },
  6. { 'row': 3, 'col': 3 },
  7. { 'row': 3, 'col': 2 }
  8. ];
  9. this.direction = 'R'; //信号量,设置运动方向
  10. this.willDirection = 'R'; //即将改变的方向,目的就是为了方向出现原地调头的情况
  11. }
  12. Snake.prototype.render = function() {
  13. // 蛇头的渲染
  14. game.setColorHead(this.body[0].row, this.body[0].col);
  15. // 蛇身的渲染
  16. for (var i = 1; i < this.body.length; i++) {
  17. game.setColor(this.body[i].row, this.body[i].col, '#649c49')
  18. }
  19. }
  20. // 蛇的运动
  21. Snake.prototype.update = function() {
  22. this.direction = this.willDirection;
  23. switch (this.direction) {
  24. case 'R': //右
  25. this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col + 1 });
  26. break;
  27. case 'D': //下
  28. this.body.unshift({ 'row': this.body[0].row + 1, 'col': this.body[0].col });
  29. break;
  30. case 'L': //左
  31. this.body.unshift({ 'row': this.body[0].row, 'col': this.body[0].col - 1 });
  32. break;
  33. case 'U': //上
  34. this.body.unshift({ 'row': this.body[0].row - 1, 'col': this.body[0].col });
  35. break;
  36. }
  37. // 死亡的判断,超出了表格边缘的部分
  38. 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) {
  39. alert('撞到墙了哦,一共吃掉了' + game.score + '颗草莓');
  40. this.body.shift();
  41. // 删除时因为当前的头增时不合法的,因此游戏已经结束了
  42. clearInterval(game.timer);
  43. location.reload();
  44. }
  45. // 自己撞到自己的时候会判定死亡
  46. for (var i = 1; i < this.body.length; i++) {
  47. // 如果当前蛇的头部和身体的某一个部位的 row 和 col 完全重合的时候
  48. if (this.body[0].row == this.body[i].row && this.body[0].col == this.body[i].col) {
  49. alert('撞到自己了,吃掉了' + game.score + '颗草莓');
  50. this.body.shift();
  51. clearInterval(game.timer);
  52. location.reload();
  53. }
  54. }
  55. // 蛇吃食物
  56. // 判断如果当前的蛇的头部没有和食物进行重合,就代表此时没有吃到食物,此时就进行尾部删除,如果重合了就代表迟到了,此时我们不进行删除尾部
  57. // 判断蛇身体的长度=食物的长度
  58. if (this.body[0].row == game.food.row && this.body[0].col == game.food.col) {
  59. // 此时情况是只有头部增加了,尾部没有删除
  60. game.food = new Food(game); //创建新的食物
  61. game.score++;
  62. game.f = 0;
  63. } else {
  64. this.body.pop(); //删除数组最后一个元素
  65. }
  66. }
  67. // 蛇的方向改变,防止的是在一次渲染之前会出现调头的情况
  68. Snake.prototype.changeDirection = function(d) {
  69. this.willDirection = d;
  70. }

Food.js

  1. function Food(gameSnake) {
  2. var self = this;
  3. // 下面的 do-while 循环语句作用是先创建一个 row 和 col 然后判断这个 row 和 col 是否在蛇的身上
  4. //do...while来创建食物
  5. do {
  6. // 食物的位置
  7. this.row = parseInt(Math.random() * gameSnake.row)
  8. this.col = parseInt(Math.random() * gameSnake.col)
  9. } while ((function() {
  10. // 遍历蛇的 row col 然后和 food 新随机出来的 row col 进行判断,是否重合
  11. for (var i = 0; i < gameSnake.snake.body.length; i++) {
  12. if (self.row == gameSnake.snake.body[i].row && self.col == gameSnake.snake.body[i].col) {
  13. return true;
  14. }
  15. }
  16. return false;
  17. })());
  18. }
  19. Food.prototype.render = function() {
  20. game.setHTML(this.row, this.col);
  21. }

本文转载自: https://blog.csdn.net/m0_60264901/article/details/122277887
版权归原作者 实习期小潘 所有, 如有侵权,请联系我们删除。

“JavaScript制作贪吃蛇小游戏”的评论:

还没有评论