如何检测时间轴播放头越过音频片段startTime的时刻以仅触发一次播放
方案1:单帧区间判断+状态标记(最易实现,适合少量clip场景)
核心思路是记录上一帧的时间,判断当前帧时间t和上一帧时间lastT的区间是否刚好覆盖了clip的startTime,同时给每个clip加播放状态标记避免重复触发,支持播放头来回拖拽的场景。
// 初始化时给所有clip加播放状态标记,同时记录上一帧时间 let lastT = 0 const clips = [clip_green, clip_lightblue, clip_darkblue, clip_gray] clips.forEach(clip => clip.hasPlayed = false) playhead.callbackForEveryFrame(doStuffOnEveryFrame) function doStuffOnEveryFrame(t) { clips.forEach(clip => { // 仅当startTime落在(上一帧时间, 当前帧时间]区间内,且未播放过才触发 if (!clip.hasPlayed && clip.startTime > lastT && clip.startTime <= t) { clip.play() clip.hasPlayed = true } // 播放头往回拖时重置对应clip的播放状态 if (clip.hasPlayed && clip.startTime > t) { clip.hasPlayed = false } }) lastT = t }
方案2:预排序+滑动指针(适合大量clip场景,性能更优)
如果你的clip数量很多,每帧遍历所有clip效率低,可以提前把clip按startTime升序排序,维护一个待触发的指针,每帧只需要检查指针位置往后的clip,不需要遍历全部,均摊时间复杂度接近O(1)。
// 提前按startTime从小到大排序所有clip const clips = [clip_green, clip_lightblue, clip_darkblue, clip_gray].sort((a,b) => a.startTime - b.startTime) let currentClipIndex = 0 let lastT = 0 playhead.callbackForEveryFrame(doStuffOnEveryFrame) function doStuffOnEveryFrame(t) { // 只检查还没触发过的clip while (currentClipIndex < clips.length) { const currentClip = clips[currentClipIndex] if (currentClip.startTime > lastT && currentClip.startTime <= t) { currentClip.play() currentClipIndex++ } else if (currentClip.startTime > t) { // 已经排过序,后面的clip时间都更大,直接跳出循环 break } else { // 处理往回拖的情况,指针回退 currentClipIndex-- } } lastT = t }
方案3:预调度方案(无需每帧判断,性能最优)
如果播放头支持匀速播放,不需要实时拖拽的场景,可以直接在初始化阶段给每个clip按startTime调度播放任务,完全不需要在每帧回调里做判断。
const clips = [clip_green, clip_lightblue, clip_darkblue, clip_gray] // 假设播放头速度为1单位/秒,按startTime调度播放 clips.forEach(clip => { setTimeout(() => { clip.play() }, clip.startTime * 1000) })
如果支持拖拽操作,只需要在拖拽结束的时候清空旧的定时器,按当前播放头位置重新计算调度时间即可。
内容的提问来源于stack exchange,提问作者Megidd
相关产品推荐
相关产品推荐

