html+css+javascript实现小游戏2048(详解,附源代码)
1.上下左右的移动原理相同,这里只详细说明向上移动的方法 2.这里的上下左右由wasd四个键控制 3…小方块空的意思就是没数字,空白
html部分
先创建好2048的一个静态布局 zuiwaibian:一个大的框框,整体的游戏界面。 caidan:用于显示当前得分的区域。 a1,a2,a3,a4:是第一行的小方块。 b1,b2,b3,b4:是第二行的小方块。 c1,c2,c3,c4:是第三行的小方块。 d1,d2,d3,d4:是第四行的小方块。
<div id="zuiwaibian">
<div id="caidan">0</div>
<div id="youxi">
<div id="a1" class="model"></div>
<div id="a2" class="model"></div>
<div id="a3" class="model"></div>
<div id="a4" class="model"></div>
<div id="b1" class="model"></div>
<div id="b2" class="model"></div>
<div id="b3" class="model"></div>
<div id="b4" class="model"></div>
<div id="c1" class="model"></div>
<div id="c2" class="model"></div>
<div id="c3" class="model"></div>
<div id="c4" class="model"></div>
<div id="d1" class="model"></div>
<div id="d2" class="model"></div>
<div id="d3" class="model"></div>
<div id="d4" class="model"></div>
</div>
</div>
css部分
为html部分相应标签设置对应css样式。 zuiwaibian
#zuiwaibian{
width:400px;
height:600px;
background-color:#fce6ce;
}
caidan
#caidan{
width:100%;
height:150px;
margin-top:6px;
background-color:#a68c71;
font-size:50px;
text-align:center;
line-height:150px;
color:#fff;
}
youxi
#youxi{
width:400px;
height:400px;
background:#c0af9d;
margin-top:10px;
}
小方块样式
.model{
float:left;
margin-left:8px;
margin-top:8px;
width:90px;
height:90px;
background-color:#cdc1b3;
border-radius:5px;
}
设置成功后如下 
全局变量
记录得分的变量score
var score=0;
存储16个id的二维数组(便于遍历)
var a=[['a1','a2','a3','a4'],['b1','b2','b3','b4'],['c1','c2','c3','c4'],['d1','d2','d3','d4']];
用于记录在一次移动过程中每个小方块相加的次数
var xx=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
作用说明:假设有如下  防止按下w(上)直接生成8  后面会做介绍
小方块处理函数
1.qingkong(kuai_object) 该函数用于清空小方块中的数字,以及颜色。 参数 kuai_object:小方块对象
function qingkong(kuai_object){
kuai_object.style.backgroundColor="#cdc1b3";
kuai_object.innerHTML="";
}
2.create_num_color(kuai_object,num) 该函数用于给小方块上色,以及添加数字 参数 kuai_object:小方块对象 num:所要填的数字 (这里数字最大至4096)
function create_num_color(kuai_object,num){
switch (num){
case 2://ok
kuai_object.style.backgroundColor="#efe5db";
kuai_object.innerHTML="2";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 4:
kuai_object.style.backgroundColor="#eddcbe";
kuai_object.innerHTML="4";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 8://ok
kuai_object.style.backgroundColor="#f3b079";
kuai_object.innerHTML="8";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 16://ok
kuai_object.style.backgroundColor="#f7925c";
kuai_object.innerHTML="16";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 32://ok
kuai_object.style.backgroundColor="#f57656";
kuai_object.innerHTML="32";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 64://ok
kuai_object.style.backgroundColor="#f4522c";
kuai_object.innerHTML="64";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 128://ok
kuai_object.style.backgroundColor="#edce71";
kuai_object.innerHTML="128";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 256://ok
kuai_object.style.backgroundColor="#e6d151";
kuai_object.innerHTML="256";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 512://ok
kuai_object.style.backgroundColor="#1200ff";
kuai_object.innerHTML="512";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 1024:
kuai_object.style.backgroundColor="#cc00ff";
kuai_object.innerHTML="1024";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 2048:
kuai_object.style.backgroundColor="#000000";
kuai_object.innerHTML="2048";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 4096:
kuai_object.style.backgroundColor="#000000";
kuai_object.innerHTML="4096";
kuai_object.style.color="#e504f3";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
}
}
随机生成‘2’,‘4’函数(suiji())
实现步骤 1.检查16个小方块即遍历二维数组a,遇到空的记下它的坐标。、
var flag_x=[];
var flag_y=[];
2.如果flag_x.length不为0,在flag_x[]和flag_y[]中随机取同位置的两个数 flag_x[random],flag_y[random] 这就确定了一个随机的、空的小方块a[flag_x[random]][flag_y[random]] 然后再随机选要填的数字‘2’或‘4’ 最后调用小方块处理函数create_num_color(kuai_object,num)即可
function suiji(){
var flag_x=[];
var flag_y=[];
for (var i=0;i<4 ;i++ )
{
for (var j=0;j<4 ;j++ )
{
if(document.getElementById(a[i][j]).innerHTML==""){
flag_x.push(i);
flag_y.push(j);
}
}
}
if(flag_x.length!=0){
var r=[2,4];
var num_object=Math.floor(Math.random() * flag_x.length);
var object=document.getElementById(a[flag_x[num_object]][flag_y[num_object]]);
create_num_color(object,r[Math.floor(Math.random() * 2)]);
return;
}
}
更新得分函数update_score(num)
参数 num:分数
function update_score(num){
document.getElementById("caidan").innerHTML=num;
}
键盘监听事件
document.onkeypress=f_key;
f_key函数
function f_key(){
if(window.event.keyCode==97){
var num=0;
zero();
num=remove_zuo(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==119){
var num=0;
zero();
num=remove_shang(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==100){
var num=0;
zero();
num=remove_you(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==115){
var num=0;
zero();
num=remove_xia(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
}
按下向上键
这里摘出按下向上键后的处理过程进行说明,其它三个方向原理相同
if(window.event.keyCode==119){
var num=0;
zero();
num=remove_shang(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
整体思路就是通过dfs遍历二维数组,然后在遍历过程中进行相应操作
dfs函数remove_shang(x,y,n)
参数 x:二维数组a的横坐标 y:二维数组a的纵坐标 n:记录递归调用次数,每次加1(便于判断是否应该生成随机数) 终止条件:x>3 结束循环,返回递归次数。
if(x>3){
return n;
}
第一行,也就是x=0,无论小方块是否为空都不用管,直接下一个。 因为就算第一行有小方块有数字,也不用移,向上没空间了。
因为dfs的遍历是自左向右逐行进行的,所以 x=x+parseInt((y+1)/4) y=(y+1)%4 parseInt为取整函数 
if(x==0){
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
(下面说的每一行小方块指的y都是相同的,即同一列) 当x!=0&&x<=3时获取如下对象(因为,第一行没有上一行) var two=document.getElementById(a[x][y]); var one=document.getElementById(a[x-1][y]); 当前行元素不为空,上一行元素为空,则调用create_num_color(kuai_object,num)函数 kuai_object传上一行的,即one num传当前行的数字,即parseInt(two.innerHTML); 然后x-1,检查上一行,确保如下情况,数字移到最上面 这样就完成了上移  代码
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_shang(x-1,y,n);
}
当当前行不为空,上一行也不为空,且两个数字相等并xx[x-1][y]==0(后面介绍作用)时 清空当前行数字,上一行数字乘2
create_num_color(one,2*two.innerHTML);
qingkong(two);
更新分数
score=score+2*two.innerHTML;
update_score(score);
并将
xx数组作用
xx[x-1][y]置为1,说明,这个位置上已经是加过的和,防止在遍历后面行时出现二次相加,什么是二次相加?就是出现如下情况 假如有如下情景  加一次  不然直接就这样了  所以每次做移动前都要保持xx数组全为0 通过zero()函数将其置为0
返回值n
这里再说一下返回n的用处 当出现这种情况时,再按上键是没反应的(没相加也没移动),也就是递归调用17次后直接结束 (16次检查每个格子+1次x>3退出)  当然返回n==17也是两种情况,一种就是如上情况,还有空格子,一种就是没有空格子(游戏结束)
if(window.event.keyCode==119){
var num=0;
zero();
num=remove_shang(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
check_over()函数
function check_over(){
var jishu=0;
for (var i=0;i<4 ;i++ )
{
for (var j=0;j<4 ;j++ )
{
if(document.getElementById(a[i][j]).innerHTML!=""){
jishu=jishu+1;
}
}
}
if(jishu==16){
alert("游戏结束!");
}
}
remove_shang(x,y,num)函数
function remove_shang(x,y,n){
n++;
if(x==0){
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
if(x>3){
return n;
}else{
var two=document.getElementById(a[x][y]);
var one=document.getElementById(a[x-1][y]);
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_shang(x-1,y,n);
}
if(one.innerHTML!=""&&two.innerHTML!=""){
if(one.innerHTML==two.innerHTML&&xx[x-1][y]==0){
xx[x-1][y]=1;
score=score+2*two.innerHTML;
update_score(score);
create_num_color(one,2*two.innerHTML);
qingkong(two);
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
}
}
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
其它方向移动
其它方向的移动与向上的原理相同,所以我们只需要将其它小方块的id按照从左向右,从上至下存储即可,这样就都转换成了向上移。
var a=[['a1','a2','a3','a4'],['b1','b2','b3','b4'],['c1','c2','c3','c4'],['d1','d2','d3','d4']];
var b=[['d4','d3','d2','d1'],['c4','c3','c2','c1'],['b4','b3','b2','b1'],['a4','a3','a2','a1']];
var c=[['d1','c1','b1','a1'],['d2','c2','b2','a2'],['d3','c3','b3','a3'],['d4','c4','b4','a4']];
var d=[['a4','b4','c4','d4'],['a3','b3','c3','d3'],['a2','b2','c2','d2'],['a1','b1','c1','d1']];
源码(复制粘贴即可用)
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title> New Document </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
</head>
<style type="text/css">
*{
margin:0;
padding:0;
}
#zuiwaibian{
width:400px;
height:600px;
background-color:#fce6ce;
}
#caidan{
width:100%;
height:150px;
margin-top:6px;
background-color:#a68c71;
font-size:50px;
text-align:center;
line-height:150px;
color:#fff;
}
#youxi{
width:400px;
height:400px;
background:#c0af9d;
margin-top:10px;
}
.model{
float:left;
margin-left:8px;
margin-top:8px;
width:90px;
height:90px;
background-color:#cdc1b3;
border-radius:5px;
}
</style>
<body>
<div id="zuiwaibian">
<div id="caidan">0</div>
<div id="youxi">
<div id="a1" class="model"></div>
<div id="a2" class="model"></div>
<div id="a3" class="model"></div>
<div id="a4" class="model"></div>
<div id="b1" class="model"></div>
<div id="b2" class="model"></div>
<div id="b3" class="model"></div>
<div id="b4" class="model"></div>
<div id="c1" class="model"></div>
<div id="c2" class="model"></div>
<div id="c3" class="model"></div>
<div id="c4" class="model"></div>
<div id="d1" class="model"></div>
<div id="d2" class="model"></div>
<div id="d3" class="model"></div>
<div id="d4" class="model"></div>
</div>
</div>
</body>
</html>
<!--js代码-->
<!--定义数据以及函数-->
<script type="text/javascript">
var score=0;
var a=[['a1','a2','a3','a4'],['b1','b2','b3','b4'],['c1','c2','c3','c4'],['d1','d2','d3','d4']];
var b=[['d4','d3','d2','d1'],['c4','c3','c2','c1'],['b4','b3','b2','b1'],['a4','a3','a2','a1']];
var c=[['d1','c1','b1','a1'],['d2','c2','b2','a2'],['d3','c3','b3','a3'],['d4','c4','b4','a4']];
var d=[['a4','b4','c4','d4'],['a3','b3','c3','d3'],['a2','b2','c2','d2'],['a1','b1','c1','d1']];
var xx=[[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]];
function create_num_color(kuai_object,num){
switch (num){
case 2://ok
kuai_object.style.backgroundColor="#efe5db";
kuai_object.innerHTML="2";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 4:
kuai_object.style.backgroundColor="#eddcbe";
kuai_object.innerHTML="4";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 8://ok
kuai_object.style.backgroundColor="#f3b079";
kuai_object.innerHTML="8";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="65px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 16://ok
kuai_object.style.backgroundColor="#f7925c";
kuai_object.innerHTML="16";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 32://ok
kuai_object.style.backgroundColor="#f57656";
kuai_object.innerHTML="32";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 64://ok
kuai_object.style.backgroundColor="#f4522c";
kuai_object.innerHTML="64";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="60px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 128://ok
kuai_object.style.backgroundColor="#edce71";
kuai_object.innerHTML="128";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 256://ok
kuai_object.style.backgroundColor="#e6d151";
kuai_object.innerHTML="256";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 512://ok
kuai_object.style.backgroundColor="#1200ff";
kuai_object.innerHTML="512";
kuai_object.style.color="#7a6d65";
kuai_object.style.fontSize="45px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 1024:
kuai_object.style.backgroundColor="#cc00ff";
kuai_object.innerHTML="1024";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 2048:
kuai_object.style.backgroundColor="#000000";
kuai_object.innerHTML="2048";
kuai_object.style.color="#ffffff";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
case 4096:
kuai_object.style.backgroundColor="#000000";
kuai_object.innerHTML="4096";
kuai_object.style.color="#e504f3";
kuai_object.style.fontSize="35px";
kuai_object.style.textAlign="center";
kuai_object.style.lineHeight="98px";
break;
}
}
function suiji(){
var flag_x=[];
var flag_y=[];
for (var i=0;i<4 ;i++ )
{
for (var j=0;j<4 ;j++ )
{
if(document.getElementById(a[i][j]).innerHTML==""){
flag_x.push(i);
flag_y.push(j);
}
}
}
if(flag_x.length!=0){
var r=[2,4];
var num_object=Math.floor(Math.random() * flag_x.length);
var object=document.getElementById(a[flag_x[num_object]][flag_y[num_object]]);
create_num_color(object,r[Math.floor(Math.random() * 2)]);
return;
}
}
function qingkong(kuai_object){
kuai_object.style.backgroundColor="#cdc1b3";
kuai_object.innerHTML="";
}
function update_score(num){
document.getElementById("caidan").innerHTML=num;
}
function remove_zuo(x,y,n){
n++;
if(x==0){
return remove_zuo(x+parseInt((y+1)/4),(y+1)%4,n);
}
if(x>3){
return n;
}else{
var two=document.getElementById(c[x][y]);
var one=document.getElementById(c[x-1][y]);
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_zuo(x-1,y,n);
}
if(one.innerHTML!=""&&two.innerHTML!=""){
if(one.innerHTML==two.innerHTML&&xx[x-1][y]==0){
xx[x-1][y]=1;
score=score+2*two.innerHTML;
update_score(score);
create_num_color(one,2*two.innerHTML);
qingkong(two);
return remove_zuo(x+parseInt((y+1)/4),(y+1)%4,n);
}
}
}
return remove_zuo(x+parseInt((y+1)/4),(y+1)%4,n);
}
function remove_shang(x,y,n){
n++;
if(x==0){
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
if(x>3){
return n;
}else{
var two=document.getElementById(a[x][y]);
var one=document.getElementById(a[x-1][y]);
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_shang(x-1,y,n);
}
if(one.innerHTML!=""&&two.innerHTML!=""){
if(one.innerHTML==two.innerHTML&&xx[x-1][y]==0){
xx[x-1][y]=1;
score=score+2*two.innerHTML;
update_score(score);
create_num_color(one,2*two.innerHTML);
qingkong(two);
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
}
}
return remove_shang(x+parseInt((y+1)/4),(y+1)%4,n);
}
function remove_you(x,y,n){
n++;
if(x==0){
return remove_you(x+parseInt((y+1)/4),(y+1)%4,n);
}
if(x>3){
return n;
}else{
var two=document.getElementById(d[x][y]);
var one=document.getElementById(d[x-1][y]);
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_you(x-1,y,n);
}
if(one.innerHTML!=""&&two.innerHTML!=""){
if(one.innerHTML==two.innerHTML&&xx[x-1][y]==0){
xx[x-1][y]=1;
score=score+2*two.innerHTML;
update_score(score);
create_num_color(one,2*two.innerHTML);
qingkong(two);
return remove_you(x+parseInt((y+1)/4),(y+1)%4,n);
}
}
}
return remove_you(x+parseInt((y+1)/4),(y+1)%4,n);
}
function remove_xia(x,y,n){
n++;
if(x==0){
return remove_xia(x+parseInt((y+1)/4),(y+1)%4,n);
}
if(x>3){
return n;
}else{
var two=document.getElementById(b[x][y]);
var one=document.getElementById(b[x-1][y]);
if(one.innerHTML==""&&two.innerHTML!=""){
create_num_color(one,parseInt(two.innerHTML));
qingkong(two);
return remove_xia(x-1,y,n);
}
if(one.innerHTML!=""&&two.innerHTML!=""){
if(one.innerHTML==two.innerHTML&&xx[x-1][y]==0){
xx[x-1][y]=1;
score=score+2*two.innerHTML;
update_score(score);
create_num_color(one,2*two.innerHTML);
qingkong(two);
return remove_xia(x+parseInt((y+1)/4),(y+1)%4,n);
}
}
}
return remove_xia(x+parseInt((y+1)/4),(y+1)%4,n);
}
function zero(){
for (var i=0;i<4 ;i++ )
{
for (var j=0;j<4 ;j++ )
{
xx[i][j]=0;
}
}
}
function check_over(){
var jishu=0;
for (var i=0;i<4 ;i++ )
{
for (var j=0;j<4 ;j++ )
{
if(document.getElementById(a[i][j]).innerHTML!=""){
jishu=jishu+1;
}
}
}
if(jishu==16){
alert("游戏结束!");
}
}
function f_key(){
if(window.event.keyCode==97){
var num=0;
zero();
num=remove_zuo(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==119){
var num=0;
zero();
num=remove_shang(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==100){
var num=0;
zero();
num=remove_you(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
if(window.event.keyCode==115){
var num=0;
zero();
num=remove_xia(0,0,num)
if(num!=17){
suiji();
}else{
check_over();
}
}
}
document.onkeypress=f_key;
</script>
<script type="text/javascript">
window.onload=function(){
suiji();
}
</script>
<script type="text/javascript">
</script>
|