上一篇完成了播放器的 Play、Pause、Reset,現在已經可以讓演算法快照自己一步一步播放。
但真的開始看動畫後,又出現新的需求:
所以今天要繼續幫播放器加入 Speed、Previous Step、Next Step。
上一篇已經有一個很重要的狀態:currentStep。
它代表「現在正在顯示第幾張快照」。
按下 Play 後,會透過 setTimeout 每隔一段時間讓 currentStep + 1,直到按下暫停,或播放到最後一步。
所以不管是自動播放還是手動切換,本質上都只是在決定:
currentStep 什麼時候 +1、-1。
下一步很簡單:
function next() {
pause()
if (!isLastStep.value) {
currentStep.value++
}
}
上一步則反過來:
function prev() {
pause()
if (currentStep.value > 0) {
currentStep.value--
}
}
同時也要限制範圍,避免第一步還繼續往前,或最後一步繼續往後。
這是我實作時遇到的一個問題。
假設動畫正在:
Step 3 → Step 4 → Step 5 → ...
這時候突然按「上一步」,如果只是:
currentStep.value--
setTimeout 其實還在背景等待。
結果就可能變成我才手動回到 Step 3,時間一到,它又自己跑到 Step 4。
所以我的做法是:
只要手動按 Previous 或 Next,就先暫停自動播放。
function prev() {
pause()
// 再處理 currentStep
}
這樣「自動播放」和「手動切換」就不會同時發生衝突。
如果想繼續播放,再自己按一次 Play 就可以了。
速度控制其實沒有讓演算法本身跑得比較快。
它改的是上一篇 setTimeout 的等待時間。
我目前設定:
const BASE_INTERVAL = 700
真正等待的時間則是:
BASE_INTERVAL / speed.value
所以:
0.5× → 700 / 0.5 = 1400ms
1× → 700 / 1 = 700ms
2× → 700 / 2 = 350ms
也就是說,倍速越高,每張快照等待的時間越短。
這裡又有一個小問題。
假設目前正在用 0.5× 播放,我突然按下 2×,難道要等原本的 1400ms 結束後才變快嗎?
我希望按下去就直接套用新速度,所以播放中修改速度時,會重新安排下一次 setTimeout:
function setSpeed(value: number) {
speed.value = value
if (isPlaying.value) {
scheduleNext()
}
}
因此切成 2× 後,下一步就會使用新的等待時間。
做到這裡,原本只能自動播放的演算法動畫,已經可以:
而且做到最後才發現,這些功能其實都圍繞著同一件事情:
播放器不用知道 Bubble Sort、Quick Sort 或 Dijkstra 到底在做什麼,它只需要知道現在是第幾個 currentStep。
演算法負責把每一步準備成快照,播放器則負責決定現在要看哪一步,以及多久之後進到下一步。
【放完成後的播放器 Vue 畫面】
完整實作紀錄: