2048小游戏项目总结

2048小游戏项目总结


最近有在玩2048,所以写了个2048的代码
话不多说,先上截图和代码

游戏截图
在这里插入图片描述
HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1.0, user-scalable=no">
	<title>2048小游戏</title>
	<link rel="stylesheet" href="css/normalize.css">
	<link rel="stylesheet" href="css/style.css">
	<script src="js/2048.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
	
	<div class="score">
		<div class="current-score">
			<strong>当前得分:</strong>
			<span id="current-score">0</span>
		</div>
		<div class="most-score">
			<strong>最高得分:</strong>
			<span id="most-score">0</span>
		</div>
	</div>
	<div class="contain">
		<div class="line-1">
			
			<div id="cd-11" class="n0"></div>
			<div id="cd-12" class="n0"></div>
			<div id="cd-13" class="n0"></div>
			<div id="cd-14" class="n0"></div>
		</div>
		<div class="line-2">
			
			<div id="cd-21" class="n0"></div>
			<div id="cd-22" class="n0"></div>
			<div id="cd-23" class="n0"></div>
			<div id="cd-24" class="n0"></div>
		</div>
		<div class="line-3">
			
			<div id="cd-31"class="n0"></div>
			<div id="cd-32"class="n0"></div>
			<div id="cd-33"class="n0"></div>
			<div id="cd-34"class="n0"></div>
		</div>
		<div class="line-4">
			
			<div id="cd-41" class="n0"></div>
			<div id="cd-42" class="n0"></div>
			<div id="cd-43" class="n0"></div>
			<div id="cd-44" class="n0"></div>
		</div>
	</div>
	<div class="controlButton">
		<input type="button" value="开始" id="start" onclick="start()">
		<input type="button" value="重新开始" id="newstart" disabled="disabled" onclick="newstart()">
	</div>
	<div class="information">
		<p>温馨提示:该游戏在PC端通过键盘上的方向键进行,在移动端通过滑动屏幕进行!
		</p>
	</div>
	<div class="number">
		<div class="line-1">
			<div id="cd-00" class="n2 n0">2</div>
			<div id="cd-01" class="n4 n0">4</div>
			<div id="cd-02" class="n8 n0">8</div>
			<div id="cd-03" class="n16 n0">16</div>
		</div>
		<div class="line-2">
			<div id="cd-10" class="n32 n0">32</div>
			<div id="cd-11" class="n64 n0">64</div>
			<div id="cd-12" class="n128 n0">128</div>
			<div id="cd-13" class="n256 n0">256</div>
		</div>
		<div class="line-3">
			<div id="cd-20" class="n512 n0">512</div>
			<div id="cd-21" class="n1024 n0">1024</div>
			<div id="cd-22" class="n2048 n0">2048</div>
			<div id="cd-23" class="n4096 n0">4096</div>
		</div>
		<div class="line-4">
			<div id="cd-30" class="n8192 n0">8192</div>
			<div id="cd-31" class="n0"></div>
			<div id="cd-32" class="n0"></div>
			<div id="cd-33" class="n0"></div>
		</div>
	</div>
</body>
</html>

HTML代码中存在下方的代码是为了禁止该网页在移动端进行缩放操作(当然,安卓系统下的UC浏览器貌似不起作用)。其中,initial-scale表示初始缩放比例,maximum-scale表示允许最大的缩放比例,minimum-scale表示允许最小的缩放比例,user-scalable表示是否可手动缩放。一行代码解决手机浏览器禁止缩放的问题。

<meta name="viewport" content="initial-scale=1, width=device-width, maximum-scale=1, minimum-scale=1.0, user-scalable=no">

CSS代码

.information {
	position: fixed;
	top: 30px;
	left: 50px;
}
.information p {
	color: red;
	width: 200px;
	line-height: 24px;
}
.score {
	font-size: 20px;
	margin: 30px auto 0; 
	width: 400px;
	height: 8px;
}
.current-score,.most-score{
	width: 200px;
	float: left;
	text-align: center;
}
.current-score span {
	color: blue;
}
.most-score span {
	color: red;
}
.contain {
	clear: both;
	height: 400px;
	width: 400px;
	background-color: #ccc;
	margin: 40px auto 20px;
	padding: 5px;
}
.n0,.n2,.n4,.n8,.n16,.n32,.n64,.n128,.n256,.n512,.n1024,.n2048,.n4096,.n8192 {
	height: 90px;
	width: 90px;
	background-color: gray;
	float: left;
	margin: 5px;
	font-size: 30px;
	text-align: center;
	line-height: 90px;
	color: #fff;
}
.controlButton {
	width: 400px;
	height: 50px;
	margin: 0 auto;
	text-align: center;
}
#newstart {
	color: graytext;
}
/*设置每个数字的样式*/
.n2{background-color: #fff;color: black;}
.n4{background-color: #ede0c8;color: black;}
.n8{background-color: #f2b179;}
.n16{background-color: #f59563;}
.n32{background-color: #f67c5f;}
.n64{background-color: #f65e3b;}
.n128{background-color: #edcf72;}
.n256{background-color: #fec716;}
.n512{background-color: #ddc190;}
.n1024{background-color: #9f8963;}
.n2048{background-color: #cc8100;}
.n4096{background-color: #5d4d32;}
.n8192{background-color: #93c;}
.number{display: none;}
/*当屏幕宽度小于1080px时的样式*/
@media screen and (max-width: 1080px) {
	.information{
		position: relative;
		top: 0;
		left: 0;
		text-align: center;
	}
	.information p {
		width: auto;
	}
}

通过上方的css代码对游戏界面进行布局和配色,其中代码块

@media screen and (max-width: 1080px) {
………………
}

是响应式布局的css写法,表示当屏幕的宽度小于1080px时相应的样式

JS代码

var score,mostScore;
var c=[];
//初始化二维数组,0号,5号单位置为0
for(var i=0;i<=5;i++){
	c[i]=[];
	for(var j=0;j<=5;j++)
		c[i][j] = 0;
}
function start() {
	controlButton();//控制按钮的可用性
	score = mostScore = 0;//初始化分数
	//开始时随机生成两块
	randomDemo();
	randomDemo();
}

function newstart() {
	if (confirm("确定要重新开始游戏吗?") == true) {
		// 将二维数组及当前分数清零
		for(var i=0;i<=5;i++){
			c[i]=[];
			for(var j=0;j<=5;j++){
				c[i][j] = 0;
				if(i>0&&j>0&&i<5&&j<5){
					document.getElementById("cd-"+i+j).innerText = "";
					document.getElementById("cd-"+i+j).className = "n0";
				}
			}
		}
		score = 0;
		document.getElementById("current-score").innerText = score;
		//重新随机生成两块
		randomDemo();
		randomDemo();
	}
}
//按钮的控制方法
function controlButton() {
	var s1 = document.getElementById("start");
	var ns = document.getElementById("newstart");
	//禁用开始按钮
	s1.setAttribute("disabled" ,"disabled");
	s1.style.color="graytext";
	//解禁重新开始按钮
	ns.removeAttribute("disabled");
	ns.style.color="inherit";
}
//随机生成方块
function randomDemo() {
	var randomnum,i,j;
	//随机产生坐标
	i = Math.floor(Math.random() * 4)+1;
	j = Math.floor(Math.random() * 4)+1;
	//生成新的方块
	if(c[i][j]==0){
		randomnum = Math.random()<0.75 ? 2:4;
		c[i][j] = randomnum;
		document.getElementById("cd-"+i+j).innerText = randomnum;
		document.getElementById("cd-"+i+j).className = "n"+randomnum;
		return true;
	}
	else return randomDemo();
}
//界面的更新方法
function update() {
	for(var i=1;i<=4;i++){
		for(var j=1;j<=4;j++){
			var pre = document.getElementById("cd-"+i+j);//当前对象
			if(c[i][j] != 0){
				pre.className = "n"+c[i][j];
				pre.innerText = c[i][j];
			}else {
				pre.className = "n0";
				pre.innerText = "";
			}
		}
	}
}
//判断是否可以左移
function canLeft() {
	for(var i=1;i<=4;i++){
		if(c[i][2]+c[i][3]+c[i][4]!=0){
			if(c[i][1]==0)
				return true;
			else if(c[i][2]==0)
				return true;
			else if(c[i][2]==c[i][1]||
					c[i][2]==c[i][3]||
					(c[i][4]!=0&&c[i][3]==c[i][4])||
					(c[i][3]==0&&c[i][4])!=0)
				return true;
		}	
	}
	return false;
}
//判断是否可以右移
function canRight() {
	for(var i=1;i<=4;i++){
		if(c[i][2]+c[i][3]+c[i][1]!=0){
			if(c[i][4]==0)
				return true;
			else if(c[i][3]==0)
				return true;
			else if(c[i][3]==c[i][4]||
					c[i][3]==c[i][2]||
					(c[i][1]!=0&&c[i][1]==c[i][2])||
					(c[i][2]==0&&c[i][1])!=0)
				return true;
		}
	}
	return false;
}
//判断是否可以上移
function canUp() {
	for(var i=1;i<=4;i++){
		if(c[2][i]+c[3][i]+c[4][i]!=0){
			if(c[1][i]==0)
				return true;
			else if(c[2][i]==0)
				return true;
			else if(c[3][i]==0 && c[4][i]!=0)
				return true;
			else if((c[3][i]!=0&&c[3][i]==c[4][i])||
					c[3][i]==c[2][i]||
					(c[1][i]==c[2][i]))
				return true;
		}
	}
	return false;
}
//判断是否可以下移
function canDown() {
	for(var i=1;i<=4;i++){
		if(c[2][i]+c[3][i]+c[1][i]!=0){
			if(c[4][i]==0)
				return true;
			else if(c[3][i]==0)
				return true;
			else if(c[2][i]==0 && c[1][i]!=0)
				return true;
			else if((c[1][i]!=0&&c[1][i]==c[2][i])||
					c[3][i]==c[2][i]||
					(c[3][i]==c[4][i]))
				return true;
		}		
	}
	return false;
}
//左移方法
function left() {
	var l = canLeft();
	for(var i=1;i<=4;i++){
		//1.先将一行内的元素以0为界排列好,如2020排成2200
		for(var j=4;j>1;j--){
			if(c[i][j-1] == 0){
				c[i][j-1]+=c[i][j];
				k=j;
				while(k<5){
					c[i][k] = c[i][k+1];
					k++;
				}
			}
		}
		//2.合并相同且相邻的方块并更新数组
		for(var j=1;j<4;j++){
			if(c[i][j]==c[i][j+1] && c[i][j]!=0){
				c[i][j]*=2;
				switch(c[i][j]){
					case 512:alert("恭喜您合并成512方块!");break;
					case 1024:alert("恭喜您合并成1024方块!");break;
					case 2048:alert("恭喜您合并成2048方块!");break;
					case 4096:alert("恭喜您合并成4096方块!");break;
					case 8192:alert("恭喜您合并成8192方块!");
				}
				score+=c[i][j];//更新分数
				document.getElementById("current-score").innerText = score;
				//判断是否破纪录
				if(score>mostScore){
					mostScore = score;
					document.getElementById("most-score").innerText = score;
				}
				k=j+1;
				//左移数组
				while(k<5){
					c[i][k] = c[i][k+1];
					k++;
				}
			}
		}
	}
	update();//更新界面
	//判断是否可以左移,能则生成方块
	if(l) randomDemo();
}
//右移方法
function right() {
	var r = canRight();
	for(var i=1;i<=4;i++){
		//1.先将一行内的元素以0为界排列好,如2020排成0022
		for(var j=1;j<4;j++){
			if(c[i][j+1] == 0){
				c[i][j+1]+=c[i][j];
				k=j;
				while(k>0){
					c[i][k] = c[i][k-1];
					k--;
				}
			}
		}
		//2.合并相同且相邻的方块并更新数组
		for(var j=4;j>0;j--){
			if(c[i][j]==c[i][j-1] && c[i][j]!=0){
				c[i][j]*=2;
				switch(c[i][j]){
					case 512:alert("恭喜您合并成512方块!");break;
					case 1024:alert("恭喜您合并成1024方块!");break;
					case 2048:alert("恭喜您合并成2048方块!");break;
					case 4096:alert("恭喜您合并成4096方块!");break;
					case 8192:alert("恭喜您合并成8192方块!");
				}
				score+=c[i][j];//更新分数
				document.getElementById("current-score").innerText = score;
				//判断是否破纪录
				if(score>mostScore){
					mostScore = score;
					document.getElementById("most-score").innerText = score;
				}
				k=j-1;
				//数组右移
				while(k>0){
					c[i][k] = c[i][k-1];
					k--;
				}
			}
		}
	}
	update();//更新界面
	//判断是否可以右移,能则生成方块
	if(r) randomDemo();
}
//上移方法
function up() {
	var u = canUp();
	for(var j=1;j<=4;j++){
		//1.先将一列内的元素以0为界排列好,如2202排成2220
		for(var i=4;i>1;i--){
			if(c[i-1][j] == 0){
				c[i-1][j]+=c[i][j];
				k=i;
				while(k<5){
					c[k][j] = c[k+1][j];
					k++;
				}
			}
		}
		//2.合并相同且相邻的方块并更新数组
		for(var i=1;i<4;i++){
			if(c[i][j]==c[i+1][j] && c[i][j]!=0){
				c[i][j]*=2;
				switch(c[i][j]){
					case 512:alert("恭喜您合并成512方块!");break;
					case 1024:alert("恭喜您合并成1024方块!");break;
					case 2048:alert("恭喜您合并成2048方块!");break;
					case 4096:alert("恭喜您合并成4096方块!");break;
					case 8192:alert("恭喜您合并成8192方块!");
				}
				score+=c[i][j];//更新分数
				document.getElementById("current-score").innerText = score;
				//判断是否破纪录
				if(score>mostScore){
					mostScore = score;
					document.getElementById("most-score").innerText = score;
				}
				k=i+1;
				//数组上移
				while(k<5){
					c[k][j] = c[k+1][j];
					k++;
				}
			}
		}
	}
	update();//更新界面
	//判断是否可以上移,能则生成方块
	if(u) randomDemo();
}
//下移方法
function down() {
	var d = canDown();
	for(var j=1;j<=4;j++){
		//1.先将一列内的元素以0为界排列好,如2202排成0222
		for(var i=1;i<4;i++){
			if(c[i+1][j] == 0){
				c[i+1][j]=c[i][j];
				k=i;
				while(k>0){
					c[k][j] = c[k-1][j];
					k--;
				}
			}
		}
		//2.合并相同且相邻的方块并更新数组
		for(var i=4;i>0;i--){
			if(c[i][j]==c[i-1][j] && c[i][j]!=0){
				c[i][j]*=2;
				switch(c[i][j]){
					case 512:alert("恭喜您合并成512方块!");break;
					case 1024:alert("恭喜您合并成1024方块!");break;
					case 2048:alert("恭喜您合并成2048方块!");break;
					case 4096:alert("恭喜您合并成4096方块!");break;
					case 8192:alert("恭喜您合并成8192方块!");
				}
				score+=c[i][j];//更新分数
				document.getElementById("current-score").innerText = score;
				//判断是否破纪录
				if(score>mostScore){
					mostScore = score;
					document.getElementById("most-score").innerText = score;
				}
				k=i-1;
				//数组下移
				while(k>0){
					c[k][j] = c[k-1][j];
					k--;
				}
			}
		}
	}
	update();//更新界面
	//判断是否可以下移,能则生成方块
	if(d) randomDemo();
}
//判断游戏是否结束,即上下左右都不能移动
function over() {
	if((!(canLeft()||canRight()||canUp()||canDown()))&&
		document.getElementById("start").disabled)
		alert("游戏结束,本局分数为"+score+",游戏的最高分数为"+mostScore);
}
//键盘事件的第一种写法
window.addEventListener("keydown",function(e) {
	if(e.keyCode == 37){
		e.preventDefault();
		left();
		over();
	}
	if(e.keyCode == 38){
		e.preventDefault();
		up();
		over();
	}
	if(e.keyCode == 39){
		e.preventDefault();
		right();
		over();
	}
	if(e.keyCode == 40){
		e.preventDefault();
		down();
		over();
	}
});
/*
//键盘事件的第二种写法
window.onkeydown = function (e) {
	if(e.keyCode == 37){
		e.preventDefault();
		left();
		over();
	}
	if(e.keyCode == 38){
		e.preventDefault();
		up();
		over();
	}
	if(e.keyCode == 39){
		e.preventDefault();
		right();
		over();
	}
	if(e.keyCode == 40){
		e.preventDefault();
		down();
		over();
	}
}*/
//监听移动设备的触摸开始
document.addEventListener('touchstart',function (event) {
    startx = event.touches[0].pageX;
    starty = event.touches[0].pageY;
});
//监听移动设备的触摸移动
document.addEventListener('touchmove',function (evnet) {
    event.preventDefault();
});
//监听移动设备的触摸结束
document.addEventListener('touchend',function (event) {
    endx = event.changedTouches[0].pageX;
    endy = event.changedTouches[0].pageY;

    var x = endx - startx;
    var y = endy - starty;
    //x
    if(Math.abs(x) > Math.abs(y)){
        if(x > 0){
            //向右移动
            if (canRight()){
                right();
            }
           	 over();
        } else {
            //向左移动
            if (canLeft()){
                left();
            }
           	 over();
        }
    } else if(Math.abs(x) < Math.abs(y)) { //y
        if (y < 0){
            //向上移动
            if (canUp()){
                up();
            }
           	 over();
        } else {  //向下移动
            if (canDown()){
                down();
            }
           	 over();
        }
    }

});

JS中,用一个二维数组来存放每个方块的数值,其中适当地留空了某些空间以备数组的移动和变化

  • JS随机函数
代码 含义
Math.random() 表示返回【0,1)之间的随机数
Math.floor(Math.random()*10) 表示返回0至9之间的整数
Math.floor(Math.random()*11) 表示返回0至10之间的整数
  • 合并方块的思路
    (1)当想要往某个方向移动时,先判断是否可往该方向移动,可移动时先将一行(列)中的数组元素以0位界排列好,如当下移时,某列的元素分别是2202,则排列成0222;当右移时,某行的元素分别是2020,则排成0022。不可移动时不生成也不合并不移动方块。
    (2)合并相同且相邻的方块并更新数组、分数和界面。
    (3)判断往某个方向移动时是否可以再生成新的方块

  • 移动端JS触摸touch

(1) 4个监听事件

事件 触发时刻
touchstart 触摸屏幕上时触发
touchmove 触摸屏幕中滑动时触发
touchend 离开屏幕时触发
touchcancel 系统取消触摸事件的时候触发

(2) 监听触摸后触摸事件会实现一个event对象,这个对象里面包括3个触摸函数列表。

函数 触发函数列表
touches 屏幕上所有手指列表
targetTouches 在当前DOM标签上手指的列表
changedTouches 涉及当前事件的手指的列表

(3)触摸函数的属性,用于获取坐标

属性 获取的坐标
clientX 触摸目标在浏览器中的x坐标
clientY 触摸目标在浏览器中的y坐标
identifier 标识触摸的唯一ID
pageX 触摸目标在当前DOM中的x坐标
pageY 触摸目标在当前DOM中的y坐标
screenX 触摸目标在屏幕中的x坐标
screenY 触摸目标在屏幕中的y坐标
target 触摸的DOM节点目标

Ending
在JS中我的算法思路不是很灵活也不是很高效,但基本还是实现了2048游戏的规则。另外还有一些操作也运用的比较陌生。倘若在阅读的过程中大家有发现错误的或者有更好的建议的,欢迎向我提出,我将感激不尽。

发布了1 篇原创文章 · 获赞 0 · 访问量 324

猜你喜欢

转载自blog.csdn.net/weixin_44849651/article/details/104092835