forked from 75camp/2018-contest
-
Notifications
You must be signed in to change notification settings - Fork 0
/
global.js
419 lines (353 loc) · 14.4 KB
/
global.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
window.onload = function () {
// 是否生成新的数字
var isNewNum = false;
var currScore = 0; // 本局游戏得分
var maxScore = 0; // 历史最高得分
// 利用本地缓存来记录历史分数
if (localStorage.maxScore) {
maxScore = localStorage.maxScore - 0; //localStorage.maxScore为字符串类型
} else {
maxScore = 0;
}
var GAME = {
/*
** 游戏初始化
*/
init: function () {
// 初始化得分
$('#currScore').html(currScore);
$('#maxScore').html(maxScore);
// 再来一次游戏刷新
$('.refreshBtn').click(this.playAgain);
// 随机生成两个数字,2或者4
this.newRandomNum();
this.newRandomNum();
// 刷新盒子的背景色
this.refreshColor();
},
/*
** 再来一次游戏刷新
*/
playAgain: function () {
var boxes = $('.boxes .row .box');
for (var i = 0; i < boxes.length; i++) {
boxes.eq(i).html('').removeClass('nonEmptyBox').addClass('emptyBox');
}
// 本局游戏分数清零
currScore = 0;
$('#currScore').html(currScore);
// 随机生成两个数字,2或者4
GAME.newRandomNum();
GAME.newRandomNum();
// 刷新盒子的背景色
GAME.refreshColor();
},
/*
** 随机生成一个新数字
*/
newRandomNum: function () {
var randomNumArr = [2, 2, 4];
var randomNum = randomNumArr[getRandom(0, 2)];
// 随机生成新数字的盒子
var emptyBoxes = $('.boxes .row .emptyBox');
var newNumBox = getRandom(0, emptyBoxes.length - 1);
emptyBoxes.eq(newNumBox).html(randomNum).removeClass('emptyBox').addClass('nonEmptyBox');
},
/*
** 刷新盒子的背景色
*/
refreshColor: function () {
var boxes = $('.boxes .row .box');
for (var i = 0; i < boxes.length; i++) {
switch (boxes.eq(i).html()) {
case '':
boxes.eq(i).css('background', '');
break;
case '2':
boxes.eq(i).css('background', '#FAEBD7');
break;
case '4':
boxes.eq(i).css('background', '#FFDEAD');
break;
case '8':
boxes.eq(i).css('background', '#FFC125');
break;
case '16':
boxes.eq(i).css('background', '#FF8C00');
break;
case '32':
boxes.eq(i).css('background', '#FFC0CB');
break;
case '64':
boxes.eq(i).css('background', '#FF6A6A');
break;
case '128':
boxes.eq(i).css('background', '#FF0000');
break;
case '256':
boxes.eq(i).css('background', '#FFFACD');
break;
case '512':
boxes.eq(i).css('background', 'FFF68F');
break;
case '1024':
boxes.eq(i).css('background', '#FFB90F');
break;
case '2048':
boxes.eq(i).css('background', '#F4A460');
break;
case '4096':
boxes.eq(i).css('background', '#FFFF00');
break;
}
}
},
/*
** 获取到当前盒子旁边的盒子
*/
getSideBox: function (currBox, direction) {
// 当前盒子的位置
var currBoxX = currBox.attr('data-x') - 0;
var currBoxY = currBox.attr('data-y') - 0;
// 根据移动方向确定当前盒子旁边的盒子
switch (direction) {
case 'up':
var sideBoxX = currBoxX - 1;
var sideBoxY = currBoxY;
break;
case 'down':
var sideBoxX = currBoxX + 1;
var sideBoxY = currBoxY;
break;
case 'left':
var sideBoxX = currBoxX;
var sideBoxY = currBoxY - 1;
break;
case 'right':
var sideBoxX = currBoxX;
var sideBoxY = currBoxY + 1;
break;
}
// 旁边的盒子
var sideBox = $('.boxes .row .x' + sideBoxX + 'y' + sideBoxY);
return sideBox;
},
/*
** 移动当前盒子
*/
boxMove: function (currBox, direction) {
// 获取到当前盒子旁边的盒子
var sideBox = GAME.getSideBox(currBox, direction);
if (sideBox.length === 0) { //当前盒子在最边边上且往边上那个方向移动时,即当前盒子在移动方向上旁边没有盒子
// 当前盒子不动
} else if (sideBox.html() === '') { //当前盒子不在最边边上,且四周(四个移动方向上)都是空盒子时
sideBox.html(currBox.html()).removeClass('emptyBox').addClass('nonEmptyBox');
currBox.html('').removeClass('nonEmptyBox').addClass('emptyBox');
GAME.boxMove(sideBox, direction);
isNewNum = true; //生成一个新的数字
} else if (sideBox.html() !== currBox.html()) { //当前盒子的数字和移动方向上旁边的盒子数字不同
// 当前盒子不动
} else { //当前盒子和移动方向上旁边的盒子数字相同
// 合并
sideBox.html((sideBox.html() - 0) * 2);
currBox.html('').removeClass('nonEmptyBox').addClass('emptyBox');
currScore += (sideBox.html() - 0) * 10; //更新本局得分
$('#currScore').html(currScore);
// 比较本局当前得分和历史最高分,更新历史最高分
maxScore = currScore > maxScore ? currScore : maxScore;
$('#maxScore').html(maxScore);
localStorage.maxScore = maxScore;
isNewNum = true; //合并完产生一个新的数字
return;
}
},
/*
** 整体移动
*/
move: function (direction) {
var that = this;
// 获取所有非空盒子
var nonEmptyBoxes = $('.boxes .row .nonEmptyBox');
// 按键方向向左或向上时,正向遍历非空盒子,将非空的盒子依次朝按键方向移动,即先移动按键方向上最底层的盒子
if (direction === 'left' || direction === 'up') {
for (var i = 0; i < nonEmptyBoxes.length; i++) {
var currBox = nonEmptyBoxes.eq(i);
that.boxMove(currBox, direction);
}
} else if (direction === 'right' || direction === 'down') { //按键方向向右或向下时,正向遍历非空盒子
for (var i = nonEmptyBoxes.length - 1; i >= 0; i--) {
var currBox = nonEmptyBoxes.eq(i);
that.boxMove(currBox, direction);
}
}
// 判断是否产生新的数字
if (isNewNum) {
this.newRandomNum();
this.refreshColor();
}
},
/*
** 判断游戏是否结束
*/
isGameOver: function () {
// 获取所有盒子
var boxes = $('.boxes .row .box');
// 获取所有非空盒子
var nonEmptyBoxes = $('.boxes .row .nonEmptyBox');
if (boxes.length === nonEmptyBoxes.length) { //没有空盒子
// 遍历所有非空盒子
for (var i = 0; i < nonEmptyBoxes.length; i++) {
var currBox = nonEmptyBoxes.eq(i);
if (GAME.getSideBox(currBox, 'up') !== 0 && currBox.html() === GAME.getSideBox(currBox, 'up').html()) {
// 即当前盒子上方的盒子存在,且二者的数字相同
return;
} else if (GAME.getSideBox(currBox, 'down') !== 0 && currBox.html() === GAME.getSideBox(currBox, 'down').html()) {
// 即当前盒子下方的盒子存在,且二者的数字相同
return;
} else if (GAME.getSideBox(currBox, 'left') !== 0 && currBox.html() === GAME.getSideBox(currBox, 'left').html()) {
// 即当前盒子左侧的盒子存在,且二者的数字相同
return;
} else if (GAME.getSideBox(currBox, 'right') !== 0 && currBox.html() === GAME.getSideBox(currBox, 'right').html()) {
// 即当前盒子右侧的盒子存在,且二者的数字相同
return;
}
}
} else {
return;
}
window.alert("游戏结束!!!");
}
};
// 产生 min到max之间的随机整数
function getRandom(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
// 游戏初始化
GAME.init();
// 监听再来一次按钮的点击事件
$('.refreshBtn').click(GAME.playAgain);
// 监听键盘的方向键触发盒子移动
$('body').keydown(function (event) {
switch (event.keyCode) {
case 37:
// left
isNewNum = false;
GAME.move('left');
GAME.isGameOver();
break;
case 38:
// up
isNewNum = false;
GAME.move('up');
GAME.isGameOver();
break;
case 39:
// right
isNewNum = false;
GAME.move('right');
GAME.isGameOver();
break;
case 40:
// down
isNewNum = false;
GAME.move('down');
GAME.isGameOver();
break;
}
});
// 移动端手指触摸滑动触发盒子移动
(function () {
var boxesArea = document.getElementsByClassName('boxes')[0];
mobileTouch(boxesArea);
boxesArea.addEventListener('right', function (e) {
e.preventDefault();
isNewNum = false;
GAME.move('right');
GAME.isGameOver();
});
boxesArea.addEventListener('left', function (e) {
e.preventDefault();
isNewNum = false;
GAME.move('left');
GAME.isGameOver();
});
boxesArea.addEventListener('up', function (e) {
e.preventDefault();
isNewNum = false;
GAME.move('up');
GAME.isGameOver();
});
boxesArea.addEventListener('down', function (e) {
e.preventDefault();
isNewNum = false;
GAME.move('down');
GAME.isGameOver();
});
// 根据触摸开始和结束的位置,判断滑动方向,进而确定盒子的移动方向
function mobileTouch(obj) {
var startX, startY, endX, endY, distX, distY;
// 监听触摸开始的位置
obj.addEventListener('touchstart', function (e) {
startX = e.targetTouches[0].clientX;
startY = e.targetTouches[0].clientY;
}, false);
// 监听触摸结束的位置
obj.addEventListener('touchend', function (e) {
endX = e.changedTouches[0].clientX;
endY = e.changedTouches[0].clientY;
distX = endX - startX;
distY = endY - startY;
var difference = Math.abs(distX) - Math.abs(distY); //根据difference判断滑动是在水平方向还是垂直方向上
if (distY < 0 && difference < 0) {
obj.dispatchEvent(eventCustom('up'));
} else if (distY > 0 && difference < 0) {
obj.dispatchEvent(eventCustom('down'));
} else if (distX > 0 && difference > 0) {
obj.dispatchEvent(eventCustom('right'));
} else if (distX < 0 && difference > 0) {
obj.dispatchEvent(eventCustom('left'));
}
}, false);
// 处理自定义事件
function eventCustom(eName) {
if (typeof document.CustomEvent === 'function') {
this.event = new document.CustomEvent(eName, { //定义自定义事件
bubbles: false,
cancelable: false
});
if (!document["eventself" + eName]) {
document["eventself" + eName] = this.event;
}
} else if (typeof document.createEvent === 'function') {
this.event = document.createEvent('HTMLEvents');
this.event.initEvent(eName, false, false);
if (!document["eventself" + eName]) {
document["eventself" + eName] = this.event;
}
} else {
return false;
}
return document["eventself" + eName];
}
}
})();
// safari页面缩放问题
// 禁用双指缩放
document.addEventListener('touchstart', function (event) {
if (event.touches.length > 1) {
event.preventDefault();
}
}, {
capture: true,
passive: false
});
// 禁用手指双击缩放
var lastTouchEnd = 0;
document.addEventListener('touchend', function (event) {
var now = (new Date()).getTime();
if (now - lastTouchEnd <= 300) {
event.preventDefault();
}
lastTouchEnd = now;
}, false);
};