用html5_canvas实现2048网页游戏

摘要:用html5_canvas实现2048网页游戏

查看示例

html代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<div class="main">
<canvas id="myCanvas" width="300" height="300" ></canvas>
</div>
<div class="bottom" style="display: none;">
<div>
<div id="W" class="con">W</div>
</div>
<div>
<div id="A" class="con">A</div>
<div id="S" class="con">S</div>
<div id="D" class="con">D</div>
</div>
</div>
<div class="tips"><h4>方向控制:WASD、↑↓←→、手指滑动</h4></div>

css代码

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
<style>
body {
margin: 0;
padding: 0;
}

#myCanvas {
/*border: red 1px solid;*/
margin: 10px auto;
border-radius: 10px;
display: block;
}
.bottom{
text-align: center;
}
.bottom>div{
margin-top: 10px;
}
.con{
color:white;
background-color: green;
display: inline-block;
width:50px;
height:50px;
line-height: 50px;
text-align: center;
}
.tips{
text-align: center;
}
</style>

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
<script src="http://apps.bdimg.com/libs/jquery/1.11.3/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var d=12;
var a=60;
var directMap = {
'W':0,
'S':1,
'A':2,
'D':3,
'&':0,
'(':1,
'%':2,
'\'':3
};
//当前屏幕上所有的块
var blocks = [
0, 0, 0, 0,
2, 0, 0, 0,
0, 0, 2, 0,
0, 0, 0, 2
];
var newBlocks=[];//blocks的备份,用来保存目标状态
var newIndex=[];//保存每个块的目标位置,如newIndex[4]=8表示第4个块移动到第8个块的位置(下移一格)
//生成新数字
var another_num = function(){
var empty = [];
for(var i = 0 ; i < blocks.length; i++){
if(blocks[i]==0){
empty.push(i)
}
}
var idx = empty[parseInt(Math.random() * empty.length)];
blocks[idx] = Math.random() < 0.8 ? 2 : 4;
drawBlock(idx)
};
//通过数组下标(0-15)计算4个相关的值
var getPositon = function(n){
var obj = {};
obj.i = n%4;//第几列(从0开始)
obj.j = parseInt(n/4);//第几行(从0开始)
obj.x = (obj.i+1)*d+obj.i*a;//横坐标
obj.y = (obj.j+1)*d+obj.j*a;//纵坐标
return obj;
};
//画单个块和数字,若不指定x,y的值,则由index计算得出
var drawBlock = function(index,dx,dy){
context.fillStyle = '#ECE0C8';
var num = blocks[index];
if(num==0)return;
var x = getPositon(index).x;
var y = getPositon(index).y;
if (dx != null)x = dx;
if (dy != null)y = dy;
context.fillRect(x,y,a,a);
var fontSize = 30;
var l = num.toString().length;
if(l==4){
fontSize=25
}else if(l==5){
fontSize=20
}
context.font='bold '+fontSize+'px Meiryo';
context.fillStyle = '#7C736A';
x=x+(a-fontSize*2*l/3)/2;
y=y+(fontSize+a)/2;

context.fillText(num.toString(),x,y);
};

var merged=[];
//将cur合并到pre,若成功合并则返回pre,没合并则返回cur
var merge=function(pre , cur){
if(newBlocks[cur]!=0){
if(newBlocks[pre]==0){
newBlocks[pre]=newBlocks[cur];
newBlocks[cur]=0;
return pre
}else if(newBlocks[pre]==newBlocks[cur]&&merged.indexOf(pre)==-1){//已经合并过一此的pre块不再合并
newBlocks[pre]*=2;
newBlocks[cur]=0;
merged.push(pre);
return pre
}else{
return cur
}
}else{
return cur
}
};
//块的合并;计算本次操作后每个块目标位置(保存至newIndex数组)
var getNewIndex = function (direct) {
merged=[];
switch (direct) {
case 0:
for (var j = 0; j < 4; j++) {
for (var i = 0; i < 4; i++) {
var k = 1;
var index = 4*i+j;
while (4 * (i - k) + j >= 0) {
index = merge(4 * (i - k) + j, 4 * (i - k + 1) + j);
if(index==4*i+j)break;
k++;
}
newIndex[4*i+j]=index;
}
}
break;
case 1:
for (var j = 0; j < 4; j++) {
for (var i = 3; i >= 0; i--) {
var k = 1;
var index = 4*i+j;
while (4 * (i + k) + j < blocks.length) {
index = merge(4 * (i + k) + j, 4 * (i + k - 1) + j);
if(index==4*i+j)break;
k++;
}
newIndex[4*i+j]=index;
}
}
break;
case 2:
for (var i = 0; i < 4; i++) {
for (var j = 0; j < 4; j++) {
var k = 1;
var index = 4*i+j;
while (j - k >= 0) {
index = merge(4 * i + j - k, 4 * i + j - k + 1);
if(index==4*i+j)break;
k++;
}
newIndex[4*i+j]=index;
}
}
break;
case 3:
for (var i = 0; i < 4; i++) {
for (var j = 3; j >= 0; j--) {
var k = 1;
var index = 4*i+j;
while (j + k < 4) {
index = merge(4 * i + j + k, 4 * i + j + k - 1);
if(index==4*i+j)break;
k++;
}
newIndex[4*i+j]=index;
}
}
break;
default:
break;
}
};
//动画结束后刷新每个块的信息,产生一个新的块
var stopMoving = function(){
init();
for(var n=0;n<blocks.length;n++){
blocks[n]=newBlocks[n]+0;
drawBlock(n)
}
another_num()
};
//滑动操作
var moveBlocks = function(direct) {
//先将所有块的当前状态复制到新数组中
for (var n = 0; n < blocks.length; n++) {
newBlocks[n] = blocks[n] + 0
}
//合并,计算本次操作后每个块目标位置
getNewIndex(direct);

//动画开始
var t = 0;
var int = setInterval(function () {
//初始化背景
init();
//画有数字的块
switch (direct) {
case 0:
var stop = true;
for (var n = 0; n < blocks.length; n++) {
if (blocks[n] == 0)continue;
var x = getPositon(n).x;
var y = getPositon(n).y;
y -= d * 4 * t;//一点点地改变坐标 实现动画效果
if (y <= getPositon(newIndex[n]).y) {//本块到达目标位置,不再动了
y = getPositon(newIndex[n]).y
} else {//本块没有到达目标位置,动画不能停
stop = false
}
drawBlock(n, null, y)
}
if (stop) {
//动画结束,重新给数组赋值
clearInterval(int);
stopMoving()
}
break;
case 1:
var stop = true;
for (var n = 0; n < blocks.length; n++) {
if (blocks[n] == 0)continue;
var x = getPositon(n).x;
var y = getPositon(n).y;
y += d * 4 * t;
//停止移动的条件:该块到达最终位置
if (y >= getPositon(newIndex[n]).y) {
y = getPositon(newIndex[n]).y
} else {
stop = false
}
drawBlock(n, null, y)
}

if (stop) {
//动画结束,重新给数组赋值
clearInterval(int);
stopMoving();
}
break;
case 2:
var stop = true;
for (var n = 0; n < blocks.length; n++) {
if (blocks[n] == 0)continue;
var x = getPositon(n).x;
var y = getPositon(n).y;
x -= d * 4 * t;
if (x <= getPositon(newIndex[n]).x) {
x = getPositon(newIndex[n]).x
} else {
stop = false
}
drawBlock(n, x, null)
}
if (stop) {
//动画结束,重新给数组赋值
clearInterval(int);
stopMoving()
}
break;
case 3:
var stop = true;
for (var n = 0; n < blocks.length; n++) {
if (blocks[n] == 0)continue;
var x = getPositon(n).x;
var y = getPositon(n).y;
x += d * 4 * t;
if (x >= getPositon(newIndex[n]).x) {
x = getPositon(newIndex[n]).x
} else {
stop = false
}
drawBlock(n, x, null)
}
if (stop) {
//动画结束,重新给数组赋值
clearInterval(int);
stopMoving()
}
break;
}
t++
}, 20)
};



//滑屏监听
var startX,startY;
$('#myCanvas').bind("touchstart", function(e) {
e.preventDefault();
startX = e.originalEvent.changedTouches[0].pageX;
startY = e.originalEvent.changedTouches[0].pageY;
});
$('#myCanvas').bind("touchend", function(e) {
e.preventDefault();
var moveEndX = e.originalEvent.changedTouches[0].pageX;
var moveEndY = e.originalEvent.changedTouches[0].pageY;
var X = moveEndX - startX;
var Y = moveEndY - startY;
if ( Math.abs(Y) > Math.abs(X) && Y < 0 ) {//上
moveBlocks(0)
}else if ( Math.abs(Y) > Math.abs(X) && Y > 0) {//下
moveBlocks(1)
}else if ( Math.abs(X) > Math.abs(Y) && X < 0 ) {//左
moveBlocks(2)
}else if ( Math.abs(X) > Math.abs(Y) && X > 0 ) {//右
moveBlocks(3)
}
});
//键盘监听
document.onkeydown = function (e) {
var keynum, keychar;
if(window.event){ // IE
keynum = e.keyCode;
}
else if(e.which){ // Netscape/Firefox/Opera
keynum = e.which;
}
keychar = String.fromCharCode(keynum);
if(['W', 'S', 'A', 'D','&','(','%','\''].indexOf(keychar) > -1){
moveBlocks(directMap[keychar])
}
};
//按钮监听
var btns = document.getElementsByClassName("con");
for(var i=0;i<btns.length;i++){
btns[i].onclick = function() {
moveBlocks(directMap[this.id])
}
}


//初始化 开始
var init = function() {
//画背景
context.clearRect(0, 0, 300, 300);
context.fillStyle = '#B8AF9E';
context.fillRect(0, 0, 300, 300);
context.fillStyle = '#CCC0B2';
for (var i = 1; i <= 4; i++) {
for (var j = 1; j <= 4; j++) {
context.fillRect(i * d + (i - 1) * a, j * d + (j - 1) * a, a, a)
}
}
};
init();
//画有数字的块
for (var n = 0; n < blocks.length; n++) {
drawBlock(n)
}


})
</script>