JavaScript实现2048小游戏,我终于赢了一把

JavaScript实现2048小游戏

作者简介

作者名:编程界明世隐
简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!

系列目录

1. JavaScript 贪吃蛇游戏
2. JavaScript 俄罗斯方块
3. JavaScript 扫雷小游戏
4. JavaScript 网红太空人表盘

效果图

JavaScript实现2048小游戏,我终于赢了一把_第1张图片

实现思路

  1. 编写页面和画布代码。
  2. 绘制背景。
  3. 绘制好全部卡片。
  4. 随机生成一个卡片(2或者4)。
  5. 键盘事件监听(上、下、左、右键监听)。
  6. 根据键盘的方向,处理数字的移动合并。
  7. 加入成功、失败判定。
  8. 处理其他收尾工作。

代码实现

编写页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2048</title>
    <style>
        #box{
           width:370px;
           height:370px;
           position:absolute;
           margin:0 auto;
           left:0;
           right:0;
           top:1px;
           bottom:0;
       }

       .rebutton{
        position: absolute;
        top:370px;
        left:38%;
       }
       </style>
</head>
<body>
    <div id='box'></div>
    <button onclick="restart()" class='rebutton'>重开</button>
</body>
<script src="js/util.js"></script>
<script src="js/2048.js"></script>
<script type="text/javascript">

   </script>
</html>

添加画布

在2048.js编写代码

  1. 创建函数
function G2048(){
	this.renderArr=[];//渲染数组
	this.cards=initCardArray();
	//游戏标记
	this.flag='start';
}
//初始化数组
function initCardArray(){
	var cards = new Array();
	for (var i = 0; i < 4; i++) {
		cards[i] = new Array();
		for (var j = 0; j < 4; j++) {
			//cards[i][j]=null;
		}
	}
	return cards;
}
  1. 初始化和绘制背景代码(在2048.js中编写)
//初始化
    G2048.prototype.init=function(el,musicObj){
        if(!el) return ;
		this.el=el;
		var canvas = document.createElement('canvas');//创建画布
		canvas.style.cssText="background:white;";
		var W = canvas.width = 370; //设置宽度
		var H = canvas.height = 370;//设置高度
		
		el.appendChild(canvas);//添加到指定的dom对象中
		this.ctx = canvas.getContext('2d');
		
		this.draw();
	}
    //绘制入口
    G2048.prototype.draw=function(){
		//创建背景
		this.drawGB();

	    //渲染到页面上
		this.render();

	}

	//创建背景
	G2048.prototype.drawGB=function(){
		var bg = new _.Rect({x:0,y:0,width:364,height:364,fill:true,fillStyle:'#428853'});
		this.renderArr.push(bg);
	}

	//渲染图形
	G2048.prototype.render=function(){
		var context=this.ctx;
		this.clearCanvas();	
		_.each(this.renderArr,function(item){
			item && item.render(context);
		});
	}
	//清洗画布
	G2048.prototype.clearCanvas=function() {
		this.ctx.clearRect(0,0,parseInt(this.w),parseInt(this.h));
	}
  1. 在页面代码中加入以下 js 代码
var box = document.getElementById('box');
g2048.init(box);

JavaScript实现2048小游戏,我终于赢了一把_第2张图片
运行效果:
JavaScript实现2048小游戏,我终于赢了一把_第3张图片

绘制好全部卡片

  1. 创建Card
//定义Card
function Card(i,j){
	this.i=i;//下标i
	this.j=j;//下标j
	this.x=0;// x坐标
	this.y=0;// y坐标
	this.h=80;//高
	this.w=80;//宽
	this.start=10;//偏移量(固定值)
	this.num=0;//显示数字
	this.merge=false;//当前是否被合并过,如果合并了,则不能继续合并,针对当前轮
	//初始化创建
	this.obj = this.init();
	//创建显示数字对象
	this.numText = this.initNumText();
} 
//初始创建
Card.prototype.init=function(){
	return new _.Rect({x:this.x,y:this.y,width:this.w,height:this.h,fill:true});
}
//根据i j计算x y坐标
Card.prototype.cal=function(){
	this.x = this.start + this.j*this.w + (this.j+1)*5;
	this.y = this.start + this.i*this.h + (this.i+1)*5;
	//更新给obj
	this.obj.x=this.x;
	this.obj.y=this.y;
	//设置填充颜色
	this.obj.fillStyle=this.getColor();

	//更新文字的位置
	this.numText.x = this.x+40;
	this.numText.y = this.y+55;
	this.numText.text=this.num;
}
//初始化显示数字对象
Card.prototype.initNumText=function(){
	var font = "34px 思源宋体";
	var fillStyle = "#7D4E33";
	return new _.Text({x:this.x,y:this.y+50,text:this.num,fill:true,textAlign:'center',font:font,fillStyle:fillStyle});
}
//获取color
Card.prototype.getColor=function(){
	var color;
	//根据num设定颜色
	switch (this.num) {
	case 2:
		color = "#EEF4EA";
		break;
	case 4:
		color = "#DEECC8";
		break;
	case 8:
		color = "#AED582";
		break;
	case 16:
		color = "#8EC94B";
		break;
	case 32:
		color = "#6F9430";
		break;
	case 64:
		color = "#4CAE7C";
		break;
	case 128:
		color = "#3CB490";
		break;
	case 256:
		color = "#2D8278";
		break;
	case 512:
		color = "#09611A";
		break;
	case 1024:
		color = "#F2B179";
		break;
	case 2048:
		color = "#DFB900";
		break;

	default://默认颜色
		color = "#5C9775";
		break;
	}
	
	return color;
}

Card.prototype.render=function(context){
	//计算坐标等
	this.cal();
	//执行绘制
	this.obj.render(context);
	//是否绘制文字的处理
	if(this.num!=0){
		this.numText.render(context);
	}
}

}
  1. 创建卡片
	//创建卡片
	G2048.prototype.drawCard=function(){
		var that=this;
		var card;
		for (var i = 0; i < 4; i++) {
			for (var j = 0; j < 4; j++) {
				card = new Card(i,j);
				that.cards[i][j]=card;
				that.renderArr.push(card);
			}
		}
	}
  1. 调用绘制代码
    JavaScript实现2048小游戏,我终于赢了一把_第4张图片
    运行效果:
    JavaScript实现2048小游戏,我终于赢了一把_第5张图片
  2. 修改一下卡片的默认数字
    JavaScript实现2048小游戏,我终于赢了一把_第6张图片

JavaScript实现2048小游戏,我终于赢了一把_第7张图片

随机生成一个卡片,2或者4

  1. 先把Card中 num 默认改成0
  2. 因为2跟4出现的比例是1:4,所以采用随机出1-5的数字,当是1的时候就表示,当得到2、3、4、5的时候就表示要出现数字2.
  3. 随机获取i,j 就可以得到卡片的位置,割接i,j取到card实例,如果卡片没有数字,就表示可以,否则就递归继续取,取到为止。
  4. 把刚才取到的数字,设置到card实例对象中就好了。

代码如下:

//随机创建一个卡片
	G2048.prototype.createRandomNumber=function(){
		var num = 0;
		var index = _.getRandom(1,6);//这样取出来的就是1-5 之间的随机数
		//因为2和4出现的概率是1比4,所以如果index是1,则创建数字4,否则创建数字2(1被随机出来的概率就是1/5,而其他就是4/5 就是1:4的关系)
		console.log('index==='+index)
		if(index==1){
			num = 4;
		}else {
			num = 2;
		}
		//判断如果格子已经满了,则不再获取,退出
		if(this.cardFull()){
			return ;
		}
		//获取随机卡片,不为空的
		var card = this.getRandomCard();
		//给card对象设置数字
		if(card!=null){
			card.num=num;
		}
	}
	//获取随机卡片,不为空的
	G2048.prototype.getRandomCard=function(){
		var i = _.getRandom(0,4);
		var j = _.getRandom(0,4);
		var card = this.cards[i][j];
		if(card.num==0){//如果是空白的卡片,则找到了,直接返回
			return card;
		}
		//没找到空白的,就递归,继续寻找
		return this.getRandomCard();
	}
	//判断格子满了
	G2048.prototype.cardFull=function() {
		var card;
		for (var i = 0; i < 4; i++) {
			for (var j = 0; j < 4; j++) {
				card = this.cards[i][j];
				if(card.num==0){//有一个为空,则没满
					return false;
				}
			}
		}		
		return true;
	}

draw方法中调用,表示打开游戏默认一个数字
JavaScript实现2048小游戏,我终于赢了一把_第8张图片
运行效果:
JavaScript实现2048小游戏,我终于赢了一把_第9张图片

加入键盘事件

同样要在draw方法中调用哦

	//按键的控制
	G2048.prototype.control=function(){
		var that=this;
		global.addEventListener('keydown',function(e){
			console.log(that.flag)
			if(that.flag!='start') return ;
			var dir;
			switch (e.keyCode){
				case 87://w
				case 38://上
					dir=1;//上移动
					break;
				case 68://d
				case 39://右
					dir=2;//右移动
					break;
				case 83://s
				case 40://下
					dir=3;//下移动
					break;
				case 65://a
				case 37://左
					dir=4;//左移动
					break;
			}
			//卡片移动的方法
			that.moveCard(dir);
		});
	}
  1. 加入移动逻辑处理代码
//卡片移动的方法
	G2048.prototype.moveCard=function(dir) {
		//将卡片清理一遍,因为每轮移动会设定合并标记,需重置
		this.clearCard();
		
		if(dir==1){//向上移动
			this.moveCardTop(true);
		}else if(dir==2){//向右移动
			this.moveCardRight(true);
		}else if(dir==3){//向下移动
			this.moveCardBottom(true);
		}else if(dir==4){//向左移动
			this.moveCardLeft(true);
		}
		//移动后要创建新的卡片
		this.createRandomNumber();
		//重绘
		this.render();
		//判断游戏是否结束
		this.gameOverOrNot();
	}

	//将卡片清理一遍,因为每轮移动会设定合并标记,需重置
	G2048.prototype.clearCard=function() {
		var card;
		for (var i = 0; i < 4; i++) {//i从1开始,因为i=0不需要移动
			for (var j = 0; j < 4; j++) {
				card = this.cards[i][j];
				card.merge=false;
			}
		}
	}
  1. 加入上下左右处理逻辑
//向上移动
	G2048.prototype.moveCardTop=function(bool) {
		var res = false;
		var card;
		for (var i = 1; i < 4; i++) {//i从1开始,因为i=0不需要移动
			for (var j = 0; j < 4; j++) {
				card = this.cards[i][j];
				if(card.num!=0){//只要卡片不为空,要移动
					if(card.moveTop(this.cards,bool)){//向上移动
						res = true;//有一个为移动或者合并了,则res为true
					}
				}
			}
		}
		return res;
	}
	//向右移动
	G2048.prototype.moveCardRight=function(bool) {
		var res = false;
		var card;
		for (var i = 0; i < 4; i++) {
			for (var j = 3; j >=0 ; j--) {//j从COLS-1开始,从最右边开始移动递减
				card = this.cards[i][j];
				if(card.num!=0){//只要卡片不为空,要移动
					if(card.moveRight(this.cards,bool)){//向右移动
						res = true;//有一个为移动或者合并了,则res为true
					}
				}
			}
		}
		return res;
	}
	
	//向下移动
	G2048.prototype.moveCardBottom=function(bool) {
		var res = false;
		var card;
		for (var i = 3; i >=0; i--) {//i从ROWS-1开始,往下递减移动
			for (var j = 0; j < 4; j++) {
				card = this.cards[i][j];
				if(card.num!=0){//只要卡片不为空,要移动
					if(card.moveBottom(this.cards,bool)){//下移动
						res = true;//有一个为移动或者合并了,则res为true
					}
				}
			}
		}
		return res;
	}
	
	//向左移动
	G2048.prototype.moveCardLeft=function(bool) {
		var res = false;
		var card;
		for (var i = 0; i < 4; i++) {
			for (var j = 1; j < 4 ; j++) {//j从1开始,从最左边开始移动
				card = this.cards[i][j];
				if(card.num!=0){//只要卡片不为空,要移动
					if(card.moveLeft(this.cards,bool)){//向左移动
						res = true;//有一个为移动或者合并了,则res为true
					}
				}
			}
		}
		return res;
	}
  1. 在Card中加入向上移动的处理逻辑
  1. 从第2行开始移动,因为第一行不需要移动。
  2. 只要卡片的数字不是0,就表示要移动。
  3. 根据 i-1 可以获取到上一个卡片,如果上一个卡片是空,则把当前卡片交换上去,并且递归,因为可能要继续往上移动。
  4. 如果当前卡片与上一个卡片是相同数字的,则要合并。
  5. 以上两种都不是,则不做操作。
//卡片向上移动
	Card.prototype.moveTop=function(cards,bool) {
		var i=this.i;
		var j=this.j;
		//设定退出条件
		if(i==0){//已经是最上面了
			return false;
		}
		//上面一个卡片
		var prev = cards[i-1][j];
		if(prev.num==0){//上一个卡片是空
			//移动,本质就是设置数字
			if(bool){//bool为true才执行,因为flase只是用来判断能否移动
				prev.num=this.num;
				this.num=0;
				//递归操作(注意这里是要 prev 来 move了)
				prev.moveTop(cards,bool);
			}
			return true;
		}else if(prev.num==this.num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
			if(bool){bool为true才执行
				prev.merge=true;
				prev.num=this.num*2;
				this.num=0;
			}
			return true;
		}else {//上一个的num与当前num不同,无法移动,并退出
			return false;
		}
	}

JavaScript实现2048小游戏,我终于赢了一把_第10张图片

  1. 在Card中加入其他3个方向的代码
//向下移动
	Card.prototype.moveBottom=function(cards,bool) {
		var i=this.i;
		var j=this.j;
		//设定退出条件
		if(i==3){//已经是最下面了
			return false;
		}
		//上面一个卡片
		var prev = cards[i+1][j];
		if(prev.num==0){//上一个卡片是空
			//移动,本质就是设置数字
			if(bool){//bool为true才执行,因为flase只是用来判断能否移动
				prev.num=this.num;
				this.num=0;
				//递归操作(注意这里是要 prev 来 move了)
				prev.moveBottom(cards,bool);
			}
			return true;
		}else if(prev.num==this.num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
			if(bool){bool为true才执行
				prev.merge=true;
				prev.num=this.num*2;
				this.num=0;
			}
			return true;
		}else {//上一个的num与当前num不同,无法移动,并退出
			return false;
		}
	
		
	}
	//向右移动
	Card.prototype.moveRight=function(cards,bool) {
		var i=this.i;
		var j=this.j;
		//设定退出条件
		if(j==3){//已经是最右边了
			return false;
		}
		//上面一个卡片
		var prev = cards[i][j+1];
		if(prev.num==0){//上一个卡片是空
			//移动,本质就是设置数字
			if(bool){//bool为true才执行,因为flase只是用来判断能否移动
				prev.num=this.num;
				this.num=0;
				//递归操作(注意这里是要 prev 来 move了)
				prev.moveRight(cards,bool);
			}
			return true;
		}else if(prev.num==this.num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
			if(bool){bool为true才执行
				prev.merge=true;
				prev.num=this.num*2;
				this.num=0;
			}
			return true;
		}else {//上一个的num与当前num不同,无法移动,并退出
			return false;
		}
	}
	//向左移动
	Card.prototype.moveLeft=function(cards,bool) {
		var i=this.i;
		var j=this.j;
		//设定退出条件
		if(j==0){//已经是最左边了
			return false;
		}
		//上面一个卡片
		var prev = cards[i][j-1];
		if(prev.num==0){//上一个卡片是空
			//移动,本质就是设置数字
			if(bool){//bool为true才执行,因为flase只是用来判断能否移动
				prev.num=this.num;
				this.num=0;
				//递归操作(注意这里是要 prev 来 move了)
				prev.moveLeft(cards,bool);	
			}
			return true;
		}else if(prev.num==this.num && !prev.merge){//合并操作(如果已经合并了,则不运行再次合并,针对当然轮)
			if(bool){bool为true才执行
				prev.merge=true;
				prev.num=this.num*2;
				this.num=0;
			}
			return true;
		}else {//上一个的num与当前num不同,无法移动,并退出
			return false;
		}
	}

运行效果:
JavaScript实现2048小游戏,我终于赢了一把_第11张图片

做到这里就基本完成了,加入其他一下辅助的东西就行了,比如重新开始、游戏胜利,游戏结束等,也就不多说了。

看到这里的大佬,动动发财的小手 点赞 + 回复 + 收藏,能【 关注 】一波就更好了。

代码获取方式

订阅我的专栏《javascript精彩实例》后,可以查看专栏内所有的文章,并且联系博主免费获取你心仪的源代码,专栏的文章都是上过csdn热榜的,值得信赖,了解一下我的专栏!。**

热门专栏推荐

【1】Java小游戏(俄罗斯方块、飞机大战、植物大战僵尸等)
【2】JavaWeb项目实战(图书管理、在线考试、宿舍管理等)
【3】JavaScript精彩实例(飞机大战、贪吃蛇、验证码等)
【4】Java小白入门200例
【5】从零学Java、趣学Java
【6】Idea从零到精通

你可能感兴趣的:(javascript,javascript精彩实例,javascript,html5,html,2048小游戏,canvas)