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

| 一、一行的左移 |
- 关键逻辑算法 伪代码 ↓
- c从0开始,遍历当前行每个元素
- 找c右侧下一个不为0的位置nextc
- 如果找到 → 如果c位置的值是0,将nextc位置的值赋值给c位置,将nextc位置的值置为0,c留在原地;否则如果c位置的值等于nextc位置的值,将c位置的值*2,将nextc位置的值置为0
- 否则(如果没找到) → 退出循环
- 坑:2048游戏的规则,如果一个数字在发生一次替换(比如左移)之后没有合并即*2,那么,它还有一次机会和相反方向的数字进行合并(还可以向右移动),这就要求如果c的位置为0,那么除了数值的替换程序之外,还应该把c位置留在原地,方便之前的数字再回来
- 解决:因为每次循环都会使c++,+1,要让c留在原地,保持不变 → 用c--,和c++抵消,保持不变
| 二、所有行的左移 |
- 思路:将一行的左移封装成一个算法,循环调用给所有行;同时为了函数的功能集中,把找c右侧下一个不为0的位置nextc的循环也封装为一个小函数
- 创建关键函数 ↓
- moveLeft() 左移所有行
- moveLeftInRow(r) 左移第r行 → 一行左移的算法封装
- 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(){ }
- 识别按键 ↓
- 原理:每一个键盘的按键下面都藏着一个唯一的编号(虚拟的)
- 通过判断每一个按键的键盘号的不同,做不同的事情(执行不同的移动控制函数)
- 上下左右的键盘号 keyCode
- 左 37
- 上 38
- 右 39
- 下 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
- data[r][c]*=2; → 将要合并的当前格数字*2
- score+=data[r][c]; → 将data中的数值赋给score
- 在updateView(){}元素填写页面的函数方法中,设置id为score的span的内容为score
- var span = document.getElementById("score");
- 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爬坑之封装行的移动算法&事件的更多相关文章
- 【2048小游戏】——CSS/原生js爬坑之纯CSS模态对话框&游戏结束
引言:2048小游戏的结束界面,使用纯CSS制作模态对话框,一般做模态对话框都会使用BootStrap自带的模态对话框组件方便使用,但在制作要运行在移动端的小项目时,就不能使用BootStrap,因为 ...
- 【2048小游戏】——原生js爬坑之遍历算法显示二维数组内容
引言:做2048小游戏会将横纵方向的数字内容,存储在一个二维数组中,要将这个二维数组中的内容显示在页面上,就一定要用遍历算法来实现了. 一.二维数组存储 首先考虑用二维数组存储所有行数,列数 ...
- 【京东详情页】——原生js爬坑之二级菜单
一.引言 做京东详情页仿写的时候,要用原生js实现顶部菜单的二级菜单显示与隐藏事件的触发. 过程中遇到了一个坑,在这里与大家分享.要实现的效果如下: 二.坑 谁触发事件?显示.隐藏二级菜单 ...
- 【京东详情页】——原生js爬坑之放大镜
一.引言 在商城的详情页中,放大镜的功能是很常见的.这里京东详情页就要做一个仿放大镜的效果,预览如下: 二.实现原理 实际上,放大镜的实现是单纯用几个div,鼠标移入其中一个小图div,触发事件显示另 ...
- 【京东详情页】——原生js爬坑之标签页
一.引言 要做详情页的商品评价等5个li的标签页转换,效果如下: 二.实现原理 有一个特别的地方:上面五个li,但下面只有四个容器(table/div). 设计的目的:无论点哪个li,只有前四个div ...
- js、jQuery实现2048小游戏
2048小游戏 一.游戏简介: 2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...
- 用js实现2048小游戏
用js实现2048小游戏 笔记仓库:https://github.com/nnngu/LearningNotes 1.游戏简介 2048是一款休闲益智类的数字叠加小游戏.(文末给出源代码和演示地址) ...
- 使用JS实现2048小游戏
JS实现2048小游戏源码 效果图: 代码如下,复制即可使用: (适用浏览器:360.FireFox.Chrome.Opera.傲游.搜狗.世界之窗. 不支持Safari.IE8及以下浏览器.) &l ...
- 基于jQuery的2048小游戏设计(网页版)
上周模仿一个2048小游戏,总结一下自己在编写代码的时候遇到的一些坑. 游戏规则:省略,我想大部分人都玩过,不写了 源码地址:https://github.com/xinhua6/2048game.g ...
随机推荐
- Leetcode 645.最长数对链
最长数对链 给出 n 个数对. 在每一个数对中,第一个数字总是比第二个数字小. 现在,我们定义一种跟随关系,当且仅当 b < c 时,数对(c, d) 才可以跟在 (a, b) 后面.我们用这种 ...
- 菜鸟之路——机器学习之BP神经网络个人理解及Python实现
关键词: 输入层(Input layer).隐藏层(Hidden layer).输出层(Output layer) 理论上如果有足够多的隐藏层和足够大的训练集,神经网络可以模拟出任何方程.隐藏层多的时 ...
- 第一个python自动化程序
#Author:xiaoxiao from selenium import webdriver def searchSelenium(): #启动浏览器 driver = webdriver.Fire ...
- [LVS] 用keepalived实现LVS NAT模式高可用性
默认前提是LVS已经可以正常工作了. 因为是NAT模式,RS的路由要指向LVS的接口地址,所以需要一个统一的后台浮动地址,使得RS都指向这个浮动IP.否则在切换时,会导致RS回包到DOWN掉的LVS上 ...
- 调试Java代码(Eclipse)汇总
Java 10个调试技巧(基础❤❤❤❤❤) Eclipse断点调试(和上一篇基本类似,补充❤❤) 使用Eclipse开发和调试java程序(从安装eclipse开始,特别细,有设置条件断点,回退的具体 ...
- include和require的区别误区
面试时总会被问到include和require的区别,回答的时候一般也是有以下几种区别: 1.include引入文件的时候,如果碰到错误,会给出警告,并继续运行下边的代码. require引入文件的时 ...
- 洛谷P1816 忠诚
P1816 忠诚 569通过 1.5K提交 题目提供者该用户不存在 标签云端 难度普及+/提高 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 主席树的常数貌似大于线段树… TL ...
- Java EE 学习(1):什么是Java EE
转载: http://www.jb51.net/article/13059.htm 经常听朋友说什么J2EE,终于知道点什么是J2EE了,汗一个,上网搜了下这个说的比较详细了,J2EE,Java2平台 ...
- HAOI2008题解
又来写题解辣-然而并不太清楚题目排列情况...不管辣先写起来- T1:[bzoj1041] 题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1 ...
- 判断是手机端还是pc端
<script type="text/javascript"> if (window.location.toString().indexOf('pref=padinde ...