个人前端故事----欢乐大富翁( ̄︶ ̄)↗ (摇骰子+棋盘)

      十一立刻就要到了~~作为前端的小伙伴~活动页面必然是少不了了~那怎么吸引眼球呢?固然是玩游戏啦~此次就带来一个我为十一作的小游戏,做为活动页中的陪衬~~css

      那咱们要作个什么样的游戏呢?先上图~前端

4443

       因为实际的效果图由于是公司的活动,我就不贴出来了~这里用这个棋盘来大体说明一下效果咯~下面是游戏规则:java

       1,当用户看到棋盘的时候,棋子出如今上一次停留下来的位置;json

       2,当用户点击开始后,中间的骰子开始摇动,最后中止在服务器返回的数字前;数组

       3,当骰子结束动画后,棋子仍是移动,一步一步的向前移动,遇到四个顶点的时候自动转弯,并最终停留在骰子步数前进的位置前;服务器

       4,当棋子结束移动后,页面上显示用户最后剩下的游戏次数,而且若是移动到有礼物的位置时弹出遮罩告诉用户获奖;异步

       5,在整个游戏期间,不容许用户继续点击开始按钮,而且当用户剩余次数用完以后开始按钮变色;函数

       游戏规则都说明了,那么需求分析就到这里了,下面介绍页面布局:布局

HTML结构:

<div class="game">
    <div class="gameimg">
             <div id="pieces" class="p0-0">    <!-- 棋子 -->
                 <img src="images/pieces.png" />
             </div>
        <div class="play">
             <div class="dice">     <!-- 骰子 -->
                 <img id="dice" class="dicelo2" src="images/dice.png" />
             </div>
             <div class="playnum">
                 您今天还有<span id="pn">0</span>次游戏机会
               </div>
             <div id="playbtn">
                  <img src="images/btn_start_gray.png" />
             </div>
         </div>
    </div>
</div>

总体的结构就是一个大的div标签,它的背景是整个棋盘,而后棋子经过相对布局定位在背景图的18个位置上,而后骰子和开始按钮以及说明都居中显示在背景图的中心。性能

CSS样式:

       对于css样式来讲,主要用到的是相对定位,设置了18个位置的css样式,并且命名规则是按照 ’p0-0‘这样的方式来命名?为何我要这样呢?这样能够用类名保存矩阵坐标的位置。棋盘上的位置1对应坐标的1-0、2对应2-0…..依此类推。最后就能够方便的设置棋子的位置了。同时,对于骰子的动画,是经过一整张png图片来进行定位。从骰子的1到6而后是动起来的3副图片,一共9张图片保存在一整张png中,而后依旧采用相对定位的方式来给用户展现。首先是骰子开始运动,我就循环显示最后3张动起来的图片,而后当动画结束后将位置停留在所要显示对应的数字前。

11118222223这样把部分图片贴出来就很明显的说明了个人意图~

javascrpt逻辑篇:

         首先是进入页面的加载,流程就是首先经过jsonp请求服务器,获取该用户上次的棋子位置,和剩余次数等基础信息,而后渲染在页面中,我就不在这里展开了,这里注意想说的是负责棋子移动和骰子摇动的逻辑部分。

         那么按照游戏规则,首先是骰子的摇动,当点击开始按钮后请求服务器结束后调用骰子执行函数,接着将服务器返回的骰子数字和到达的位置传递给复制骰子动画的函数。

/**
 * 操做骰子的执行函数
 *
 * @method play_dice
 *
 * @param  {ing}  dice_num  [骰子数字]
 * @param  {int}  next_step [到达位置]
 */
function play_dice (dice_num, next_step) {
    var _stop = dice_num,
        _pande = next_step;
    diceroll($('#dice'), _stop, _pande);
}
/**
 * 摇动骰子的动画函数
 *
 * @method diceroll
 *
 * @param  {object} dice      [骰子对象]
 * @param  {int}    num       [摇动的结果]
 * @param  {int}    _pande    [棋子停下的位置]
 */
function diceroll(dice, num, _pande){
    var i = 0,
        b = 0,
        a = function(i) {
          b = setTimeout(function() {
              dice.removeClass().addClass('dicelo' + (i % 3 + 7));   // 清除上次动画后的点数
              i++;
              if (i > 5) {
                  // 这里的dicelo9是骰子最后一幅动画的类名,删除后依次添加dicelo7,dicelo8 
                  dice.removeClass('dicelo9').addClass('dicelo'+num);
                  var j = $('#pieces').attr('class').substr(1) || 1,
                      n = j + _pande;
                  var oldstep = _pande-num-1;
                  person.step = num;
                  run(person, true);//  1右,2下,3左,4上
                     clearTimeout(b);
                  i = 0;
              } else {
                  a(i);
              }
          }, 200);
        };
    a(i);
}

       这里经过一个定时器,不断的循环骰子摇动的这个动画,而后在执行5次以后就让骰子停下来,同时清除定时器,而后在骰子中止摇动以后触发棋子移动的函数,在run函数中须要两个参数,若是第二个参数为true,就让棋子仍是移动,不然的话则只是计算棋子的矩阵坐标。而person这个对象中保存着坐标位置start: [0, 0],所要前进的步数step,和当前前进的方向de,de的值我设定为1右,2下,3左,4上 。下面是棋子移动的函数。

/**
 * 控制棋子的移动和棋盘坐标的转换
 *
 * @method run
 *
 * @param  {object}  person [棋子移动的坐标]
 * @param  {Boolean} isAn   [棋子是否须要移动]
 *
 * @return {object}         [棋子移动的坐标]
 */
function run (person, isAn) {
    var _start = person.start,
        _step = person.step,
        _de = person.de;

    // 棋子移动过程的坐标集合
    gameList = new Array();
    for (var i = 1; i <= _step; i++) {
        if (_de == 1) {  // 棋子向右移动
            _start[0] += 1;
            if (_start[0] == 5) {
                _de = 2;
            }
        }else if (_de == 2) {  // 棋子向下移动
            _start[1] += 1;
            if (_start[1] == 4) {
                _de = 3;
            }
        }else if (_de == 3) {  // 棋子向左移动
            _start[0] += -1;
            if (_start[0] == 0) {
                _de = 4;
            }
        }else if (_de == 4) {  // 棋子向上移动
            _start[1] += -1;
            if (_start[1] == 0) {
                _de = 1;
            }
        }
        gameList.push([_start[0], _start[1]]);  // 将移动后的结果保存在集合中
    }

    // 当须要棋子移动时执行
    if (isAn) {
        var j = 0,
            d = 0,
            c = function(j) {
              d = setTimeout(function() {
                  $('#pieces').attr('class', null).addClass('p'+gameList[0][0] + '-' +gameList[0][1]);
                  gameList.shift(0);
                  j++;
                  if (gameList.length == 0) { // 若是棋子移动结束后则弹出相应的结果
                          returndice(_start);
                      clearTimeout(d);
                  } else {
                      c(j);
                  }
              }, 500);
            };
        c(j);
    }
    person.start = _start;
    person.step = 0;
    person.de = _de;
    return person;
}

      这里依旧是使用定时器来重复显示棋子的移动过程,因为定时器是异步执行的,因此我将函数产生的一个运动结果保存在数组中,而后在异步的定时器中一个个的遍历数组中的结果,每次取出数组中的第一个结果,执行移动以后便移除第一个结果,后面的结果顶上来,下次取出的第一个结果就是下一次须要移动的结果,最终在结束移动的时候及队列清空的状况下清除定时器,而后我在代码中执行了returndice函数来显示移动后的结果,若是中奖了则调出遮罩提示用户的获奖状况。

总结:

       到这里,所有的逻辑基本都说明白了,其实总体来讲就是3个函数的循环调用,为了保证在移动端上的性能,在每次定时器结束以后都须要及时的清除掉定时器,不然会出现定时器覆盖的状况,在我测试的时候若是没有及时清除定时器的话,在执行20000+的时候会出现移动的步数比实际的状况少一步的状况,最开始的时候我在最后写了校验函数来保证最终棋子停下来的位置与服务器返回的一致,原本觉得是偏差,结果后来再测试的时候发现校验的时候会出现棋子闪现的状况,这是很很差的用户体验,并且按照我棋子移动的逻辑来看,是不可能出现错位的,因此理论上是不须要校验函数的,因此再通过仔细查看代码后发现了第二次棋子移动的定时器在使用后并无及时清除,在用户游戏次数较少的时候是很难出现bug的,可是自动测试的时候接近于无限的次数很容易出现错误的状况,因此仍是很重要的bug,还好及时发现。。。o(︶︿︶)o 最后为了保证在一次游戏的过程当中用户不能继续点击开始按钮,因此在开始摇骰子的时候将全局锁设置为false,并在最后棋子结束移动以后再打开全局锁。到此为止,全部的游戏规则都知足了~~

      今天就到这里吧。。。下次带来一个页面跑马灯的效果~~

相关文章
相关标签/搜索