2011-08-06 30 views
5

想象一下,我有一個具有指定寬度和高度的視口。我克隆一個元素出來查看右側,並且在隨機y位置代碼,它飛跨視這樣的:JQuery動畫 - 任何方式來「拖延」完整的觸發器?

... 
    .css({ 
     'left': BASE_NODE_INIT_LEFT_PX, 
     'top' : rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px', 
     'width': _width + 'px', 
     'height': _height + 'px', 
    }) 
    .animate({ 
     left: BASE_NODE_ANIMATE_DISTANCE_X_PX 
    } 
    ... 

夠簡單的動畫。以下是有趣的部分:每一步我都想對這個元素應用一些物理。

事情是這樣的:

 ... 
     step:function(currentStep){ 
      if($(this).data('animating-wind') !== true) 
      { 
       $(this).data('animating-wind',true); 
       var wind = (rand(1,2) == 2) ? '+=' + rand(1, 100) + 'px' : '-=' + rand(1, 100) + 'px'; 
       $(this).animate({ 
        'top': wind, 
        'text-indent': wind, 
       },{ 
        duration: 500, 
        complete: function(){ 
         $(this).data('animating-wind',false); 
        }, 
        queue: false 
       }); 
      } 
     } 
     ... 

基本上發生的事情是,而不是從右側直接穿過飛往左,它會減慢,加快和提高了隨機驟降,只是因爲我打算。

我面臨的問題是,有時「風」足夠強大,以便當步數達到總計算步數時該元素仍然可以在視口上看到,並且它會消失(發生這種情況在我complete:function(){ ...$(this).remove(); ...}

顯然發生了什麼是JQuery的認爲動畫完成,因爲它計算的步驟,並說:「我在動畫這個對象在過這麼多步驟的毫秒這麼多的像素 - 它的存在。」不過,風動畫是以外的動畫隊列所以這個動畫過程是非明智的。

我想開始動畫並保持動畫效果,直到元素從任何方向退出視口 - 一旦它不再可見,無論是從其最初的飛行路徑還是從風扇吹過屏幕,我都會檢測到它並觸發onComplete回調。我能想到的唯一的事情就是把這個動畫放到一個函數中,並在complete:function(){}中對自己進行遞歸調用,然後在step:function(){}內部執行「在視口中可見」檢查並且如果true調用stop(true,false)。這看起來像是一個非常昂貴的檢查 - 在400-1200ms內運行100次以上可能會導致動畫波濤洶涌,所以我正在尋找更優雅的解決方案。

TL; DR:由於額外的動畫 如何防止動畫的東西,只要還沒有到達它的目的地尚未被設置就可以了?

更新:我申請@mu is too short's idea以及與此想出了:

/** 
* Create a new clone of the master div for user interaction. Position it 
* randomly off the canvas, and animate it across at a random speed. 
*/ 

function spawn_target() { 
    spawn_timeout = setTimeout(function() { 
     var bonus = (rand(1, BONUS_ODDS) == BONUS_ODDS) ? ' ' + BONUS_CLASS : ''; 
     var _img_src = (bonus.length > 0) ? BONUS_NODE_IMG_SRC : BASE_NODE_IMG_SRC; 
     var _width = $('#' + BASE_NODE_ID).width(); 
      _width = Math.floor(rand(_width/3, _width)); 
     var _height = _width; 
     var _framerate = 10 - Math.floor(_height/10); 
     var _clone = $('#' + BASE_NODE_ID).clone().addClass(CLONE_CLASS + bonus).attr('id', CLONE_ID).appendTo('#' + CANVAS_ID).css({ 
      'left': BASE_NODE_INIT_LEFT_PX, 
      'top': rand(BASE_NODE_INIT_TOP_MIN_PX, BASE_NODE_INIT_TOP_MAX_PX) + 'px', 
      'width': _width + 'px', 
      'height': _height + 'px', 
     }) 

     $(_clone).children('img').attr('src', _img_src); 

     /** 
     * Handle the actual flight across the viewport 
     * @param object _this The clone we are animating manually 
     * @return object pointer This contains the interval so we can clear it later 
     */ 
     function fly(_this) { 

      var animating_wind = false; 
      var pointer = { 
       timer_id: null 
      }; 
      pointer.timer_id = setInterval(function() { 

       // Get rid of the node if it is no longer visible in the viewport 
       if (!$(_this).is(':onviewport')) { 
        clearInterval(pointer.timer_id); 
        $(_this).remove(); 
        adj_game_data(GAME_DATA_LIVES_ID, -1); 
        check_lives(); 
        spawn_target(); 
       } 

       // Move node along with slight realism 
       var distance = rand(FLY_DISTANCE_MIN, FLY_DISTANCE_MAX); 
       $(_this).css('left', '-=' + distance + 'px'); 

       // Only trigger the wind animation when it is idle 
       if (animating_wind !== true) { 
        animating_wind = true; 

        // Setup the wind physics 
        var _wind_power = rand(WIND_POWER_MIN, WIND_POWER_MAX); 
        var _wind_dir = (rand(1, 2) == 2) ? '+=' : '-='; 

        // Override wind direction to keep node inside viewport 
        if(($(_this).offset().top + $(_this).height() + _wind_power) > CANVAS_HEIGHT) 
        { 
         _wind_dir = '-='; 
        } 
        if(($(_this).offset().top - _wind_power) < CANVAS_TOP_BUFFER_PX) 
        { 
         _wind_dir = '+='; 
        } 

        var _wind = _wind_dir + _wind_power + 'px'; 

        // Apply the wind physics and don't let the node break the top or bottom 
        // boundaries of the viewport 
        $(_this).animate({ 
         'top': _wind 
        }, { 
         duration: WIND_ANIMATION_DURATION, 
         complete: function() { 
          animating_wind = false; 
         }, 
         queue: false 
        }); 
       } 
      }, _framerate); 

      return pointer; 
     } 
     $(_clone).data('interval', fly(_clone)); 

    }, rand(SPAWN_TARGET_TIMEOUT_MIN, SPAWN_TARGET_TIMEOUT_MAX)); 
} 

這是我到目前爲止有:http://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/

我喜歡這個主意雖然它看起來像jQuery應該有一些內置這正是我所希望的。現在,我不得不$(obj).stop()clearInterval($(obj).data('interval').timer_id);。 *劃痕頭......

+1

您是否考慮過親自動手製作動畫?如果你仍然在頁面上,你可以做一步,併爲下一步調用'setTimeout',然後不斷重複,直到它停止。那麼你不必擔心試圖預先計算步數的'animate'。 –

+0

你可以嘗試使用+ =而不是 - =,這樣它就會隨風而流。這意味着它會超過停止位置而不是下衝,但是如果沒有演示,我不知道這種效果會導致什麼結果。你能發佈整個動畫功能嗎? –

+0

等不及要看演示! –

回答

1

這是我認爲你應該做的(僞的JavaScript):

function animate_it($thing) { 
    var wind  = false; 
    var timer_id = setInterval(function() { 
     // Compute the movement for this step. 
     // Then factor in the wind effect and update the `wind` variable. 
     // Then apply the movement to `$thing`. 
     if(it_is_off_the_page($thing)) 
      clearInterval(timer_id); 
    }, n); 
} 

如果在計算一遍又一遍內計算什麼,預先計算它在animate_it的水平,並讓封閉關閉它。你會想玩弄一下,以找出應該是什麼n

只需手動操作動畫,讓您不會與jQuery的animate函數作戰,並在知道完成後停止動畫。這也可以讓你爲風免費提供一個方向和力量(這樣你的動畫物體可以倒退)。

您可能想讓timer_id回到外面的世界,以便您可以從外面阻止整個事情。在這種情況下,你會想用假一元對象的指針:

function animate_it($thing) { 
    var wind = false; 
    var pointer = { timer_id: null }; 
    pointer.timer_id = setInterval(function() { 
     // Compute the movement for this step. 
     // Then factor in the wind effect and update the `wind` variable. 
     // Then apply the movement to `$thing`. 
     if(it_is_off_the_page($thing)) { 
      clearInterval(pointer.timer_id); 
      pointer.timer_id = null; 
     } 
    }, n); 
    return pointer; 
} 

var timer = animate_it($thing); 

// And then later, to shut it down... 
if(timer.timer_id) 
    clearInterval(timer.timer_id); 

你可能會想「就消失了」回調上animate_it,如果你有很多動畫對象,這將讓你保持定時器的外部清單清潔無殘留。


,試圖與animate這樣做的問題是,animate計算的開頭的步數,然後你可以改變這種狀況。你需要不同數量的步驟,但animate不在乎(它甚至比蜂蜜獾更小)。

+0

好吧,這是一個堅實的想法。我現在嘗試一下,讓你知道它是怎麼回事。至於預先計算風,風的想法是創造一個隨機性。我基本上是將蝴蝶從一側移動到另一側,如果你考慮它們如何飛行,它就不像鳥兒。儘管他們盡最大的努力繼續前進,但他們加速,減速,起伏非常零散。每半秒左右風的「陣風」就是我需要計算以創造這種隨機性。給我幾分鐘,我會張貼小提琴。 – AlienWebguy

+0

@AlienWebguy:所有我想說的「預計算」的東西是儘可能少的每一步;例如,在定時器啓動之前,可以執行'var $ x = $(x)'時不要執行'$(x)'。關閉'wind'可以讓你擁有一個持久的值,而不用調用'.data'的所有開銷。 –