引言:2048小游戏的核心玩法是移动行,包括横行和纵行,玩家可以选择4个方向,然后所有行内的数字就会随着行的移动而向特定的方向移动。这个行的移动是一个需要重复调用的算法,所以这里就要将一行的移动算法封装,循环调用给所用行,这样便实现了所有行的调用。


 

一、一行的左移
  • 关键逻辑算法   伪代码 ↓
  1. c从0开始,遍历当前行每个元素
  2. 找c右侧下一个不为0的位置nextc
  3. 如果找到 →  如果c位置的值是0,将nextc位置的值赋值给c位置,将nextc位置的值置为0,c留在原地;否则如果c位置的值等于nextc位置的值,将c位置的值*2,将nextc位置的值置为0
  4. 否则(如果没找到) → 退出循环
  • 坑:2048游戏的规则,如果一个数字在发生一次替换(比如左移)之后没有合并即*2,那么,它还有一次机会和相反方向的数字进行合并(还可以向右移动),这就要求如果c的位置为0,那么除了数值的替换程序之外,还应该把c位置留在原地,方便之前的数字再回来
  • 解决:因为每次循环都会使c++,+1,要让c留在原地,保持不变  →  用c--,和c++抵消,保持不变
二、所有行的左移
  • 思路:将一行的左移封装成一个算法,循环调用给所有行;同时为了函数的功能集中,把找c右侧下一个不为0的位置nextc的循环也封装为一个小函数
  • 创建关键函数  ↓
  1. moveLeft()    左移所有行
  2. moveLeftInRow(r)     左移第r行  →  一行左移的算法封装
  3. getNextcInRow(r,c)    找r行c列右侧下一个不为0的位置nextc   →   循环,找到返回位置nextc,没找到返回-1
  • 2048游戏规则:每一次控制移动都要随机生成一个2或4,但反过来,一定要发生了移动才能生成2或4,只是按键控制了移动,但没有发生移动,那就不生成。
  • 坑:要判定控制移动是否发生了真实的移动
  • 解决:在控制移动前将data转为字符串保存在before中,在控制移动后将data转为字符串保存在after中,然后再判断before是否等于after,如果不等于,重绘页面,生成2或4,如果等于,不重绘,也不生成。
  • 坑:如果先刷新了页面,再生成一个2或4,这样页面就看不到这个2或4了
  • 解决:先生成一个2或4,然后再刷新页面

三、键盘按下事件
  • 事件:用户在页面上,用鼠标触发的行为的变化
  • 为页面添加  键盘按下事件 处理函数  →   document.onkeydown=function(){ }
  • 识别按键  ↓
  1. 原理:每一个键盘的按键下面都藏着一个唯一的编号(虚拟的)
  2. 通过判断每一个按键的键盘号的不同,做不同的事情(执行不同的移动控制函数)
  • 上下左右的键盘号   keyCode
  1. 左   37
  2. 上   38
  3. 右   39
  4. 下   40
  • 关键代码   ↓
//为当前页面添加键盘按下事件处理函数
document.onkeydown = function(e){
//判断按键号:
switch (e.keyCode){
case 37://左
moveLeft();
break;
case 38://上
moveUp();
break;
case 39://右
moveRight();
break;
case 40://下
moveDown();
break;
}
}
四、游戏得分Score
  • 游戏的得分,应该作为游戏的一个重要属性保存下来  →   var  score = 0;初始值为0
  • 在每一次游戏开始的时候,即start()起始,都应该将得分归零  →   score=0;
  • 2048游戏规则:每一次发生数字合并都会增加分值,分值数=合并后的显示数字=合并前的数字*2
  1. data[r][c]*=2;   →   将要合并的当前格数字*2
  2. score+=data[r][c];   →   将data中的数值赋给score
  • 在updateView(){}元素填写页面的函数方法中,设置id为score的span的内容为score
  1. var span = document.getElementById("score");
  2. span.innerHTML=score;
五、游戏移动完整代码
var game={
RN:4,
CN:4,
data:null,
score:0,
state:1,
GAMEOVER:0,
RUNNING:1,
//启动游戏
start:function(){
this.state=this.RUNNING;
this.score=0;
this.data=[];
for(var r=0;r<this.RN;r++){
this.data[r]=[];
for(var c=0;
c<this.CN;
this.data[r][c]=0,c++);
}
this.randomNum();
this.randomNum();
this.updateView();
//为页面绑定键盘按下事件
document.onkeydown=function(e){
switch(e.keyCode){
case 37: this.moveLeft();break;
case 38: this.moveUp();break;
case 39: this.moveRight();break;
case 40: this.moveDown();break;
}
}.bind(this);/*this是start方法的this*/
},
move:function(callback){
var before=String(this.data);
callback();//this->window
var after=String(this.data);
if(before!=after){
this.randomNum();
if(this.isGameOver()){
this.state=this.GAMEOVER;
}
this.updateView();
}
},
isGameOver:function(){
for(var r=0;r<this.RN;r++){
for(var c=0;c<this.CN;c++){
if(this.data[r][c]==0){return false;}
else if(c<this.CN-1
&&this.data[r][c]==this.data[r][c+1]){
return false;
}
else if(r<this.RN-1
&&this.data[r][c]==this.data[r+1][c]){
return false;
}
}
}
return true;
},
moveLeft:function(){
this.move(function(){
for(var r=0;r<this.RN;r++){
this.moveLeftInRow(r);
}
}.bind(this));/*this是moveLeft方法的this*/
},
moveLeftInRow:function(r){
for(var c=0;c<this.CN-1;c++){
var nextc=this.getNextInRow(r,c);
if(nextc==-1){break;}
else{
if(this.data[r][c]==0){
this.data[r][c]=this.data[r][nextc];
this.data[r][nextc]=0;
c--;
}else if(this.data[r][c]
==this.data[r][nextc]){
this.data[r][c]*=2;
this.score+=this.data[r][c];
this.data[r][nextc]=0;
}
}
}
},
getNextInRow:function(r,c){
c++;
for(;c<this.CN;c++){
if(this.data[r][c]!=0){
return c;
}
}
return -1;
},
moveRight:function(){
this.move(function(){
for(var r=0;r<this.RN;r++){
this.moveRightInRow(r);
}
}.bind(this));
},
moveRightInRow:function(r){
for(var c=this.CN-1;c>0;c--){
var prevc=this.getPrevInRow(r,c);
if(prevc==-1){break;}
else{
if(this.data[r][c]==0){
this.data[r][c]=this.data[r][prevc];
this.data[r][prevc]=0;
c++;
}else if(this.data[r][c] ==this.data[r][prevc]){
this.data[r][c]*=2;
this.score+=this.data[r][c];
this.data[r][prevc]=0;
}
}
}
},
getPrevInRow:function(r,c){
c--;
for(;c>=0;c--){
if(this.data[r][c]!=0){
return c;
}
}
return -1;
},
moveUp:function(){
this.move(function(){
for(var c=0;c<this.CN;c++){
this.moveUpInCol(c);
}
}.bind(this));
},
moveUpInCol:function(c){
for(var r=0;r<this.RN-1;r++){
var nextr=this.getNextInCol(r,c);
if(nextr==-1){break;}
else{
if(this.data[r][c]==0){
this.data[r][c]=this.data[nextr][c];
this.data[nextr][c]=0;
r--;
}else if(this.data[r][c]
==this.data[nextr][c]){
this.data[r][c]*=2;
this.score+=this.data[r][c];
this.data[nextr][c]=0;
}
}
}
},
getNextInCol:function(r,c){
r++;
for(;r<this.RN;r++){
if(this.data[r][c]!=0){
return r;
}
}
return -1;
},
moveDown:function(){
this.move(function(){
for(var c=0;c<this.CN;c++){
this.moveDownInCol(c);
}
}.bind(this));
},
moveDownInCol:function(c){
for(var r=this.RN-1;r>0;r--){
var prevr=this.getPrevInCol(r,c);
if(prevr==-1){break;}
else{
if(this.data[r][c]==0){
this.data[r][c]=this.data[prevr][c];
this.data[prevr][c]=0;
r++;
}else if(this.data[r][c]
==this.data[prevr][c]){
this.data[r][c]*=2;
this.score+=this.data[r][c];
this.data[prevr][c]=0;
}
}
}
},
getPrevInCol:function(r,c){
r--;
for(;r>=0;r--){
if(this.data[r][c]!=0)
return r;
}
return -1;
},
//将数组中每个元素更新到页面的div中
updateView:function(){
for(var r=0;r<this.RN;r++){
for(var c=0;c<this.CN;c++){
var div= document.getElementById("c"+r+c);
if(this.data[r][c]!=0){
div.innerHTML=this.data[r][c];
div.className="cell n"+this.data[r][c];
}else{//否则
div.innerHTML="";
div.className="cell";
}
}
}
//找到id为score的元素,设置其内容为score属性
document.getElementById("score")
.innerHTML=this.score;
//如果游戏状态为结束
if(this.state==this.GAMEOVER){
document.getElementById("gameover")
.style.display="block";
document.getElementById("final")
.innerHTML=this.score;
}else{
document.getElementById("gameover").style.display="none";
}
},
randomNum:function(){
while(true){
var r=Math.floor(Math.random()*(this.RN));
var c=Math.floor(Math.random()*(this.CN));
if(this.data[r][c]==0){
this.data[r][c]=Math.random()<0.5?2:4;
break;
}
}
}
};
game.start();

注:转载请注明出处

【2048小游戏】——原生js爬坑之封装行的移动算法&事件的更多相关文章

  1. 【2048小游戏】——CSS/原生js爬坑之纯CSS模态对话框&游戏结束

    引言:2048小游戏的结束界面,使用纯CSS制作模态对话框,一般做模态对话框都会使用BootStrap自带的模态对话框组件方便使用,但在制作要运行在移动端的小项目时,就不能使用BootStrap,因为 ...

  2. 【2048小游戏】——原生js爬坑之遍历算法显示二维数组内容

    引言:做2048小游戏会将横纵方向的数字内容,存储在一个二维数组中,要将这个二维数组中的内容显示在页面上,就一定要用遍历算法来实现了. 一.二维数组存储    首先考虑用二维数组存储所有行数,列数   ...

  3. 【京东详情页】——原生js爬坑之二级菜单

    一.引言 做京东详情页仿写的时候,要用原生js实现顶部菜单的二级菜单显示与隐藏事件的触发. 过程中遇到了一个坑,在这里与大家分享.要实现的效果如下: 二.坑 谁触发事件?显示.隐藏二级菜单       ...

  4. 【京东详情页】——原生js爬坑之放大镜

    一.引言 在商城的详情页中,放大镜的功能是很常见的.这里京东详情页就要做一个仿放大镜的效果,预览如下: 二.实现原理 实际上,放大镜的实现是单纯用几个div,鼠标移入其中一个小图div,触发事件显示另 ...

  5. 【京东详情页】——原生js爬坑之标签页

    一.引言 要做详情页的商品评价等5个li的标签页转换,效果如下: 二.实现原理 有一个特别的地方:上面五个li,但下面只有四个容器(table/div). 设计的目的:无论点哪个li,只有前四个div ...

  6. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

  7. 用js实现2048小游戏

    用js实现2048小游戏 笔记仓库:https://github.com/nnngu/LearningNotes 1.游戏简介 2048是一款休闲益智类的数字叠加小游戏.(文末给出源代码和演示地址) ...

  8. 使用JS实现2048小游戏

    JS实现2048小游戏源码 效果图: 代码如下,复制即可使用: (适用浏览器:360.FireFox.Chrome.Opera.傲游.搜狗.世界之窗. 不支持Safari.IE8及以下浏览器.) &l ...

  9. 基于jQuery的2048小游戏设计(网页版)

    上周模仿一个2048小游戏,总结一下自己在编写代码的时候遇到的一些坑. 游戏规则:省略,我想大部分人都玩过,不写了 源码地址:https://github.com/xinhua6/2048game.g ...

随机推荐

  1. CSU-ACM寒假集训选拔-入门题

    CSU-ACM寒假集训选拔-入门题 仅选择部分有价值的题 J(2165): 时间旅行 Description 假设 Bobo 位于时间轴(数轴)上 t0 点,他要使用时间机器回到区间 (0, h] 中 ...

  2. Leetcode 567.字符串的排列

    字符串的排列 给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列. 换句话说,第一个字符串的排列之一是第二个字符串的子串. 示例1: 输入: s1 = "ab&q ...

  3. LeetCode——Problem2:Add Two Numbers

    这又过了一周了,总感觉刷这个好花时间呀.每次都一两个小时.让我不好安排时间.应该是我太菜了.对,没错,就是这样 1.题目 You are given two non-empty linked list ...

  4. linux系统带宽监测脚本

    服务器可能经常遇到服务器出带宽跑满,不知如何查询被哪个进程占用的情况,有一款开源的英文软件iftop功能比较强大可以查询相关信息,可能刚接触linux系统的朋友不太会使用,在此写了一个功能比较简单无需 ...

  5. linux系统初始化——busybox的inittab文件格式说明

    busybox的inittab文件格式说明 要写自己的inittab,需要理解busybox的inittab文件格式. busybox的inittab文件与通常的inittab不同,它没有runlev ...

  6. codeforces gym 100553I

    codeforces gym 100553I solution 令a[i]表示位置i的船的编号 研究可以发现,应是从中间开始,往两边跳.... 于是就是一个点往两边的最长下降子序列之和减一 魔改树状数 ...

  7. Codeforces Round #363 (Div. 2) C dp或贪心 两种方法

    Description Vasya has n days of vacations! So he decided to improve his IT skills and do sport. Vasy ...

  8. bzoj2438 杀人游戏 Tarjan强联通

    [bzoj2438][中山市选2011]杀人游戏 Description 一位冷血的杀手潜入 Na-wiat,并假装成平民.警察希望能在 N 个人里面,查出谁是杀手.警察能够对每一个人进行查证,假如查 ...

  9. cf 701 E - Connecting Universities

    Descrition 给你一颗\(n\le 2*10^5\)个点的树, 有\(2*k(2k\le n)\)座大学座落在点上 (任二大学不在同一个点) 求一种两两匹配的方案, 使得距离和最大 即\[ma ...

  10. hdu 3980 Paint Chain 组合游戏 SG函数

    题目链接 题意 有一个\(n\)个珠子的环,两人轮流给环上的珠子涂色.规定每次涂色必须涂连续的\(m\)颗珠子,无法继续操作的人输.问先手能否赢. 思路 参考 转化 第一个人取完之后就变成了一条链,现 ...