個人前端故事----歡樂大富翁( ̄︶ ̄)↗ (搖骰子+棋盤)

      十一立刻就要到了~~作爲前端的小夥伴~活動頁面必然是少不了了~那怎麼吸引眼球呢?固然是玩遊戲啦~此次就帶來一個我爲十一作的小遊戲,做爲活動頁中的陪襯~~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,並在最後棋子結束移動以後再打開全局鎖。到此爲止,全部的遊戲規則都知足了~~

      今天就到這裏吧。。。下次帶來一個頁面跑馬燈的效果~~

相關文章
相關標籤/搜索