Skip to content

[Bug] 容器重新分配导致 sf::Sound 播放中断 #3

Description

@EienTokei

描述问题

std::vector<sf::Sound> 中存储的音效在播放过程中会意外中断。

  1. play() 中将开始播放的 sf::Sound 放入容器,运行时却没有声音
  2. 单个 SE 播放正常,但连续播放多个 SE 时全部意外中断。
  3. 当有其他音效播放完毕被清理时,正在播放的长音效会被提前停止。

例如:播放一个 7 秒的走路声,在另一个短音效(0 秒)播放完毕后,走路声随即中断,实际只播放了约 0.7 秒。

复现步骤

场景1. 不采用直接在容器内构造的 emplace_back()
场景2. 在脚本中构建连续多个播放 SE 的指令
场景3. 在通道构造函数中预先分配好容器的容量,同时播放长短不一的多个 SE

预期行为

所有 SE 应该完整播放,互不干扰。

实际行为

各场景处于播放中的 SE 被提前中断。
以场景3为例,7秒的 se_walk 实际只播放了约 0.7 秒。

[14:25:40.029] debug [endeus] SEChannel.cpp       :21  | SE played: se_ok
[14:25:40.029] debug [endeus] GloriousDays.cpp    :23  | get audio asset type: 4 by alias: se_walk
[14:25:40.030] debug [endeus] ResourceCache.hpp   :30  | loadResource: path=assets/audio/se/se_walk.ogg, cached=false
[14:25:40.102] debug [endeus] ResourceCache.hpp   :38  | loadResource: path=assets/audio/se/se_walk.ogg, success=true
[14:25:40.103] debug [endeus] SEChannel.cpp       :21  | SE played: se_walk
[14:25:40.104] debug [endeus] GloriousDays.cpp    :23  | get audio asset type: 4 by alias: se_door_open
[14:25:40.104] debug [endeus] ResourceCache.hpp   :30  | loadResource: path=assets/audio/se/se_door_open.ogg, cached=false
[14:25:40.126] debug [endeus] ResourceCache.hpp   :38  | loadResource: path=assets/audio/se/se_door_open.ogg, success=true
[14:25:40.126] debug [endeus] SEChannel.cpp       :21  | SE played: se_door_open
[14:25:40.127] debug [endeus] Executor.cpp        :92  | FadeLayer: id='door', from alpha 0.8 to 0, duration=1s
[14:25:40.127] debug [endeus] Executor.cpp        :49  | ShowLayer: id='ev_reader', texture='ev_reader', pos=(0,0), alpha=0, order=0
[14:25:40.128] debug [endeus] WorldManager.cpp    :14  | addLayer: id='ev_reader', texture='ev_reader', order=0, pos=(0,0), alpha=0
[14:25:40.128] debug [endeus] Executor.cpp        :92  | FadeLayer: id='ev_reader', from alpha 0 to 1, duration=1s
[14:25:40.128] debug [endeus] Executor.cpp        :122 | SetContent: append=false, text='你选择了...'
[14:25:40.129] debug [endeus] WorldManager.cpp    :87  | setContent: replace mode
[14:25:40.129] debug [endeus] ResourceCache.hpp   :30  | loadResource: path=assets/images/ev/ev_reader.png, cached=false
[14:25:40.214] debug [endeus] ResourceCache.hpp   :38  | loadResource: path=assets/images/ev/ev_reader.png, success=true
[14:25:40.234] debug [endeus] Anemoi.cpp          :24  | Anemoi update: 1 animation(s) completed
[14:25:40.846] debug [endeus] SEChannel.cpp       :41  | update: 1 SE(s) completed
[14:25:41.015] debug [endeus] BGMChannel.cpp      :78  | fade out completed, BGM stopped
[14:25:41.016] debug [endeus] Anemoi.cpp          :24  | Anemoi update: 2 animation(s) completed
[14:25:41.134] debug [endeus] Anemoi.cpp          :24  | Anemoi update: 1 animation(s) completed
[14:25:41.303] debug [endeus] SEChannel.cpp       :41  | update: 1 SE(s) completed
[14:25:41.320] debug [endeus] SEChannel.cpp       :41  | update: 1 SE(s) completed

根因分析

  • SFML 源码中 sf::Sound::setBuffer() 会先调用 stop()
  • sf::Sound 的拷贝构造/拷贝赋值/析构都会触发停止。
  • std::vector 扩容时的重新分配或移除元素的 erase_if 时,元素被拷贝/销毁,导致正在播放的声音中断。

解决方案

已改用 std::array<std::unique_ptr<sf::Sound>, MAX_SE>,避免任何拷贝。

环境

  • 操作系统:Windows 11
  • 引擎版本:0.5.0
  • SFML 版本:3.0.2

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentation

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions