2011-08-06 20 views
5

Hãy tưởng tượng tôi có một chế độ xem có chiều rộng và chiều cao được xác định. Tôi clone một yếu tố ngoài tầm nhìn về phía bên phải, và bay nó qua cửa sổ xem mỗi vị trí ngẫu nhiên y với mã như thế này:JQuery animate - bất kỳ cách nào để "stall" kích hoạt hoàn thành?

... 
    .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 
    } 
    ... 

Simple đủ hình ảnh động. Đây là phần thú vị: trên mỗi bước tôi muốn áp dụng một số vật lý cho yếu tố này.

Something như thế này:

 ... 
     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 
       }); 
      } 
     } 
     ... 

Về cơ bản những gì xảy ra là thay vì bay thẳng qua từ phải sang trái, nó chậm lại, tăng tốc, và đặt ra và dips một cách ngẫu nhiên, cũng giống như tôi đang có ý định.

Sự cố tôi gặp phải là đôi khi "gió" đủ mạnh để phần tử vẫn hiển thị trên chế độ xem khi số bước đã đạt đến tổng số bước được tính toán và nó sẽ biến mất (điều này xảy ra Rõ ràng những gì đang xảy ra là JQuery nghĩ rằng hình ảnh động hoàn tất bởi vì nó tính toán các bước và nói "Tôi đang làm động vật này đối tượng này nhiều điểm ảnh trong nhiều mili giây này qua nhiều bước này - nó ở đó". hình động gió là bên ngoài hàng đợi hoạt ảnh vì vậy quá trình hoạt ảnh này không có gì là khôn ngoan.

Điều tôi muốn là bắt đầu hoạt ảnh và chỉ tiếp tục hoạt ảnh cho đến khi phần tử đã thoát khỏi chế độ xem theo bất kỳ hướng nào - một khi nó không còn nhìn thấy được nữa, hoặc từ đường bay ban đầu hoặc từ gió thổi tắt màn hình, tôi sẽ phát hiện và kích hoạt cuộc gọi lại onComplete. Điều duy nhất tôi có thể nghĩ đến là đặt hoạt ảnh này bên trong một hàm và trong complete:function(){} thực hiện cuộc gọi đệ quy cho chính nó, sau đó bên trong step:function(){} Tôi sẽ thực hiện kiểm tra "hiển thị trong chế độ xem" và gọi stop(true,false) nếu true. Điều này có vẻ giống như một kiểm tra rất tốn kém - chạy mà tính toán 100 lần trong 400-1200ms có thể làm cho hoạt hình choppy vì vậy tôi đang tìm kiếm một giải pháp thanh lịch hơn.

TL; DR: Làm cách nào để tiếp tục tạo hoạt ảnh miễn là chưa đạt đến đích do hoạt ảnh bổ sung được đặt trên đó?

UPDATE: tôi áp dụng @mu is too short's idea và đến với điều này:

/** 
* 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)); 
} 

Dưới đây là những gì tôi có cho đến nay: http://jsfiddle.net/AlienWebguy/DmtQ7/embedded/result/

Tôi thích ý tưởng này mặc dù nó có vẻ như JQuery nên có một cái gì đó built- trong, đó là những gì tôi đã hy vọng. Bây giờ, thay vì $(obj).stop() Tôi phải clearInterval($(obj).data('interval').timer_id);. * Trầy xước đầu ...

+1

Bạn đã cân nhắc thực hiện hoạt ảnh bằng tay chưa? Bạn có thể thực hiện một bước và gọi 'setTimeout' cho bước tiếp theo nếu bạn vẫn ở trên trang, sau đó tiếp tục lặp lại cho đến khi nó dừng lại. Sau đó, bạn sẽ không phải lo lắng về 'animate' cố gắng tính toán trước số bước. –

+0

bạn có thể thử sử dụng + = thay vì - = để nó chảy "bằng gió". Điều này có nghĩa là nó sẽ vượt qua vị trí dừng thay vì undershoot, nhưng không có bản demo, tôi không biết tác dụng này sẽ dẫn đến kết quả gì. Bạn có thể đăng toàn bộ chức năng animate không? –

+0

không thể đợi để xem bản trình diễn! –

Trả lời

1

Đây là những gì tôi nghĩ rằng bạn nên làm (pseudo-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); 
} 

Nếu có bất cứ điều gì trong tính toán bên trong đó là tính hơn và hơn nữa, nó precompute ở mức animate_it và để đóng cửa đóng trên đó. Bạn sẽ muốn chơi với nó một chút để tìm ra những gì n nên được.

Chỉ cần thực hiện hoạt ảnh bằng tay để bạn không chiến đấu với chức năng animate của jQuery và dừng hoạt ảnh khi bạn biết nó được thực hiện. Điều này cũng cho phép bạn bao gồm một hướng và sức mạnh cho gió (để đối tượng hoạt hình của bạn có thể quay trở lại) khá nhiều miễn phí.

Bạn có thể muốn lấy lại timer_id về thế giới bên ngoài để bạn có thể dừng toàn bộ mọi thứ từ bên ngoài. Trong trường hợp đó, bạn muốn giả một con trỏ với một đối tượng là một yếu tố:

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); 

Bạn có thể muốn một "nó đã biến mất" gọi lại trên animate_it nếu bạn đã có rất nhiều đối tượng hoạt hình, mà có thể cho phép bạn giữ danh sách bộ hẹn giờ ngoài của bạn sạch sẽ và không bị trôi dạt.


Vấn đề với cố gắng để làm điều này với animateanimate tính số bước ngay từ đầu và sau đó bạn có thể thay đổi điều đó. Bạn cần một số bước thay đổi nhưng animate không quan tâm (nó quan tâm thậm chí ít hơn một mật ong lửng).

+0

Ok đây là một ý tưởng vững chắc. Tôi sẽ thử nó ngay bây giờ và cho bạn biết làm thế nào nó đi. Theo như tính toán trước gió, ý tưởng của gió là tạo ra một sự ngẫu nhiên. Tôi về cơ bản là làm một con bướm từ bên này sang bên kia, và nếu bạn nghĩ về cách chúng bay, nó không giống như một con chim. Họ tăng tốc độ, làm chậm lại, tăng và giảm rất thường xuyên bất chấp những nỗ lực tốt nhất của họ để tiếp tục tiến lên phía trước. "Gusts" của gió mỗi nửa giây hoặc hơn là những gì tôi cần phải tính toán để tạo ra sự ngẫu nhiên đó. Gimme một vài phút và tôi sẽ đăng một câu đố. – AlienWebguy

+0

@AlienWebguy: Tất cả những gì tôi đang cố gắng nói với công cụ "tiền tố" là làm ít nhất có thể trong mỗi bước; ví dụ, không làm '$ (x)' khi bạn có thể làm 'var $ x = $ (x)' trước khi bộ đếm thời gian bắt đầu. Và đóng cửa trên 'wind' cho phép bạn có một giá trị liên tục mà không cần phải trả phí cho' .data'. –

Các vấn đề liên quan