一个自制的2048小游戏(2)

先声明哈:我做的这个也是跟着被人学习的,写文章是为了复习思路,还有巩固一下。总而言之呢,就是为了多理解思路,多折腾代码。

咳咳,上次我们已经将游戏的初始化全部完成了,包括游戏过程中需要的updataBoardView(); generateOneNumber();showNumberWithAnimation()也都全写好了,所以这次呢就是来写游戏过程中的逻辑了,发车了,抓紧时间上车~~

一.游戏过程键盘操作

  1. 键盘监听函数
    玩过这款游戏的人都知道,操作就是通过上下左右来移动小方块,完成合并操作。所以我们在全局写一个键盘的事件监听函数$(document).keydown()
    我们需要在其中写入什么呢?首先需要判断是哪个按键被按下,所以肯定需要获取event这个事件触发式生成的对象
Event 对象

Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠的位置、鼠标按钮的状态。
事件通常与函数结合使用,函数不会在事件发生前被执行!
具体的event的解释大家可以去w3school看看。其中event有一个keyCode属性能够获取到敲击键盘的虚拟键盘码

我们通过拿到的keyCode来判断哪个键被按下,同时执行相应的函数就好了,代码如下

 $(document).keydown(function (event){
    switch(event.keyCode){
        case 37: //left
            moveLeft();
            generateOneNumber();
            break;
        case 38: //up
            
            break;
        case 39: //right
            
            break;
        case 40: //down
            
            break;
    }
});

但这牵扯到的两个问题,一个是当前的游戏状态允不允许执行左移或者右移,比如如果是不能左移的话,那按下←应该是无效的,同时就不应该新生成一个数字。一个是移动后应该立马检测游戏有没有结束,如果四个方向都不能移动的话,游戏就应该GameOver了。为解决第一个问题,我们需要做一个检测,返回一个值来决定需不需要新生成一个数字。为解决第二个问题,我们需要写一个isgameover().

  • 我们将检测函数写在moveleft内部返回,将键盘监听代码改为如下
case 37://left
        if(moveLeft()){
            generateOneNumber();
            isgameover();
        }
  1. 左移函数moveLeft()
    在这里面我们做两件事,一个是先判断能不能移动,不行的话直接返回false。如果能移动的话,我们再执行接下来的移动部分。我先把代码贴出来
    完整代码:
function moveLeft(){
    if(!canMoveLeft(board)){
        return false;
    }

    //遍历右边12个格子
    for(var i=0;i<4;i++){
        for(var j=1;j<4;j++){
            if(board[i][j]!=0){
                //有数字则遍历左边
                for(var k=0;k<j;k++){
                    //看落点是否为空且路上有无障碍
                    if(board[i][k]==0&&noBlockHorizontal(i,k,j,board)){
                        //move
                        showMoveAnimation(i,j,i,k);
                        //更新
                        board[i][k]=board[i][j];
                        board[i][j]=0;
                        continue;
                    }else if(board[i][k]==board[i][j]&&noBlockHorizontal(i,k,j,board)&&!hasConflicted[i][k]){
                        //move
                        showMoveAnimation(i,j,i,k);
                        //更新
                        board[i][k]+=board[i][j];
                        board[i][j]=0;
                        //分数增加
                        score += board[i][k];
                        updateScore(score);

                        hasConflicted[i][k]=true;
                        
                        continue;
                    }
                }
            }
        }
    }
    //遍历完后更新格子显示状态,慢一点才能显示动画
    setTimeout("updateBoardView()",200);
    return true;
}

我们通过canMoveLeft来判断当前游戏状态能不能左移,我们要用到的是存储格子数据的数组board,我们将这个函数写在support.js中

//检测能否左移
function canMoveLeft(board){
    for(var i=0;i<4;i++){
        for(var j=1;j<4;j++){
            if(board[i][j]!= 0){
                if(board[i][j-1]==0||board[i][j-1]==board[i][j])
                    return true;
            }
        }
    }
    return false;
}

这里面显而易见的是左边第一列的4个格子是不能移动的,所以只需要遍历右边的12个格子,只要有一个有数字的格子的自身左边的一个格子为空,或者说值和它相等,那么游戏状态就是可以左移的,直接return true;即可。
看完检测函数后我们来看看后面的移动的部分。

//遍历右边12个格子
    for(var i=0;i<4;i++){
        for(var j=1;j<4;j++){
            if(board[i][j]!=0){
                //有数字则遍历左边
                for(var k=0;k<j;k++){
                    //看落点是否为空且路上有无障碍
                    if(board[i][k]==0&&noBlockHorizontal(i,k,j,board)){
                        //move
                        showMoveAnimation(i,j,i,k);
                        //更新
                        board[i][k]=board[i][j];
                        board[i][j]=0;
                        continue;
                    }else if(board[i][k]==board[i][j]&&noBlockHorizontal(i,k,j,board)&&!hasConflicted[i][k]){
                        //move
                        showMoveAnimation(i,j,i,k);
                        //更新
                        board[i][k]+=board[i][j];
                        board[i][j]=0;
                        //分数增加
                        score += board[i][k];
                        updateScore(score);

                        hasConflicted[i][k]=true;
                        
                        continue;
                    }
                }
            }
        }
    }
    //遍历完后更新格子显示状态,慢一点才能显示动画
    setTimeout("updateBoardView()",200);
    return true;

同理,也是只需要遍历右边的12个格子,先判断遍历到的这个格子是不是有值,有的话则遍历其左边的所有格子。这里就分成两种情况
1.目标格子是空的,且中间没有阻碍,于是可以移动过去
2.目标格子的值和自身是相等的,而且中间没有阻碍,那么就可以合并
除了这两种情况以外的都不需要做什么操作。
为此我们需要在support.js中写一个检测两个格子间(同一行)有没有阻碍的函数
noBlockHorizontal:

//检测行上有无阻碍
function noBlockHorizontal(row,col1,col2,board){
    for(var i=col1+1;i<col2;i++){
        if(board[row][i]!=0)
            return false;
    }
    return true;
}

这个我相信大家都看得懂,我就不解释了。
对于第一种情况我们的操作是:

  • 调用移动动画函数
  • 更新board数组,将自身的值传给目标格子,自身设为0

对于第二种情况我们的操作是:

  • 调用移动动画函数
  • 更新board数组,目标格子的值加上自身的值,自身设为0
  1. 移动动画函数showMoveAnimation(fromx,fromy,tox,toy)
//移动动画
function showMoveAnimation(fromx,fromy,tox,toy){
    var numberCell=$("#number-cell-"+fromx+"-"+fromy);
    numberCell.animate({
        left:getPosLeft(tox,toy),
        top:getPosTop(tox,toy)
    },200);
}

我们是取自身这个数字方块,给它加个animate。animate里面传的是目标格子的left和top值,这个值是通过目标格子的坐标得到的。

  1. moveLeft()函数收尾
    在一系列的修改都完成后,我们就需要根据现在的board来渲染格子视图
    所以最后添加,并返回true给键盘监听函数使用。
//遍历完后更新格子显示状态,慢一点才能显示动画
    setTimeout("updateBoardView()",200);
    return true;
  1. 最后的最后
    其他方向的移动函数也是同理,我就不贴代码了,几乎一模一样,细节上的一些数字不同罢了。当一切都完成后,我们就已经可以开始愉快的玩耍我们的游戏啦!!
游戏画面
后面还有一些小bug的修复,得分的统计,游戏结束的判断等,就放到下一篇文章吧,谢谢!!
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容