JavaScript实现2048小游戏,我终于赢了一把
JavaScript实现2048小游戏
作者简介
作者名:
简介:CSDN博客专家,从事软件开发多年,精通Java、JavaScript,博主也是从零开始一步步把学习成长、深知学习和积累的重要性,喜欢跟广大ADC一起打野升级,欢迎您关注,期待与您一起学习、成长、起飞!
系列目录
1. JavaScript 贪吃蛇游戏
2. JavaScript 俄罗斯方块
3. JavaScript 扫雷小游戏
4. JavaScript 网红太空人表盘
效果图
实现思路
- 编写页面和画布代码。
- 绘制背景。
- 绘制好全部卡片。
- 随机生成一个卡片(2或者4)。
- 键盘事件监听(上、下、左、右键监听)。
- 根据键盘的方向,处理数字的移动合并。
- 加入成功、失败判定。
- 处理其他收尾工作。
代码实现
编写页面代码
<!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编写代码
创建函数
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;
}初始化和绘制背景代码(在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)); }
在页面代码中加入以下 js 代码
var box = document.getElementById(‘box’);
g2048.init(box);
运行效果:
绘制好全部卡片
创建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.ithis.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);
}
}}
创建卡片
//创建卡片 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);}} }
调用绘制代码
运行效果:
修改一下卡片的默认数字
随机生成一个卡片,2或者4
- 先把Card中 num 默认改成0
- 因为2跟4出现的比例是1:4,所以采用随机出1-5的数字,当是1的时候就表示,当得到2、3、4、5的时候就表示要出现数字2.
- 随机获取i,j 就可以得到卡片的位置,割接i,j取到card实例,如果卡片没有数字,就表示可以,否则就递归继续取,取到为止。
- 把刚才取到的数字,设置到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方法中调用,表示打开游戏默认一个数字
运行效果:
加入键盘事件
同样要在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://wcase 38://上dir=1;//上移动break;case 68://dcase 39://右dir=2;//右移动break;case 83://scase 40://下dir=3;//下移动break;case 65://acase 37://左dir=4;//左移动break;}//卡片移动的方法that.moveCard(dir);});}
加入移动逻辑处理代码
//卡片移动的方法
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;}} }
加入上下左右处理逻辑
//向上移动
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; }
在Card中加入向上移动的处理逻辑
- 从第2行开始移动,因为第一行不需要移动。
- 只要卡片的数字不是0,就表示要移动。
- 根据 i-1 可以获取到上一个卡片,如果上一个卡片是空,则把当前卡片交换上去,并且递归,因为可能要继续往上移动。
- 如果当前卡片与上一个卡片是相同数字的,则要合并。
- 以上两种都不是,则不做操作。
//卡片向上移动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;}}
在Card中加入其他3个方向的代码
//向下移动
Card.prototype.moveBottom=function(cards,bool) {
var i=this.i;
var j=this.j;
//设定退出条件
if(i3){//已经是最下面了
return false;
}
//上面一个卡片
var prev = cards[i+1][j];
if(prev.num0){//上一个卡片是空
//移动,本质就是设置数字
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精彩实例》后,可以查看专栏内所有的文章,并且联系博主免费获取你心仪的源代码,专栏的文章都是上过csdn热榜的,值得信赖,了解一下我的专栏!。**
热门专栏推荐
【1】Java小游戏(俄罗斯方块、飞机大战、植物大战僵尸等)
【2】JavaWeb项目实战(图书管理、在线考试、宿舍管理等)
【3】JavaScript精彩实例(飞机大战、贪吃蛇、验证码等)
【4】Java小白入门200例
【5】从零学Java、趣学Java
【6】Idea从零到精通
JavaScript实现2048小游戏,我终于赢了一把相关推荐
- javascript实现2048小游戏
最近打算系统的学习一下javascript,想做点项目练手,就选择用javascript实现我比较喜欢玩的2048游戏,大体完成以后还是蛮有成就感的.(文末给出相关代码) 游戏相关截图: ...
- 【javascript】2048小游戏
目录 什么是2048 游戏状态机 游戏界面绘制 3.1 界面 3.2 数字的背景颜色 分数逻辑 4.1 加分 4.2 更新最高分 方向控制逻辑 5.1 数组 5.2 随机数 5.3 初始化 5.4 判 ...
- python游戏代码五子棋_用20行Python代码实现2048小游戏,你会吗?
前些天在b站上看到有个大佬用c写了一个2048小游戏,我便一下来了兴趣.心想着,我貌似也能用Python来整一波,话不多说,直接开搞. 2048的游戏规则: 2048游戏总共有16个格子,初始时会有两 ...
- python秒表游戏代码_用20行Python代码实现2048小游戏,你会吗?
前些天在b站上看到有个大佬用c写了一个2048小游戏,我便一下来了兴趣.心想着,我貌似也能用Python来整一波,话不多说,直接开搞. 2048的游戏规则: 2048游戏总共有16个格子,初始时会有两 ...
- html css js实现快递单打印_JS与HTML、CSS实现2048小游戏(六)
在前面的五篇文章中,小编带大家完成了网页版2048小游戏的基本游戏逻辑.但是在游戏结束的gameover()方法中咱们只是简单的通过alert来弹出一些信息,这样的话只能出现下图的效果.这样的游戏,不 ...
- 2048小游戏设计思路
2048小游戏设计思路: 游戏初始截图: 游戏过程中截图: 游戏失败截图: 部分代码: <!DOCTYPE html><html> <head><meta h ...
- 2048小游戏(原生js基础代码篇)
今天在这里,我将给各位呈现一个简单的游戏代码. 想必大家都接触过2048这个小游戏吧,在悠闲时间用于消遣时间最好不过了,那么,我给大家写一个2048最基本的原生js代码. HTML: <!DOC ...
- html+css+js适合前端小白的实战全解(超详细)——2048小游戏(三)
续上一小节,我们回到newgame()这个函数,我们之前只做了init()内函数,相当于一个初始化操作 现在,我们需要再随机两个两个生成数字. 随机生成数字在这个游戏里会经常出现,用户移动一步,也会产 ...
- html+css+js适合前端小白的实战全解(超详细)——2048小游戏(二)
续上一小节,我们可以发现每一个grid-cell上的数字初始时并不在格子里. 这些数字可以随着玩家的操作而移动 我们可以想象:初始时每一个格子上的数为0,他们并不显示 ↓ 只有当grid-cell ...
最新文章
- R语言伯努利分布(Bernoulli distribution)函数(dbern, pbern, qbern rbern)实战
- CentOS5.5下NIS配置
- mysql分表方法-----MRG_MyISAM引擎分表法
- oom 如何避免 高并发_【面试题】如何设计一个高并发系统?
- tryLock尝试获取锁
- 计算机二级web题目(7.1)--综合选择题1
- 未来教育计算机二级书怎么样,未来教育计算机二级
- 前端框架:AntdUI 文档入门
- input上报流程分析【转】
- Does taro support react hook?
- MySQL 索引优化器选择索引的规则
- ROS学习笔记九:用C++编写ROS发布与订阅
- linux导出日志命令_Linux中的导出命令
- 亲身经历:2018年深圳保洁员工资时薪75,月薪不清楚
- mysql中timestamp字段
- 动态添加 data 属性的时候 发现某一个值无法取到
- 清华校友、香港科技大学准博士ICCV顶会论文被爆公然抄袭!去年CVPR也是抄的...
- 官宣!等你来赛,2022 第二届 STM32 Hackathon 挑战赛海选开放报名!
- 小程序map组件一——使用腾讯地图个性化地图组件、腾讯云可视化大屏展示
- HDU steps 1.2.6 Identity Card
热门文章
- 激光切割机雕刻机桌面打标机打码机点胶机写字机上位机C#源码STM32F407控制板源码
- 【Linux】Linux系统的常见指令
- SW toolbox国标生成斜齿轮失败
- HTC Desire (G7) VS MOTO Milestone VS MOTO XT800 个人对比评测
- java对数字证书的验证_JAVA对数字证书的常用操作
- java语言算法描述_六大java语言经典算法
- ENVI app store报错:打不开和显示无法联网
- 机器学习与深度学习——通过knn算法分类鸢尾花数据集iris求出错误率并进行可视化
- 用turtle画路飞
- Python周刊502期