当 XNA windows 游戏关闭时,如何阻止 SoundEffect 使它们崩溃?
Posted
技术标签:
【中文标题】当 XNA windows 游戏关闭时,如何阻止 SoundEffect 使它们崩溃?【英文标题】:How do you stop SoundEffect from crashing XNA windows games when they are closed? 【发布时间】:2011-02-24 17:45:08 【问题描述】:我正在使用 Visual C# Express 在 xna 中为 windows 创建一个游戏。在游戏中,有六个 SoundEffect 对象定期调用其 Play() 方法。问题是有时当游戏关闭时它会崩溃。 似乎在播放音效时关闭窗口时会发生这种情况。这是在 Visual C# 中弹出的消息:
AccessViolationException 未处理
试图读取或写入受保护的内存。这通常表明其他内存已损坏。
Visual Studio 中没有任何可调试的源,当单击“获取此异常的一般帮助”时,会弹出一个空白页面..
使用的代码看起来很像 MSDN 示例。这看起来像是存在于底层框架某处某处的问题,而不是我的代码。但我当然不确定。这已经发生了很多次。
http://msdn.microsoft.com/en-us/library/bb195053.aspx
以下是完整的异常详情:
System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=Microsoft.Xna.Framework
StackTrace:
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type)
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type)
at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args)
InnerException:
(我也有通过 MediaPlayer 播放的音乐,但我认为这无关。)
编辑:我似乎找到了一些可行的方法,但它有点老套,真的没有必要。我仍然愿意接受任何更优雅的解决方案。
在 Game1.UnloadContent() 中调用这一行。它将确保(如果您的音效都短于 3 秒)在程序实际关闭时没有声音播放。
System.Threading.Thread.Sleep(3000);
【问题讨论】:
UnloadContent 的代码是什么样的? (而且,从模板项目开始时,你能重现这个吗?) 【参考方案1】:将 SoundEffect 对象设为类成员,并在类解构时调用 SoundEffect 的 Dispose() 方法:
class MyClass
~MyClass()
effect.Dispose();
SoundEffect effect;
这应该让 SoundEffect 对象在您关闭游戏时自行清理。您可以在此处阅读有关一次性对象的信息:http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
【讨论】:
我确实这样做了,但崩溃仍然发生。 您是否尝试过从 SoundEffect 对象获取 SoundEffectInstance 并从 SoundEffectInstance 调用 Play? 这里使用析构函数和Dispose
非常不正确!。您不应在终结器中的另一个对象上调用Dispose
,因为该对象可能在终结器运行时已经终结。终结器永远不应该引用另一个对象。 (正确的说法是破坏,而不是破坏)。
你的第一个答案也是不正确的——但没有那么严重。
否决,因为在 C# 中不能保证在进程退出时调用终结器,因此上面的代码将没有预期的效果。【参考方案2】:
你能让 MyClass 实现 IDisposable 并在该方法中处理 SoundEffect 吗?
【讨论】:
ContentManager.Load
加载的资源归 ContentManager 本身“所有”,应使用ContentManager.Unload
卸载。不要给他们打电话Dispose
。【参考方案3】:
我认为可以肯定地说这是框架中的一个错误。因为它在音频代码中,所以框架可能没有正确处理从驱动程序获取的内容。很难确定。
可以说从框架中出来的AccessViolationException
是不“正常的”。这几乎可以肯定不是你的错。
发生异常的函数IsEventRegistered
是unsafe
函数。因此,该函数很可能正在执行异常所说的操作:它正在访问无效的内存地址。
异常来自音频捕获(麦克风)的关闭代码,那么您是否在代码中对麦克风进行了处理?您可以尝试使用/不使用麦克风,看看会发生什么。
另外:在没有附加调试器的情况下运行时会发生这种情况吗? (Ctrl+F5)
至于解决问题:您的解决方案不错。
如果你等不起这三秒钟,并且你想弄脏自己的手并编写一些非常有问题(半不可移植,不一定向前兼容)代码:你可以使用反射来访问音频系统的私有属性。查找每当您调用 SoundEffect.Play
时在内部创建的 SoundEffectInstance
对象列表,然后在关闭之前停止这些实例。
或者您也可以通过从不调用Play
而是调用CreateInstance
并自行管理即发即弃音效来有效地做同样的事情。缺点是这需要编写大量代码!
【讨论】:
【参考方案4】:我遇到了同样的问题,我在类终结器(析构函数)中为我的声音集合做了空值。对我有用。
public class Audio
private ContentManager content;
public List<SoundEffectInstance> SoundInstance get; private set;
public AudioEmitter Emitter get; set;
public AudioListener Listener get; set;
public List<SoundEffect> Sound get; set;
public Audio(ContentManager content)
this.content = content;
Emitter = new AudioEmitter();
Listener = new AudioListener();
Sound = new List<SoundEffect>();
SoundInstance = new List<SoundEffectInstance>();
//set to null your sound instances and effects :D
~Audio()
Sound = null;
SoundInstance = null;
...
【讨论】:
以上是关于当 XNA windows 游戏关闭时,如何阻止 SoundEffect 使它们崩溃?的主要内容,如果未能解决你的问题,请参考以下文章
在运行 XNA 游戏时在 Visual Studio 中观看控制台输出面板