2023-04-14 使用纯JS实现一个2048小游戏

文章目录

      • 一.实现思路
        • 1.2048的逻辑
        • 2.移动操作的过程中会有三种情况
      • 二.代码部分:分为初始化部分和移动部分
        • 1.初始化部分
          • 1.1.生成第一个方块:
          • 1.2.生成第二个方块:
        • 2.移动过程部分:
      • 三.实现代码
        • 1.HTML结构
        • 2.CSS部分
        • 3.JS部分
      • 四.效果

一.实现思路

1.2048的逻辑

一共有16个格子,开局5个随机格子上生成带数字的方块,2或者4
通过控制方向来使原有的方块移动并产生新的方块

2.移动操作的过程中会有三种情况

  • 方块移动的方向没有其他方块
  • 方块移动的方向有其他方块,但数字不同
  • 方块移动的方向有其他方块,且数字相同

二.代码部分:分为初始化部分和移动部分

1.初始化部分

新建一个4X4二维数组,存储16个方块的值,
分两个步骤生成第一个和第二个方块

1.1.生成第一个方块:

用0-15的随机数代表第几个数组元素上面生成第一个方块块的值(值为2或者4),其余的值为0
具体生成2或者4,设置为随机,其中2的概率高一些,4的概率低一些,比如:
0-10之间,若随机值为0,生成2,否则生成4,比例:10:1

1.2.生成第二个方块:
  • 为什么第二个方块(以及其他所有后续的方块)不能使用上述方法?
    因为如果两次生成的随机数一样,那么就会出现bug:
    同一位置产生两个值

  • 第二个方块如何生成?
    先获取16个格子中,空格的个数,也就是二维数组中0的个数
    以空格的个数作为循环的次数

2.移动过程部分:

移动过程是根据输入的方向来控制方块的移动的

  • 首先获取输入的状态,即玩家操作的上下左右键
  • 其次,移动的控制逻辑是:
遍历二维数组,找到每一个方块(以左移动为例)
由于第一列无需移动,只从每一行的第二个方块开始判断
(若第一个方块不存在:交换值,并让交换的原位置的值清0
若当前方块的紧邻左方块和当前方块,两者的值相同,那么左边的值变为原来的两倍,当前方块的值清0
若当前方块的紧邻左方块看和当前方块,两者的值不同,不作处理,不移动

三.实现代码

1.HTML结构

快捷键:div#all>div.cell#n0$@0*4+div.cell#n1$@0*4+div.cell#n2$@0*4+div.cell#n3$@0*4
代码:2048.html


<html>
<head>
	<meta charset="UTF-8">
	<title>2048小游戏title>
	<link rel="stylesheet" href="2048.css" />
head>
<body>
	
	<p class="header">SCORE: <span id="score01">span>p>
	
	
	<div id="all">
		
		<div class="cell"  id="n00">div>
		<div class="cell"  id="n01">div>
		<div class="cell"  id="n02">div>
		<div class="cell"  id="n03">div>
		
		<div class="cell"  id="n10">div>
		<div class="cell"  id="n11">div>
		<div class="cell"  id="n12">div>
		<div class="cell"  id="n13">div>
		
		<div class="cell"  id="n20">div>
		<div class="cell"  id="n21">div>
		<div class="cell"  id="n22">div>
		<div class="cell"  id="n23">div>
		
		<div class="cell"  id="n30">div>
		<div class="cell"  id="n31">div>
		<div class="cell"  id="n32">div>
		<div class="cell"  id="n33">div>
	div>
	
	<div id="gameover" >
		<p>
			GAME OVER
			<br />
			SCORE:<span id="score02">span>
			<br />
			<a onclick="typeonce()">TYPE AGAINa>
		p>
		
	div>
	<script type="text/javascript" src="2048.js" >script>
body>
html>

2.CSS部分

2038.css

*{
  font-family: arial;
  /*	user-select: none;*/
  font-weight: bold;
  }
  
  .header{
  width: 480px;
  font-size:40px ;
  margin: 60px auto 5px auto;
  }
  
  #score01{
  color: #F00;
  }
  
  #all{
  width: 480px;
  height: 480px;
  background-color: #bbada0;
  margin: 0 auto;
  border-radius: 20px;
  }
  
  .cell{
  width: 100px;
  height: 100px;
  background-color: #ccc0b3;;
  border-radius: 10px;
  text-align: center;
  line-height: 100px;
  font-size: 40px;
  color: #fff;
  float: left;
  margin: 16px 0px 0px 16px;
  
  }
  
  .n2{
  background-color:#eee3da;
  color:#776e65;
  }
  .n4{
  background-color:#ede0c8;
  color:#776e65;
  }
  .n8{
  background-color:#f2b179;
  }
  .n16{
  background-color:#f59563;
  }
  .n32{
  background-color:#f67c5f;
  }
  .n64{
  background-color:#f65e3b;
  }
  .n128{
  background-color:#edcf72;
  }
  .n256{
  background-color:#edcc61;
  }
  .n512{
  background-color:#9c0;
  }
  .n1024{
  background-color:#33b5e5;
  font-size:40px;
  }
  .n2048{
  background-color:#09c;
  font-size:40px;
  }
  .n4096{
  background-color:#a6c;
  font-size:40px;
  }
  .n8192{
  background-color:#93c;
  font-size:40px;
  }
  
  #gameover{
  position: absolute;
  background-color: rgba(0,0,0,0.2);
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  font-size: 40px;
  display: none;
  }
  
  #gameover p{
  background-color: #fff;
  width: 300px;
  height: 200px;
  border-radius: 10px;
  line-height: 66.66px;
  text-align: center;
  position: absolute;
  left: 50%;
  top: 50%;
  margin-left: -150px;
  margin-top: -150px;
  }
  
  #gameover p a{
  padding: 10px;
  text-decoration: none;
  background-color: #9f8d77;
  color: #fff;
  border-radius: 10px;
  cursor: pointer;
  }
  

3.JS部分

/******思路*******/

/*一.游戏环节:创建game对象*/
//属性:data,score,gamerunning,gameover,status
//普通方法:start,randomNum,dataView,isGameOver
//移动的方法:moveLeft,moveRight,moveUp,moveDown
//移动方法中处理每一行数据的方法:
//moveLeftinRow,moveLeftNum,moveRightinRow,moveRightNum
//moveUpinRow,moveUpNum,moveDowninRow,moveDownNum

// var game={};

/*二.监听鼠标按下事件,并调用game对象中的移动方法*/
//如果监听到上下左右对应的ASCII码,就触发相应的上下左右game移动方法

// document.οnkeydοwn=function(){}

/*三.游戏开始时,调用game对象中的start方法*/

// game.start();

/*四.点击再来一次*/
//隐藏#gameover元素,并跳转回2048.html

// function typeonce(){}

/*一.游戏环节:创建game对象*/
//属性:data,score,gamerunning,gameover,status
//普通方法:start,randomNum,dataView,isGameOver
//移动的方法:moveLeft,moveRight,moveUp,moveDown
//移动方法中处理每一行数据的方法:
//moveLeftinRow,moveLeftNum,moveRightinRow,moveRightNum
//moveUpinRow,moveUpNum,moveDowninRow,moveDownNum
var game={
	/*****对象属性*****/
	data:[],//二维数组:用于存储2048的值
	score:0,//游戏分数:开始时分数为0
	gamerunning:1,//游戏开始时:游戏状态为1
	gameover:0,//游戏结束时:游戏状态为0
	status:1,//个人状态与游戏状态相对应,默认为1
	/*****普通对象方法*****/
	//1.start方法:游戏开始时还原所有(把game属性还原)
	start:function(){
		this.data=[//二维数组的值都清零
			[0,0,0,0],
			[0,0,0,0],
			[0,0,0,0],
			[0,0,0,0]
		];
		this.score=0;//分数也清零
		this.status=this.gamerunning;//状态码=游戏开始的状态码(也就是1)
		// 调用对象方法randomNum,用于获取随机数,调用五次
		for(var i=0;i<5;i++){
			this.randomNum();
		}
		// 调用对象方法dataView,用于更新视图
		this.dataView();
	},
	//2.randomNum方法:随机赋值,让随机的数组元素获得2或4作为其值
	randomNum:function(){
		while(1){//是否方块存在空白位置
			var row=Math.floor(Math.random()*4);//获取一个0~3的随机整数,代表第几行
			var col=Math.floor(Math.random()*4);//获取一个0~3的随机整数,代表第几列
			//判断:如果二维数组data的某个元素的值为0,就让其其值变为2或4
			if(this.data[row][col]==0){
				var num=Math.random()>.2?2:4;//num的值只能是2或者4,概率分别是80%和20%
				this.data[row][col]=num;
				break;
			}
		}
	},
	//3.dataView方法:更新视图
	dataView:function(){
		//思路:数组元素的值不为0时,把其值赋给html结构中对应的div中
		for(var row=0;row<4;row++){
			for(var col=0;col<4;col++){
				//拼接成div#n23这样的字符串
				var div=document.getElementById("n"+row+col);
				if(this.data[row][col]!=0){//数组元素的值不为0
					div.innerHTML=this.data[row][col];//
2
div.className="cell n"+this.data[row][col];//赋予新类名:n23,即
}else{//数组元素的值为0 div.innerHTML="";//不显示任何内容 div.className="cell"; } } } //更新分数 document.getElementById("score01")=this.score; //判断游戏是否结束 //游戏结束时弹出gameover框,并显示最终分数 if(this.status==this.gameover){ document.getElementById("gameover").style.display="block"; document.getElementById("score02")=this.score; }else{ document.getElementById("gameover").style.display="none"; } }, //4.isGameOver方法:判断游戏是否结束 isGameOver:function(){ //思路:游戏结束就返回一个true,未结束就返回一个return false; //未结束的几种情况(返回false):1.有空白;2.左右有相同;3.上下有相同 for(var row=0;row<4;row++){ for(var col=0;col<4;col++){ if (this.data[row][col] == 0) { //有空白的时候 return false; } if (col < 3) { //判断左右是否有相同,只需要判断到第三个格子即可 if (this.data[row][col] == this.data[row][col + 1]) { return false; } } if (row < 3) { //判断上下是否有相同,只需要判断到第三个格子即可 if (this.data[row][col] == this.data[row + 1][col]) { return false; } } } } return true; } }, /*****移动的对象方法*****/ /* 向左移动的思路: - 遍历二维数组data,第一列无需移动,只从第二个方块开始 - 若第一个方块不存在:赋值(交换),并让原位置的值清零 - 若当前方块的紧邻左方块和当前方块两者值相同,左方块倍增,右方块清零 - 若当前方块和紧邻左方块和当前方块两者值不同,不作处理 */ /**1.左移**/ //1.3.moveLeft方法:向左移动 moveLeft:function(){ var before=String(this.data); for(var row=0;row<4;row++){ this.moveLeftinRow(row); } var after=String(this.data); if(before!=after){ this.randomNum(); if(this.isGameOver()) this.status=this.gameover; this.dataView(); } }, //1.2.moveLeftinRow方法:处理向左移动时每一行的数据 moveLeftinRow:function(row){ for(var col=0;col<3;col++){ var nextCol=this.moveLeftNum(row,col); if(nextCol!=-1){ if(this.data[row][col]==0){ this.data[row][col]=this.data[row][nextCol]; this.data[row][nextCol]=0; col--; }else if(this.data[row][col]==this.data[row][nextCol]){ this.data[row][col]*=2; this.data[row][nextCol]=0; this.score+=this.data[row][col]; } }else{ break; } } }, //1.1.moveLeftNum方法:获取符合条件的列数 moveLeftNum:function(row,col){ for(var i=col+1;i<4;i++){ if(this.data[row][i]!=0) return i; else return -1; } }, /**2.右移**/ //2.3.moveRight方法:向右移动 moveRight:function(){ // 移动前:把二维数组data转化成字符串 var before=String(this.data); // 调用对象方法moveRightinRow:用于处理每一行的函数 for(var row=0;row<4;row++){ this.moveRightinRow(row); } // 移动后:把二维数组转化成字符串 var after=String(this.data); // 判断:移动前后的data是否不一样 if(before!=after){ this.randomNum();//调用对象方法randomNum:生成2或者4的随机数 if(this.isGameOver) this.status=this.gameover;//若游戏结束,状态值为结束状态 this.dataView();//调用对象方法dataView:更新视图 } }, //2.2.moveRightinRow方法:处理向右移动时每一行的数据 moveRightinRow:function(row){ for(var col=3;col>=0;col--){ // 调用对象方法moveRightNum:获取符合条件的列数i var nextCol=this.moveRightNum(row,col);//赋值:把符合条件的col赋给nextCol if(nextCol!=-1){//若有值,说明需要进行左右值交换 if(this.data[row][col]==0){//若当前数组元素的值为0 this.data[row][col]=this.data[row][nextCol];//给当前元素赋值 this.data[row][nextCol]=0;//让下一元素赋值后清零 col++;//再次从最后边的数进行循环 }else if(this.data[row][col]==this.data[row][nextCol]){//若左右元素有相同的值 this.data[row][col]*=2;//当前元素的值倍增 this.data[row][nextCol]=0;//下一元素的值清零 this.score+=this.data[row][col];//分数叠加 } }else{//若没有值,跳出循环 break; } } }, //2.1.moveRightNum方法:获取符合条件的列数 //形参:row-行数,col-列数 moveRightNum:function(row,col){ //循环并获取前面的数据 for(var i=col-1;i>=0;i--){//最右边一列不移动,从第col-i列开始循环 //判断:前面是否找到数字 if(this.data[row][i]!=0) return i;//返回下标 else return-1;//返回-1 } }, /**3.上移**/ //3.3.moveUp方法:向上移动 moveUp:function(){ var before=String(this.data); for(var col=0;col<4;col++){ this.moveUpinCol(col); } var after=String(this.data); if(before!=after){ this.randomNum(); if(this.isGameOver()) this.status=this.gameover; this.dataView(); } }, //3.2.moveUpinCol方法:处理所有行的每一列数据 moveUpinCol:function(col){ for(var row=0;row<3;row++){ var nextRow=this.moveUpNum(row,col); if(nextRow!=-1){ if(this.data[row][col]==0){ this.data[row][col]=this.data[nextRow][col]; this.data[nextRow][col]=0; row--; }else if(this.data[row][col]==this.data[nextRow][col]){ this.data[row][col]*=2; this.data[nextRow][col]=0; this.score+=this.data[row][col]; } }else{ break; } } }, //3.1.moveUpNum:获取符合条件的列数 moveUpNum:function(row,col){ for(var i=row+1;i<4;i++){ if(this.data[i][col]!=0) return i; else return 0; } }, /**4.下移**/ //4.3.moveDown方法:向下移动 moveDown:function(){ var before=String(this.data); for(var col=0;col<4;col++){ this.moveDowninCol(col); } var after=String(this.data); if(before!=after){ this.randomNum(); if(this.isGameOver()) this.status=this.gameover; this.dataView(); } }, //4.2.moveDowninCol方法:处理每一列所有行数的数据 moveDowninCol:function(col){ for(var row=3;row>=0;row--){ var nextRow=this.moveDownNum(row,col); if(nextRow!=-1){ if(this.data[row][col]==0){ this.data[row][col]=this.data[nextRow][col]; this.data[nextRow][col]=0; row++; }else if(this.data[row][col]==this.data[nextRow][col]){ this.data[row][col]*=2; this.data[nextRow][col]=0; this.score+=this.data[row][col]; } }else{ break; } } }, //4.1.moveDownNum方法:获取符合条件的行数 moveDownNum:function(row,col){ // 如果当前元素不为空,就返回i for(var i=row-1;i>=0;i--){ if(this.data[i][col]!=0) return i; else return -1; } } }; /*二.监听鼠标按下事件,并调用game对象中的移动方法*/ //如果监听到上下左右对应的ASCII码,就触发相应的上下左右game移动方法 document.onkeydown=function(event){ if(event.keyCode==65) game.moveLeft(); if(event.keyCode==87) game.moveUp(); if(event.keyCode==68) game.moveRight(); if(event.keyCode==83) game.moveDown(); } /*三.游戏开始时,调用game对象中的start方法*/ game.start(); /*四.点击再来一次时*/ //隐藏#gameover元素,并跳转回2048.html function typeonce(){ document.getElementById("gameover").style.display="none"; window.location.href="2048.html"; }

四.效果

2023-04-14 使用纯JS实现一个2048小游戏_第1张图片

你可能感兴趣的:(项目与应用,js,javascript,前端,css,游戏,2048)