2011-08-06 13 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コールバックをトリガーします。私が考えることができるのは、このアニメーションを関数の中に入れて、自身に再帰呼び出しを行い、次にstep:function(){}の中に「ビューポートで表示」チェックを行い、stop(true,false)の場合はtrueと呼び出します。これはちょうど非常に高価なチェックのように思えます - 400-1200msで100回以上計算するとアニメーションが不安定になるので、より洗練されたソリューションを探しています。

TL; DR: は、どのように私はそれが原因追加のアニメーションは、それに設定されることにまだその先に到達していない限り、何かをアニメーション保つのですか?

UPDATE:私は@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)); 
} 

は、ここで私がこれまで持っているものです:jQueryの何かを持っている必要がありますようにそれはそうかかわらhttp://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/

私はこのアイデアを気に入っ内蔵それは私が望んでいたものです。今、$(obj).stop()の代わりに私はclearInterval($(obj).data('interval').timer_id);する必要があります。 *傷ヘッド...

+1

アニメーションを手作業で行うことを検討しましたか?もしあなたがまだページ上にあるならば、あなたは1つのステップを実行し、次のステップのために 'setTimeout'を呼び出すことができます。そうすれば、ステップ数を事前に計算しようとするアニメーションを心配する必要はありません。 –

+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にコールバック「それがなくなっている」したいと思います。その場合は、あなたは偽の1つの要素オブジェクトとのポインタをしたいと思いますタイマーの外部リストをきれいにして無駄をなくしましょう。


animateでこれをやろうとしているとの問題はanimateは、冒頭にステップ数を計算し、その後、あなたはそれを変更することができるということです。さまざまなステップ数が必要ですが、animateは気にしません。

+0

これは確かなアイデアです。私は今それを試し、それがどのように行くのかを教えてあげます。風を事前に計算する限り、風のアイデアはランダム性を作り出すことです。私は基本的に一方の側から他方の側へ蝶をアニメーション化しています。彼らがどのように飛んでいるか考えると、それは鳥のようなものではありません。スピードアップ、スローダウン、上昇、下降は非常に散発的です。 2分の1秒ごとに風の "突風"は、私はその乱雑さを作成するために計算する必要があります。私には数分の手紙があります。 – AlienWebguy

+0

@AlienWebguy:私が「事前計算」を使って言いたいことは、各ステップで可能な限り少ないことです。たとえば、タイマーが始まる前に 'var $ x = $(x)'を実行できるときに '$(x)'を実行しないでください。 'wind'を閉じると、' .data'を呼び出すオーバーヘッドがなくても永続的な値を持つことができます。 –

関連する問題