项目需求

  1. 设计地图
    • 设计高度和宽度
    • 地图由一个个原子组成(原子就是小的div)
    • 可以设计X轴有n个原子,Y轴n个原子
    • 显示画布的功能
  2. 创造食物
    • 食物的宽度和高度等于原子的大小
    • 功能:在地图上显示食物
  3. 蛇本体
    • 设置头、体、尾(至少三个原子)
    • 高度和宽度为原子的大小
    • 功能:
      1. 持续运动
      2. 键盘控制方向
      3. 遇到边界,游戏结束,重新开始
      4. 遇到事物,增加一个原子的大小
      5. 自己碰到自己,游戏结束,重新开始
  4. 规则
    1. 蛇可以升级,定义一个级别号
    2. 每升一级,速度加快
    3. 定义升级条件,随着等级提高,升级难度加大

业务流程:
创建每一个对象,相关使用对象
开始暂停功能

项目开发

阶段一: (制作背景)

  1. 1. 创建一个定时器,并绑定给开始游戏和暂停游戏z
  2. 1. 制作背景地图,选择是否显示格子
  3. 1. 代码见 -> [阶段一开发代码](https://www.yuque.com/u12581613/sr444s/euf28o?view=doc_embed)

阶段二:(基础内容)

  1. 1. 构造一个食物对象,并且会在地图中随机生成食物
  2. 1. 构造蛇对象,先初始化蛇的头、体、尾
  3. 1. 键盘控制方向,让蛇自由运动
  4. 1. 代码见 -> [阶段二开发代码](https://www.yuque.com/u12581613/sr444s/swqzg7?view=doc_embed)

阶段三:(控制规则)

  1. 1. 控制蛇吃掉食物会自己变长
  2. 1. 判断蛇撞墙和咬到自己,游戏结束
  3. 1. 增加游戏难度(如关数,速度...)
  4. 1. 美化网页(可自选)
  5. 1. 代码见下方,此项目完成

完整代码

  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. box-sizing: border-box;
  13. }
  14. body{
  15. background: url("img/bj.jpg") 0 no-repeat;
  16. background-size: cover;
  17. background-attachment: fixed;
  18. position: absolute;
  19. left: 0;
  20. top: 0;
  21. width: 100%;
  22. height: 100%;
  23. }
  24. #main{
  25. margin: 100px;
  26. }
  27. .btn{
  28. width: 100px;
  29. height: 40px;
  30. /* margin: 10px; */
  31. }
  32. .canvas{
  33. position: relative;
  34. top: 40px;
  35. border: 1px solid rgb(107, 221, 178);
  36. background-color: rgb(218, 236, 245);
  37. /* background-color: rgb(0, 0, 0); */
  38. }
  39. .gtitle{
  40. font-size: 25px;
  41. font-weight: bold;
  42. margin: 10px;
  43. padding:10px;
  44. }
  45. #gnum{
  46. color: red;
  47. }
  48. </style>
  49. </head>
  50. <body>
  51. <div id="main">
  52. <h1>贪吃蛇</h1>
  53. <input class="btn" type="button" value="开始游戏" id="begin"/>
  54. <input class="btn" type="button" value="暂停游戏" id="pause"/>
  55. <span class="gtitle"><span id="gnum">1</span></span>
  56. <script>
  57. var timer; //变量可以提升
  58. var showCanvas = false; //是否显示格子
  59. /*设置地图的构造方法:
  60. atom为原子初始化的宽高(应该一致)
  61. xnum为地图x轴应该有多少个原子(横向)
  62. ynum为地图y轴应该有多少个原子(纵向)
  63. */
  64. function Map(atom,xnum,ynum){
  65. this.atom = atom;
  66. this.xnum = xnum;
  67. this.ynum = ynum;
  68. this.canvas = null; //初始化画布
  69. this.create = function(){
  70. this.canvas = document.createElement("div");
  71. this.canvas.className = "canvas";
  72. this.canvas.style.width = this.atom * this.xnum + "px"; //画布的宽
  73. this.canvas.style.height = this.atom * this.ynum + "px"; //画布的高
  74. main.appendChild(this.canvas);
  75. //判断是否需要显示格子
  76. if (showCanvas){
  77. for (var i = 0;i<xnum;i++){
  78. for (var j = 0;j<ynum;j++){
  79. //定义格子的样式
  80. var lattice = document.createElement("div");
  81. lattice.style.border = "1px solid rgb(107, 221, 178)";
  82. lattice.style.width = this.atom + "px";
  83. lattice.style.height = this.atom + "px";
  84. //添加格子到地图中
  85. this.canvas.appendChild(lattice);
  86. lattice.style.position = "absolute";
  87. //利用绝对定位
  88. lattice.style.left = i * this.atom + "px";
  89. lattice.style.top = j * this.atom + "px";
  90. }
  91. }
  92. }
  93. }
  94. }
  95. //创建食物的构造方法
  96. function Food(map){
  97. this.width = map.atom;
  98. this.height = map.atom;
  99. this.bgcolor = "rgb(" + Math.floor(Math.random()*200) + "," + Math.floor(Math.random()*200) + ","+ Math.floor(Math.random()*200) + ")";
  100. //基于x轴和y轴的位置
  101. this.x = Math.floor(Math.random()*map.xnum);
  102. this.y = Math.floor(Math.random()*map.ynum);
  103. this.flag = document.createElement("div");
  104. //设置食物的样式
  105. this.flag.style.width = this.width + "px";
  106. this.flag.style.borderRadius = "5px";
  107. this.flag.style.height = this.height + "px";
  108. this.flag.style.backgroundColor = this.bgcolor;
  109. //定义食物的位置
  110. this.flag.style.position = "absolute";
  111. this.flag.style.left = this.x * this.width + "px";
  112. this.flag.style.top = this.y * this.height + "px";
  113. map.canvas.appendChild(this.flag);
  114. }
  115. //创建蛇的构造方法
  116. function Snake(map){
  117. //设置宽、高
  118. this.width = map.atom;
  119. this.height = map.atom;
  120. //默认走的方向
  121. this.direction = "right";
  122. //设置蛇的主体
  123. this.body = [
  124. { x:2, y:0 }, //蛇头
  125. { x:1, y:0 }, //蛇体
  126. { x:0, y:0 }, //蛇尾
  127. ];
  128. //显示蛇 var i in this.body
  129. this.display = function(){
  130. for (var i = 0;i < this.body.length; i++){
  131. if (this.body[i].x != null){
  132. var create_s = document.createElement("div");
  133. //将节点保存到一个状态变量当中,以便之后删除
  134. this.body[i].flag = create_s;
  135. //设置蛇的样式
  136. create_s.style.width = this.width + "px";
  137. create_s.style.height = this.height + "px";
  138. /* create_s.style.border = "2px solid rgb(241, 159, 112)" */
  139. create_s.style.backgroundColor = "rgb(107, 109, 221)";
  140. create_s.style.borderRadius = "5px";
  141. //设置蛇的位置
  142. create_s.style.position = "absolute";
  143. create_s.style.left = this.body[i].x * this.width + "px";
  144. create_s.style.top = this.body[i].y * this.height + "px";
  145. //添加到地图中
  146. map.canvas.appendChild(create_s);
  147. }
  148. }
  149. }
  150. //控制蛇的运动
  151. this.run = function(){
  152. /*
  153. { x:2, y:0 }, //蛇头
  154. { x:1, y:0 }, //蛇体
  155. { x:0, y:0 }, //蛇尾
  156. 让x轴的每个位置+1
  157. */
  158. for (var i = this.body.length-1; i>0; i--) {
  159. this.body[i].x = this.body[i-1].x;
  160. this.body[i].y = this.body[i-1].y;
  161. }
  162. //根据方向处理蛇头
  163. switch (this.direction) {
  164. case "left":this.body[0].x--; break;
  165. case "right":this.body[0].x++; break;
  166. case "up": this.body[0].y--; break;
  167. case "down": this.body[0].y++; break;
  168. }
  169. //判断蛇头是否吃到食物,吃到食物坐标重叠
  170. if (this.body[0].x == food.x && this.body[0].y == food.y){
  171. //蛇加一节,由前面的否循环给这里的x和y赋值
  172. this.body.push({ x:null,y:null,flag:null });
  173. //判断是否下一关
  174. if (this.body.length >= level.slength){
  175. level.set();
  176. }
  177. //删除旧食物节点
  178. map.canvas.removeChild(food.flag);
  179. //创建新的食物
  180. food = new Food(map);
  181. }
  182. //判断蛇是否出界
  183. if (this.body[0].x < 0 || this.body[0].x > map.xnum - 1 || this.body[0].y < 0 || this.body[0].y > map.ynum-1) {
  184. //出界游戏结束,关闭定时器
  185. clearInterval(timer);
  186. alert("真笨呢~居然撞墙死掉了!");
  187. //重置关数
  188. document.querySelector("#gnum").innerHTML = "1";
  189. //重新开始游戏
  190. restart(map,this);
  191. return false;
  192. }
  193. // 判断蛇是否和咬到自己
  194. for (var i = 4;i < this.body.length; i++) {
  195. if (this.body[0].x == this.body[i].x && this.body[0].y == this.body[i].y){
  196. clearInterval(timer);
  197. alert("哎~怎么能咬到自己呢!");
  198. //重置关数
  199. document.querySelector("#gnum").innerHTML = "1";
  200. //重新开始游戏
  201. restart(map,this);
  202. return false;
  203. }
  204. }
  205. //删除旧的元素
  206. for (var i in this.body){
  207. if (this.body[i].flag != null){ //当吃到食物,flag等于null,且不能删除
  208. map.canvas.removeChild(this.body[i].flag);
  209. }
  210. }
  211. //显示新的元素
  212. this.display();
  213. }
  214. }
  215. function restart(map,snake){
  216. //删除蛇的"尸体"
  217. for (var i in snake.body){
  218. map.canvas.removeChild(snake.body[i].flag);
  219. }
  220. //重新生成蛇
  221. snake.body = [
  222. { x:2, y:0 }, //蛇头
  223. { x:1, y:0 }, //蛇体
  224. { x:0, y:0 }, //蛇尾
  225. ];
  226. //初始化方向
  227. snake.direction = "right";
  228. //重新显示蛇
  229. snake.display();
  230. map.canvas.removeChild(food.flag);
  231. food = new Food(map)
  232. }
  233. //设置规则类,控制级别
  234. function Level(){
  235. this.num = 1; //第几级别
  236. this.speed = 300; //毫秒,每升一关,速度加快
  237. this.slength = 7; //每一关的程度判断
  238. this.set = function(){
  239. this.num++;
  240. if (this.speed <= 100){
  241. this.speed = 100;
  242. }else{
  243. this.speed -= 40;
  244. }
  245. this.slength += 3; //通关的长度,自行设置
  246. this.display();
  247. start(); //重新开始,速度加快
  248. }
  249. //定义关数的显示
  250. this.display = function(){
  251. document.querySelector("#gnum").innerHTML = this.num;
  252. }
  253. }
  254. //实例化规则类
  255. var level = new Level();
  256. level.display();
  257. //实例化地图类
  258. var map = new Map(20,40,20);
  259. map.create(); //创建画布
  260. //实例化食物类,并创建食物
  261. var food = new Food(map);
  262. //实例化蛇类,创建蛇
  263. var snake = new Snake(map);
  264. //显示蛇
  265. snake.display();
  266. //加入键盘事件,控制蛇的方向
  267. document.onkeydown = function(event){
  268. event = event || window.event;
  269. //上:38 右:39 下:40 左:37
  270. switch (event.keyCode){
  271. case 38:
  272. if (snake.direction != "down"){
  273. snake.direction = "up";
  274. }
  275. break;
  276. case 39:
  277. if (snake.direction != "left"){
  278. snake.direction = "right";
  279. }
  280. break;
  281. case 40:
  282. if (snake.direction != "up"){
  283. snake.direction = "down";
  284. }
  285. break;
  286. case 37:
  287. if (snake.direction != "right"){
  288. snake.direction = "left";
  289. }
  290. break;
  291. }
  292. }
  293. function start(){
  294. clearInterval(timer);
  295. timer = setInterval(function(){
  296. snake.run();
  297. },level.speed);
  298. }
  299. //给开始按钮绑定函数
  300. document.querySelector("#begin").onclick = function(){
  301. start();
  302. }
  303. document.querySelector("#pause").onclick = function(){
  304. clearInterval(timer);
  305. }
  306. </script>
  307. </div>
  308. </body>
  309. </html>