首页 > 技术文章 > javascript 实现贪吃蛇游戏

hjysunshine 2020-02-07 11:38 原文

html代码:

1 <div class="content">
2     <div class="btn startBtn">             <!-- 开始按钮 -->   
3         <button type="button"></button>
4     </div>
5     <div class="btn stopBtn">                <!-- 暂停按钮 -->
6         <button type="button"></button>
7     </div>
8     <div id="snakeWrap"></div>         <!-- 主题内容 -->
9 </div>

css代码:

 1 * {
 2     margin: 0;
 3     padding: 0;
 4 }
 5 body {
 6     background-color: #565F65;
 7     width: 100%;
 8     height: 10vh;
 9     overflow: hidden;
10 }
11 
12 .content {
13     width: 500px;
14     height: 500px;
15     position: absolute;
16     top: 50%;
17     left: 50%; 
18     margin-top: -250px;
19     margin-left: -250px;
20     background-color: #565F65;
21     border: 10px solid #E7E7E7;
22     box-shadow: inset 0px 0px 5px 2px #000;
23 }
24 .btn {
25     width: 100%;
26     height: 100%;
27     position: absolute;
28     top: 0;
29     left: 0;
30     background-color: rgba(0, 0, 0, .3);    /*游戏未开始时和暂停时的遮罩*/
31     z-index: 2;
32 }
33 .btn button {
34     background: none;
35     border: none;
36     background-size: 100% 100%;
37     cursor: pointer;
38     outline: none;
39     position: absolute;
40     left: 50%;
41     top: 50%;
42 }
43 .startBtn button{
44     width: 170px;
45     height: 80px;
46     background-image: url(img/startbtn.png);
47     margin-top: -40px;
48     margin-left: -85px;
49 }
50 .stopBtn {
51     display: none;
52 }
53 .stopBtn button{
54     width: 70px;
55     height: 70px;
56     background-image: url(img/stopbtn.png);
57     margin-top: -35px;
58     margin-left: -35px;
59 }
60 
61 #snakeWrap {
62     width: 500px;
63     height: 500px;
64     position: relative;
65 }
66 .snakeHead { /*蛇头样式*/
67     background-color: aqua;
68     border-radius: 50%;
69 }
70 .snakeBody { /*蛇身样式*/           
71     background-color: navajowhite;
72     border-radius: 50%;
73 }
74 .food {   /*食物样式*/
75     background-image: url(img/food.png);
76     background-size: cover;
77 }

 

javascript 代码:

  1 var sw = 20,    //一个方块的宽
  2      sh = 20,    //一个方块的高
  3        tr = 25,    //行数
  4        td = 25;    //列数
  5 var snake = null,   //蛇的实例
  6        food = null,    //食物的实例
  7        game  = null;   //游戏的实例

8 function Square(x, y, classname) { 9 this.x = x * sw; //方块实际的位置 10 this.y = y * sh; //方块实际的位置 11 this.class = classname; 12 13 this.viewContent = document.createElement('div'); //方块对应的DOM元素 14 this.viewContent.className = this.class; 15 this.parent = document.getElementById('snakeWrap'); //方块的父级 16 } 17 18 Square.prototype.create = function() { //创建方块 DOM,并添加到页面里 19 this.viewContent.style.position = 'absolute'; 20 this.viewContent.style.width = sw + 'px'; 21 this.viewContent.style.height = sh + 'px'; 22 this.viewContent.style.left = this.x + 'px'; 23 this.viewContent.style.top = this.y + 'px'; 24 25 this.parent.appendChild(this.viewContent); 26 }; 27 28 Square.prototype.remove = function() { 29 this.parent.removeChild(this.viewContent); 30 } 31 32 // 33 function Snake() { 34 this.head = null; //存一下蛇头的信息 35 this.tail = null; //存一下蛇尾的信息 36 this.pos = []; //存储蛇身上的每一个方块的位置,二维数组 37 38 this.directionNum = { //存储蛇走的方向,用一个对象来表示 39 left : { 40 x : -1, 41 y : 0, 42 rotate : 180 43 }, 44 right : { 45 x : 1, 46 y : 0, 47 rotate : 0 48 }, 49 up : { 50 x : 0, 51 y : -1, 52 rotate : -90 53 }, 54 down : { 55 x : 0, 56 y : 1, 57 rotate : 90 58 } 59 } 60 } 61 62 Snake.prototype.init = function() { 63 //创建蛇头 64 var snakeHead = new Square(2, 0, 'snakeHead'); 65 snakeHead.create(); 66 this.head = snakeHead; // 存储蛇头信息 67 this.pos.push([2, 0]); //把蛇头的位置存起来 68 69 //创建蛇身体 70 var snakeBody1 = new Square(1, 0, 'snakeBody'); 71 snakeBody1.create(); 72 this.pos.push([1, 0]); //把蛇身1的位置存起来 73 74 var snakeBody2 = new Square(0, 0, 'snakeBody'); 75 snakeBody2.create(); 76 this.tail = snakeBody2; //把蛇尾的信息存起来 77 this.pos.push([0, 0]); //把蛇身1的位置存起来 78 79 //让蛇头蛇身形成链表关系 80 snakeHead.last = null; 81 snakeHead.next = snakeBody1; 82 83 snakeBody1.last = snakeHead; 84 snakeBody1.next = snakeBody2; 85 86 snakeBody2.last = snakeBody1; 87 snakeBody2.next = null; 88 89 //给蛇添加一条属性,用来表示蛇走的方向 90 this.direction = this.directionNum.right; //默认让蛇往右走 91 92 } 93 94 //这个方法用来获取蛇头的下一个位置对应的元素, 要根据元素做不同的事情 95 Snake.prototype.getNextPos = function() { 96 var nextPos = [ //蛇头要走的下一个点的坐标 97 this.head.x/sw + this.direction.x, 98 this.head.y/sh + this.direction.y 99 ]; 100 101 //下一个点是自己,代表撞到了自己,游戏结束 102 var selfCollind = false; //是否撞到自己 103 this.pos.forEach(function(value) { 104 if(value[0] == nextPos[0] && value[1] == nextPos[1]) { 105 //如果数组中的两个数据都相等,就说明下一个点在蛇身上里面能找到,代表撞到自己了 106 selfCollind = true; 107 } 108 }); 109 if(selfCollind) { 110 console.log('撞到自己了!'); 111 112 this.strategies.die.call(this); 113 114 return; 115 } 116 117 //下一个点是墙,游戏结束 118 if(nextPos[0] < 0 || nextPos[1] < 0 || nextPos[0] > td - 1 || nextPos[1] > tr - 1) { 119 console.log('撞墙了!'); 120 121 this.strategies.die.call(this); 122 123 return; 124 } 125 //下一个点是食物,吃 126 if(food && food.pos[0] == nextPos[0] && food.pos[1] == nextPos[1]) { 127 //如果这个条件成立说明现在蛇头要走的下一个点是食物的那个点 128 console.log('撞到食物了了!'); 129 this.strategies.eat.call(this); 130 return; 131 } 132 //下一个点什么都不是,走 133 this.strategies.move.call(this); 134 }; 135 136 //处理碰撞后要做的事 137 Snake.prototype.strategies = { 138 move : function(format) { //这个参数用于决定要不要删除最后一个方块(蛇尾), 当传了这个参数后就表示要做的事情是吃 139 //创建新身体(在蛇头位置) 140 var newBody = new Square(this.head.x/sw, this.head.y/sh, 'snakeBody'); 141 //更新链表关系 142 newBody.next = this.head.next; 143 newBody.next.last = newBody; 144 newBody.last = null; 145 146 147 this.head.remove(); //旧舌头从原来的位置删除 148 newBody.create(); 149 150 //创建一个新蛇头(蛇头下一个要走到的点) 151 var newHead = new Square(this.head.x/sw + this.direction.x, this.head.y/sh + this.direction.y, 'snakeHead') 152 //更新链表关系 153 newHead.next = newBody; 154 newHead.last = null; 155 newBody.last = newHead; 156 newHead.viewContent.style.transform = 'rotate('+this.direction.rotate+'deg)'; 157 newHead.create(); 158 159 160 //蛇身上每一个方块的坐标也要更新 161 this.pos.splice(0,0, [this.head.x/sw + this.direction.x, this.head.y/sh + this.direction.y]); 162 this.head = newHead; //还要把this.head的信息更新一下 163 164 if(!format) { //如何format 的值为 false, 表示需要删除(除了吃之外的操作) 165 this.tail.remove(); 166 this.tail = this.tail.last; 167 168 this.pos.pop(); 169 } 170 171 }, 172 eat : function() { 173 this.strategies.move.call(this, true); 174 createFood(); 175 game.score ++; 176 }, 177 die : function() { 178 game.over(); 179 } 180 } 181 182 snake = new Snake(); 183 184 //创建食物 185 function createFood() { 186 //食物小方块的随机坐标 187 var x = null; 188 var y = null; 189 190 var include = true; //循环跳出的条件, true表示食物的坐标在蛇身上(需要继续循环),false表示食物坐标不在蛇身上(不循环了) 191 while(include) { 192 x = Math.round(Math.random() * (td - 1)); //0-29 193 y = Math.round(Math.random() * (tr - 1)); 194 195 snake.pos.forEach(function(value) { 196 if(x != value[0] && y != value[1]) { 197 //这个条件成立说明现在随机出来的这个坐标,在蛇身上并没有找到 198 include = false; 199 } 200 }); 201 202 } 203 //生成食物 204 food = new Square(x, y, 'food'); 205 food.pos = [x,y]; //存储一下生成食物的坐标,用于跟蛇头要走的下一个点作对比 206 var foodDom = document.querySelector('.food'); 207 if(foodDom) { 208 foodDom.style.left = x*sw + 'px'; 209 foodDom.style.top = y*sh + 'px'; 210 }else { 211 food.create(); 212 } 213 } 214 215 216 217 //创建游戏逻辑 218 function Game() { 219 this.timer = null; 220 this.score = 0; 221 this.speed = 200; 222 } 223 Game.prototype.init = function() { 224 snake.init(); 225 snake.getNextPos(); 226 createFood(); 227 228 document.onkeydown = function(ev) { //用户按下方向键触发事件 229 if(ev.which == 37 && snake.direction != snake.directionNum.right) { 230 //用户按下左键是,蛇不能是往右走 231 snake.direction = snake.directionNum.left; 232 }else if(ev.which == 38 && snake.direction != snake.directionNum.dowm) { 233 snake.direction = snake.directionNum.up; 234 }else if(ev.which == 39 && snake.direction != snake.directionNum.left) { 235 snake.direction = snake.directionNum.right; 236 }else if(ev.which == 40 && snake.direction != snake.directionNum.up) { 237 snake.direction = snake.directionNum.down; 238 } 239 } 240 241 this.start(); 242 } 243 244 Game.prototype.start = function() { //开始游戏 245 this.timer = setInterval(function() { 246 snake.getNextPos(); 247 248 }, this.speed); 249 } 250 Game.prototype.pause = function() { 251 clearInterval(this.timer); 252 } 253 Game.prototype.over = function() { //开始游戏 254 clearInterval(this.timer); 255 alert('你的得分为' + this.score); 256 257 //游戏回到最初的状态 258 var snakeWrap = document.getElementById('snakeWrap'); 259 snakeWrap.innerHTML = ''; 260 snake = new Snake(); 261 game = new Game(); 262 var startBtnWrap = document.querySelector('.startBtn'); 263 startBtnWrap.style.display = 'block'; 264 } 265 //开启游戏 266 game = new Game(); 267 var startBtn = document.querySelector('.startBtn button'); 268 startBtn.onclick = function() { 269 startBtn.parentNode.style.display = 'none'; 270 game.init(); 271 }; 272 273 274 //暂停 275 var snakeWrap = document.getElementById('snakeWrap'); 276 var puseBtn = document.querySelector('.stopBtn button') 277 snakeWrap.onclick = function() { 278 game.pause(); 279 puseBtn.parentNode.style.display = 'block'; 280 } 281 282 puseBtn.onclick =function() { 283 game.start(); 284 puseBtn.parentNode.style.display = 'none'; 285 }

 

推荐阅读