原生JS 实现2048小游戏详解

HTML部分

2048小游戏
	<div  class="score-style">Score:<span id="scorespan1">0</span></div>		
	<div class="gameover-background-stly" id="gameoverid">
		<div  class="gameover-stly">
			 <p>
			GAME OVER!				
			<div>Score:<span id="scorespan2">0</span></div>		
			<a href="javascript:game.start()">Try  aging</a>
		     </p> 
		</div>
    </div>
<div id="gamestar">
	<!--第一行-->
	<div id="c00" class="cell"></div>
	<div id="c01" class="cell"></div>
	<div id="c02" class="cell"></div>
	<div id="c03" class="cell"></div>
	<!--第二行-->
	<div id="c10" class="cell"></div>
	<div id="c11" class="cell"></div>
	<div id="c12" class="cell"></div>
	<div id="c13" class="cell"></div>
	<!--第三行-->
	<div id="c20" class="cell"></div>
	<div id="c21" class="cell"></div>
	<div id="c22" class="cell"></div>
	<div id="c23" class="cell"></div>
	<!--第四行-->
	<div id="c30" class="cell"></div>
	<div id="c31" class="cell"></div>
	<div id="c32" class="cell"></div>
	<div id="c33" class="cell"></div>
</div>

	<script src="js/new_file.js">
		
	</script>
	
</body>
 </html>

CSS部分

*{
	margin: 0;
	box-sizing: border-box;	    /*初始化*/
}
a{
	text-decoration: none;	
}
#gamestar{ 
	/*margin: 0 auto;*/
	width: 480px;
	height: 480px;
	border-radius:10px;
	background-color: #ccc0b3;
	position: absolute;
	top: 50%;
	left: 50%;
	margin-top: -240px;
	margin-left: -240px;
}
.cell{
	width: 100px;
	height: 100px;
	text-align: center;
	line-height: 100px;
	font-size: 40px;
	background-color: #bbada0;  
	position: absolute;	
	
}
/*每行间距*/
div[id^="c0" ]{top: 16px;}
div[id^="c1" ]{top: 132px;}	
div[id^="c2" ]{top: 248px;}	
div[id^="c3" ]{top: 364px;}
/*每列间距*/
div[id$="0"]{left: 16px;}
div[id$="1"]{left: 132px;}
div[id$="2"]{left: 248px;}
div[id$="3"]{left: 364px;}
.score-style{
	font-size:45px ;
	width: 480px;
	height: 60px;
	text-align: center;
	line-height: 60px;
	font-weight: bold;
	font-family: "微软雅黑";
	color: #776e65;
	/*background-color: #;*/
	position: absolute;
	left: 50%;
	top: 15%;
	margin-left: -240px;	
}



.gameover-stly{
	text-align: center;
	width: 240px;
	height: 264px;
	border: 1px solid #F65E3B;
	background-color: #FFFFFF;
	border-radius:5px ;
	font-family: "微软雅黑";
    font-size: 40px; 
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -100px;
    margin-top: -132px;	
    z-index: 1;
    box-shadow: #F59563 5px 5px 20px;
}


.gameover-background-stly{
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background-color: rgb(55,55,55,0.5); 	
	display: none;  /*隐藏样式,如果不加持续刷新时会闪出样式*/
	
}

.n2{background-color:#eee3da}
.n4{background-color:#ede0c8}
.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}
.n2048{background-color:#09c}
.n4096{background-color:#a6c}
.n8192{background-color:#93c}
.n8,.n16,.n32,.n64,.n128,.n256,.n512,.n1024,.n2048,.n4096,.n8192{color:#fff}
.n1024,.n2048,.n4096,.n8192{font-size:40px}

js部分

var game={
	date:null,      //二维数组初始化
	RN:4,          /*行数*/
	CN:4,          //每行的列数
	state:1,      //保存游戏中的状态
	RUNNING:1,    //正在运行中
	GAMEOVER:0,   //结束游戏
	Scoeraddtion:0, //保存的分数
	start(){		
	
	 //清空遮罩层
	 document.getElementById("gameoverid").style.display="none";
	//清空分数
	this.Scoeraddtion=0;
	//游戏状态设为运行中
	 this.state=this.RUNNING;
	 
	//新建空数组
	this.date=[];//初始状态
	//遍历数组
	for(var i=0;i<this.RN;i++){
		//将行数组变为空数组
		this.date[i]=[];
		for(var j=0;j<this.CN;j++){
			this.date[i][j]=0;
	  }			
	}
	
	this.randomnum()  		//调用方法,产生随机位置的2或4,生产两个随机数
	this.randomnum()
	game.updateView()          //更新视图
	
	 console.log(this.date)
	document.onkeydown=function(event){
			switch (event.keyCode){
				//左移动
				case 37:
				game.moveLeft();	
					break;
				//上移动
				case 38:
				game.moveTop()							
					break;
				//右移动
				case 39:
				game.moveRight()
					break;
				//下移动
				case 40:
				game.moveDown()	
					break;
			  }            
	          document.getElementById("scorespan1").innerHTML=game.Scoeraddtion;  //页面输出分数
	       }		       		          
        },   
        
        //判断是否结束游戏
	isgameOver(){			
	 	for(var r=0;r<this.date.length;r++){			   //遍历数组		
				for(var c=0;c<this.date[r].length;c++){
					if(this.date[r][c]==0){return false;}     // 当数组中有0是,输出 false   
					if((c<this.CN-1)&&(this.date[r][c]==this.date[r][c+1])){   //当0~2列与1~3列分别比较
						return false;
					}
					if((r<this.RN-1)&&(this.date[r][c]==this.date[r+1][c])){//当0~2行与1~3行分别比较,
						return false;
					  }
		       }	//如果全部不满足则输出ture,输出的结果用于判断结束弹框弹出
		  }
	 	return true;		 	
	},
	
	//获取一个随机位置的随机数
  randomnum(){	  	   		   	 
      while(true){	            
      	var sjr=Math.floor( Math.random()*this.RN);  //产生随机数的行位置
        var sjc=Math.floor( Math.random()*this.CN);  //产生随机数的列位置
   		if(this.date[sjr][sjc]==0){	   			
   			this.date[sjr][sjc]=Math.random()>0.2?2:4; //随机位置产生2和4的几率
   			break;   		
   	   }   		
   	}	 	          	 		 	
 },
 
 //更新运算过后的视图给出样式和结果
 updateView(){	 
 	//给数组中不同数字添加样式
 	for(var i=0;i<this.CN;i++){
 		for(var j=0;j<this.RN;j++){
			var	n=this.date[i][j];	
			var  div=document.getElementById("c"+i+j);
			if(n !=0 ){
				div.innerHTML= n;
				div.className="cell n"+n; //为出现在数组中的数字添加样式
			}else{
				div.innerHTML="";          //数字为0,样式不变
				div.className="cell";
			}
	      }					
 	  }	 
 	  
 	  //根据运算过后的结果,输出分数,调用方法 this.isgameOver()给出的结果判断是否结束游戏,给出结束游戏的视图
 	  document.getElementById("scorespan1").innerHTML= this.Scoeraddtion;  //运算过后的分数累加,页面输出分数,
 	  this.isgameOver();
 	  this.state=this.isgameOver()?this.GAMEOVER:this.RUNNING;    //判断当前的游戏状态,并赋值给this.state
 	  var div=document.getElementById("gameoverid");              //绑定htmlID用于给出结束后的样式
 	  if(this.state==this.GAMEOVER){                              //如果当前的游戏状态为结束状态,
 	  	div.style.display="block";                               //调出游戏结束后的页面
 	  	document.getElementById("scorespan2").innerHTML=game.Scoeraddtion;   //结束时的总分	 	  	
 	  }else{
 	  	div.style.display="none";               //否则结束页面隐藏
 	  }	 	  
 },
   
moveLeft(){//左移所有行		
	// 为数组拍照保存到before中,用于之后比较是否有过移动,为是否添加随机数做准备
	var befor=String(this.date);
	// r从0开始,到<RN结束 循环每一行
	for(var r=0;r<this.RN;r++){
	         this.moveLeftInRow(r);// 左移第r行  moveLeftInRow(r) ---- 可以单独完成一件事情  反复被使用     
	     }
	      var after=String(this.date); // 为数组拍照保存到after中
	      if(after!=befor) {        // 如果after!=before   表示data中的数据有变化
	         this.randomnum()                     // 生成随机数添加到data中去   randomNum()
	         this.updateView()         // 更新页面 updateView()		
	      }   		        			   
      },
      
moveLeftInRow(r){//左移第r行
	// c从0开始,到<CN-1
	//console.log(this.date)//测试
	for(var c=0;c<this.CN-1;c++){    //循环遍历第r行中的c列,将r行中的c列的每个元素进行比较判断,
	var nextc=this.getNextInRow(r,c);  //c列中从下标0开始第一个不为0的数下标,用于判断和运算
	   //console.log(nextc)  //测试
		if(nextc==-1){                   //说明r行中从下标为0开始的所有都为0,所以不做运算
			break;
		}else if(this.date[r][c]==0){    //当r行下标为0的数也为0,则将这个r数组中不为0的数交换赋值,
			 this.date[r][c] = this.date[r][nextc];
		     this.date[r][nextc]=0;
		     		  c--;                      //赋值完成后将此时的赋值的数保留原位置,用于与下一位直接判断和运算,减少一次循环
		}else if(this.date[r][c]== this.date[r][nextc]){		//两数相等的时候做相加	       
		           this.date[r][c]*=2;
		           this.date[r][nextc]=0;	
		           this.Scoeraddtion+=this.date[r][c];//根据规则,将相加出来的分数进行存储,用于输出页面展示
	 }		    			
	}		
   },
 
getNextInRow(r,c) {//查找r行c列下一个不为0的位置
	   for(var i=c+1;i<this.CN;i++){	//r行下标为0 的数,左移动时并不需要与左边的数做比较运算,所以从下标为1开始遍历r行	   	
	     if(this.date[r][i]!=0){      //不为0数的下标
	      return  i;	   
	     }	
	    }return -1;                  //全部遍历结束了返回-1,则说明r行这一行都为0(下标为0的数不在遍历范围内所以除外)
	// i从c+1开始,到<CN结束	
		// 如果i位置的值不为0, return  i
	// 循环结束
	// 返回 -1 表示全部为0 的位置		
   },
   
   //右移
   moveRight(){                     //右移所有行
   	 // 移动之前拍照  before
   	var befor=String(this.date);
   	 //console.log(befor)//测试

	for(var r=0;r<this.RN;r++){                   // r从0开始,到RN结束
		this.moveRightInRow(r)		             // 每一行向右移动 调用函数moveRightInRow(r)
	                                             // 循环结束
	}
	var after=String(this.date);                  // 为数组结束后拍照保存到after中      
	//console.log(after)//测试
	if(after!=befor) {                                // 如果after!=before   表示data中的数据有变化
	         this.randomnum()                        // 生成随机数添加到data中去   randomNum()
	         this.updateView()                       // 更新页面 updateView()		
	        }   
},
moveRightInRow(r){//右移第r行
	//console.log(this.date)//测试
	for(var c=this.CN-1;c>0;c--){                      // c从倒数第二个开始,到>0结束    反向遍历r行每一列
		var prevc=this.getPrevcInRow(r,c); // 得到位置prevc  调用函数 getPrevcInRow(r,c)
		//console.log(prevc)//测试
		if(prevc==-1){                                  // 查询r行c列的前一个不为0的位置 那么此行就是全部为0 
			break;
	   }else{
		if(this.date[r][c]==0){
			 this.date[r][c] = this.date[r][prevc];
		     this.date[r][prevc]=0;
		     		  c++;   
		}else if(this.date[r][c]== this.date[r][prevc]){			      
		           this.date[r][c]*=2;
		           this.date[r][prevc]=0;
		           this.Scoeraddtion=this.date[r][c]+this.Scoeraddtion;
		}
	    			
	}
	}	
		
},
getPrevcInRow(r,c){//获取r行c列前一个不为0值的位置
	for(var i=c-1;i>=0;i--){  // i从CN-1开始,到>=0结束   反向遍历
		if(this.date[r][i]!=0){
		 return  i;	   
	     }	
	    }return -1;					
		// 如果r行i列位置的值不等于0   返回i
	// 循环结束
	// 返回-1表示全部为0 的位置
	},
			
	//上移所有,遍历所有列,并判断算法是否有改变数组,刷新做过算法之后的视图,给出随机数
	moveTop(){
	var befor=String(this.date);	
		for(var c=0;c<this.CN;c++){
			this.moveTopCol(c);
		}
		var after=String(this.date); 
		if(after!=befor) {                                // 如果after!=before   表示data中的数据有变化
	         this.randomnum()                        // 生成随机数添加到data中去   randomNum()
	         this.updateView()                       // 更新页面 updateView()		
	 }   
},
							
	//上移一列,根据不为0下标位置给出不同情况的算法
	  moveTopCol(c){		 
	    for(var r=0;r<this.RN-1;r++){
	      var Next=this.moveTopNextCol(r,c);	 // 将r行不为0 的数的下标调用赋值用于判断计算
	      //console.log(Next)
	          if(Next==-1){  //说明全部为0,不做计算调整
	       	 break;		       	
	       }else{
	       	if(this.date[r][c]==0){ //当c位置的数为0的时候,将第一个不为0的数赋值给c位置的数,c保持原位置,
	       		this.date[r][c]=this.date[Next][c]
	       		this.date[Next][c]=0;
	       		r--;
	       	}else if(this.date[r][c]==this.date[Next][c]){	 //	当第一个数字与c位置数相等则两数相加       				       		
	       		this.date[r][c]*=2;
	       		this.date[Next][c]=0;
	       		this.Scoeraddtion=this.date[r][c]+this.Scoeraddtion;
	       	}		       			       	
	       }
	    }				
	},	
	//输出从r开始,不为0的下标,用于判断情况作出算法  r行,c列
	moveTopNextCol(r,c){			
		for(var i=r+1;i<this.RN;i++){   
			if(this.date[i][c]!=0){
				 return  i;	   
	     }	
	    }return -1;	  //说明全部为0
	  },
	
	//下移,遍历每一列
	moveDown(){
		 var befor=String(this.date);
		 for(var c=0;c<this.CN;c++){
		 	this.moveDowninCol(c)
		   }
		var alter=String(this.date)
		if(alter!=befor){
			this.randomnum()                        // 生成随机数添加到data中去   randomNum()
	        this.updateView()                       // 更新页面 updateView()	
		}
		
	},
	//下移,上移的反向遍历,c列r行的排序计算
	moveDowninCol(c){
		for(var r=this.RN-1;r>=0;r--){
			var  Down= this.moveDownNextCols(r,c);	  
			if(Down==-1){
				break;
			}else{
				if(this.date[r][c]==0){
					this.date[r][c]=this.date[Down][c]
					this.date[Down][c]=0;
					r++
					
				}else if(this.date[r][c]==this.date[Down][c]){
					this.date[r][c]*=2
					this.date[Down][c]=0;
					this.Scoeraddtion=this.date[r][c]+this.Scoeraddtion;
				}
			}			
		  }
		
		},			
		//下移,从RN-1开始反向查找不为0的下标
	moveDownNextCols(r,c){
		for(var i=r-1;i>=0;i--){
			if(this.date[i][c]!=0){
				return  i;	   
	     }	
	    }return -1;				
		}
	}

 game.start()
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值