簡體   English   中英

如何使所有的條以不同的速度同時平滑地移動?

[英]How to make all the bars move smoothly at the same time even though they are moving at different speeds?

我有 5 個進度條,它們都以不同的速度同時移動。 它們的速度是動態的,需要以編程方式修改,這就是為什么這是用 JS 實現的,而不是使用 CSS 的動畫。這是一個 jsfiddle: https://jsfiddle.net/ezg97/ey319g48/7/
問題是這樣的:進度條移動不穩定,我希望它們都能順利移動,我不確定如何完成這個? 這是我正在構建的游戲。

如果它們以非常小的數字(如 1)遞增,則它們看起來幾乎是在平穩移動; 然而,實際上他們將能夠以任何速度移動。

代碼也可以在這里查看:

 // array to maintain progress bars var pbArr = [{ pid: 'bar1', // parent container id speed: 31, // max speed value accl: 10, // speed at which it will accelerate curr: 0, // current speed dist: 0 // total distance/displacement }, { pid: 'bar2', speed: 40, accl: 1, curr: 0, dist: 0 }, { pid: 'bar3', speed: 21, accl: 20, curr: 0, dist: 0 }, { pid: 'bar4', speed: 35, accl: 6, curr: 0, dist: 0 }, { pid: 'bar5', speed: 25, accl: 16, curr: 0, dist: 0 }]; var loopCnt = 1; // loop count to maintain width var pb_timeout; // progress bar timeout function // create progress bar funtion var createPB = function () { var is_all_pb_complete = true; // flag to check whether all progress bar are completed executed for (var i = 0; i < pbArr.length; i++) { var childDiv = document.querySelector('#' + pbArr[i].pid + ' div'); // child div // When initially starting, set current speed to acceleration speed if (pbArr[i].curr === 0) { pbArr[i].curr = pbArr[i].accl; } else { // if the current speed + the acceleration is less than top speed, add more acceleration if ((pbArr[i].curr + pbArr[i].accl) < pbArr[i].speed) { pbArr[i].curr += pbArr[i].accl; } // if the current speed + the acceleration is greater than acceleration, then make current speed equal to top speed else { pbArr[i].curr = pbArr[i].speed; } } // removed output: console.log(pbArr[i]); // add the current speed to the distance traveled already pbArr[i].dist += pbArr[i].curr; var newWidth = pbArr[i].dist; // new width //if your new distance traveled is less than 100, add it to the progress bar if (newWidth <= 100) { is_all_pb_complete = false; childDiv.style.width = newWidth + '%'; } else { // if your new distance traveled is greater than or equal to 100, set the prgoress bar to 100% childDiv.style.width = '100%'; } } if (is_all_pb_complete) { // if true, then clear timeout clearTimeout(pb_timeout); return; } loopCnt++; // increment loop count // recall function pb_timeout = setTimeout(function () { createPB(); }, 1000); } // call function to initiate progress bars createPB();
 .bar{ width:200px; height:20px; background-color:black; position:relative; }.child{ position:abosoute; top:0px; left:0px; background-color:red; height:20px; }.clr{ width:100%; height:2px; }
 <div class="bar" id="bar1"><div class="child"></div></div> <div class="clr"></div> <div class="bar" id="bar2"><div class="child"></div></div> <div class="clr"></div> <div class="bar" id="bar3"><div class="child"></div></div> <div class="clr"></div> <div class="bar" id="bar4"><div class="child"></div></div> <div class="clr"></div> <div class="bar" id="bar5"><div class="child"></div></div>

我在最初提出這個問題時看到了這個問題,但沒有時間。 另一個答案最近使它復活了。

當然,問題在於您每秒重新繪制一次。 這不可能導致平滑 animation。我們可以嘗試使用一些固定的亞秒級增量來解決這個問題,並按固定的時間表重新運行。 這會比這更平滑,但仍然可能會不穩定,因為瀏覽器可能會根據其他負載以不同的速率接收您的請求。 下一個技巧是使用setTimeout / setInterval調用下一步,並使用現在和我們開始確定我們在 animation 中的位置之間的時間差,進行適當的更改。 那是十年前最先進的 state,但瀏覽器供應商意識到,如果他們提供 API 會更容易,使這更容易。 那就是requestAnimationFrame 我們向這個 function 提供回調,它用當前經過的時間調用我們。 我們使用該經過的時間來確定我們的 animation 的當前 state 並更新 DOM。 AFAICT,對於那些出於任何原因不能使用 CSS 動畫的人來說,這仍然是藝術的 state。

唯一的問題是您的代碼沒有使用連續技術來計算位置。 相反,您使用加速度更新當前速度並使用當前速度更新 position。我們想要一個連續的 function,它不僅接受1s2s3s等時間,而且還0.18641s2.5184s 為此,我們需要使用一些簡單的微積分。

您可能還記得給定時間的速度 function 是給定時間 function 對 position 的導數。 而加速度的function是速度的導數。 使用一些初始值,我們可以使用反導數的另一種方式 go。 如果這聽起來很復雜,給定一個固定的加速度,就像在這個問題中一樣,但實際上並非如此。 唯一的復雜性來自最大速度值。 沒有它,給定加速度a ,初始速度0和初始 position 0 ,我們可以計算速度v和 position, p ,如下所示:

v = a * t
p = (a/2) * t^2 

僅通過最簡單的反導數。

知道我們有一個最大速度,比如說m ,我們將不得不調整這些。 這些現在更加復雜,但並非絕對可怕:

v = a * t                           when t < m/a
v = m                               when t >= m/a

p = (a/2) * t^2                     when t < m/a
p = m ( t - m/a) + (a/2 * (m/a)^2)  when t >= m/a

最后一個可以簡化為

p = (a/2) * t^2                     when t < m/a
p = m ( t - m/a) + (m^2 / 2a)       when t >= m/a

我們現在可以用不可變的數據結構(我的首選)編寫這段代碼,通過從時間、初始加速度和最大速度應用這個 function 來獲得新的dist屬性,這些數據結構在每一步都被轉換成新的數據結構。 它可能看起來像這樣:

 const processPbs = (pbs) => (time) => { const t = time / 1000 const newPbs = pbs.map (setPosition (t)) displayPbs (newPbs) if (newPbs.some (({dist}) => dist < 100)) { window.requestAnimationFrame (processPbs (newPbs)) } } const setPosition = (t) => (pb) => ({... pb, dist: Math.min (100, t < pb.speed / pb.accl? (pb.accl /2) * t ** 2: pb.speed * (t - pb.speed / pb.accl) + ((pb.speed) ** 2 / (2 * pb.accl))) }) const displayPbs = (pbs) => pbs.forEach (({pid, dist}) => document.querySelector('#' + pid + ' div').style.width = dist + '%' ) var pbArr = [{pid: 'bar1', speed: 31, accl: 10, dist: 0}, {pid: 'bar2', speed: 40, accl: 1, dist: 0}, {pid: 'bar3', speed: 21, accl: 20, dist: 0}, {pid: 'bar4', speed: 35, accl: 6, dist: 0}, {pid: 'bar5', speed: 25, accl: 16, dist: 0}] window.requestAnimationFrame (processPbs (pbArr))
 .bar {width: 200px; height: 20px; background-color: black; position: relative;}.child {position: abosoute; top: 0px; left: 0px; background-color: red; height:20px;}.clr {width:100%; height:2px;}
 <div class="bar" id="bar1"><div class="child"></div></div><div class="clr"></div> <div class="bar" id="bar2"><div class="child"></div></div><div class="clr"></div> <div class="bar" id="bar3"><div class="child"></div></div><div class="clr"></div> <div class="bar" id="bar4"><div class="child"></div></div><div class="clr"></div> <div class="bar" id="bar5"><div class="child"></div></div>

我們主要的 function 是processPbs ,它接受一個進度條列表並返回一個 function 需要時間,用它來創建一個新版本的進度條,使用上面的公式設置dist屬性,然后顯示新的條,如果還有任何尚未達到神奇的100閾值,則請求額外的 animation 幀以重復該過程。

它使用兩個助手。 setPosition使用該公式進行實際計算, displayPbs更新 DOM。 一個強烈的建議是您始終將 DOM 更改隔離到與您的邏輯不同的函數中。

這里有些事情我們可能想改變。 我們應該將 DOM 節點緩存在我們的對象中,而不是在每次迭代時重新計算它們。 我把它留給讀者作為練習。 我們也可能決定不想要所有這些臨時對象,並選擇改變 static 進度條列表中的值。 不過,我只會在脅迫下這樣做,因為我更喜歡不可變數據。 但如果存在性能問題,這將不會太難實現。

它有助於一點點添加transition: all 0.1s ease; 到你的.child class,但並沒有完全解決它。


enter code here

##你知道嗎,你可以使用教程中的CSS 動畫

在 MDN web 開發人員不要忘記使用 JavaScript 動態更改它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM