引言: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. [oldboy-django][4python面试]面试前需要熟练掌握的知识点(待更新)

    python基础 - 生成器 - 装饰器 - 迭代器 - 列表生成式 - 引用,传参 - 面向对象,继承 前端Html: - 词法分析 - 作用域 - 语法分析 - this - Jsonp mysq ...

  2. [oldboy-django][5python基础][高级特性]generator生成器

    # 生成器基础 - 定义 在循环的时候不断推算下一个元素的值,而不是一下子创建空间存储所有元素,这样节省空间. 并且在适当的条件结束循环,这种一边循环一边计算的机制,称为generator生成器 - ...

  3. Spring 简单而强大的事务管理功能

    开始之前 关于本教程 本教程将深入讲解 Spring 简单而强大的事务管理功能,包括编程式事务和声明式事务.通过对本教程的学习,您将能够理解 Spring 事务管理的本质,并灵活运用之. 先决条件 本 ...

  4. Unity 碰撞检测

    武器与怪物的碰撞 目前来说有三种思路,其实前两种算变种了: 1.动画关键帧回调 + 范围检测.http://blog.csdn.net/u013700908/article/details/52888 ...

  5. ruby 制作自己的gem包

    在ruby工程目录下新建一个文件:crowdSystem.gemspec.需要在lib目录下存在同一名称的ruby库文件:crowdSystem.rb

  6. BootStrap导入及其使用

    BootStrap主要是一个CSS框架,用于页面布局 <!DOCTYPE html> <html lang="en"> <head> <m ...

  7. POJ 3255:Roadblocks(次短路)

    题目大意:求无向图的次短路. 分析: 在起点终点各求一次最短路,枚举边,通过该边的最短路为其权值加上到起点和终点最短路之和,找到最短但又比最短路长的路径. 代码: program block; typ ...

  8. input聚焦时,滚动至可视区域

    这里的代码来自vux,觉得vux处理得很好,在此记录一下. 当我们在手机上填表单的时候,我们会希望正在填的input或者textarea会自动滚动至可视区域,方便我们边填写边查看内容.以前我的做法是, ...

  9. [Linux]方便openmp等程序的类似编译

    因为总是打参数例如-fopenmp或者-lGL等等有些麻烦,所以特地写一个可以使用的bash文件用来执行简单的操作 首先在.profile中添加 if [ -d "$HOME/bin&quo ...

  10. vs2017 出现“文件中的类都不能进行设计,因此未能为该文件显示设计器”问题处理

    今天拷贝了以前的一个项目.打算出一个新版本. 但是拷贝了sln文件后,去除掉以前的项目,新增了一个  winfrom项目中 出现了:文件中的类都不能进行设计,因此未能为该文件显示设计器.错误 百度了一 ...