C# 当窗口有焦点时,XNA滞后

C# 当窗口有焦点时,XNA滞后,c#,xna,lag,C#,Xna,Lag,我正在使用XNA3.1为xna游戏研究开发,我注意到一些游戏存在一个问题,尽管系统有足够的资源来处理它们,但它们仍然存在延迟,并且处理器使用量过多,令人费解。当游戏中的窗口处于焦点时,进程1(在任务管理器中)将达到100%的使用率,并且游戏显示出轻微的延迟迹象(当声音效果按顺序重复时,显著)。当游戏失去窗口焦点时,它会继续实时绘制和更新,但进程使用率会降低,延迟也会消失 我已经在各种游戏中对此进行了测试,结果保持不变,证明这与我的代码或代码效率无关 这是一个与XNA3.1隔离的问题吗?是否有解决

我正在使用XNA3.1为xna游戏研究开发,我注意到一些游戏存在一个问题,尽管系统有足够的资源来处理它们,但它们仍然存在延迟,并且处理器使用量过多,令人费解。当游戏中的窗口处于焦点时,进程1(在任务管理器中)将达到100%的使用率,并且游戏显示出轻微的延迟迹象(当声音效果按顺序重复时,显著)。当游戏失去窗口焦点时,它会继续实时绘制和更新,但进程使用率会降低,延迟也会消失

我已经在各种游戏中对此进行了测试,结果保持不变,证明这与我的代码或代码效率无关


这是一个与XNA3.1隔离的问题吗?是否有解决方案?还是我必须切换到4.0,希望我的游戏不要使用任何不向后兼容的东西?

根据我的经验,XNA在对焦时每秒运行60帧,在对焦时每秒运行约20帧。但是,如果已将
IsFixedTimeStep=false当进程处于焦点时,游戏将以尽可能快的速度运行。在我的游戏中,在我的机器上,它以500-700 fps的速度运行。这与发生的
Update()
调用的数量有关。所以我的游戏每秒更新500-700次

我敢打赌,你已经禁用了固定的时间步,大量的更新和抽签调用消耗了你100%的核心,这会干扰你的音乐。我建议删除行
IsFixedTimeStep=false如果它在那里。如果代码中不存在这一行,这就不是问题所在,尽管我敢打赌您的更新或绘图所做的工作比它应该做的要多


刚刚在我自己的游戏中注意到这一点,我的更新循环中有一个Console.WriteLine语句(用于调试),这会导致很多延迟。

XNA在窗口未聚焦时添加睡眠! 不久前,我解决了这个问题,覆盖了游戏类,改变了游戏类理解其形式是否处于活动状态的方式

据我所知,在不使用代码修改游戏类行为的情况下,无法禁用此行为

特别是,我不久前发现的方法是一个真正的黑客怪癖! 非常不干净的溶液,但我找到的唯一方法

public class MyGame
{
    private MethodInfo pActivate;

    public MyGame()
    {
        // We need to access base HostActivate method, that unfortunally, is private!
        // We need to use reflection then, of course this method is an hack and not a real solution!
        // Ask Microsoft for a better implementation of their class!

        this.pActivate = typeof(Game).GetMethod("HostActivated", BindingFlags.NonPublic | BindingFlags.Instance);
    }

    protected sealed override void OnDeactivated(object sender, EventArgs args)
    {
        base.OnDeactivated(sender, args);

        // Ok, the game form was deactivated, we need to make it believe the form was activated just after deactivation.

        if (!base.Active)
        {
            // Force activation by calling base.HostActivate private methods.
            this.pActivate.Invoke(this, new object[] { sender, args });
        }
    }
}

该问题可能是由垃圾收集器引起的。每次垃圾收集器运行时,帧速率可能会下降一两秒钟,不过在Windows上这不应该是个问题

将这一行添加到代码中,查看生成了多少堆内存。每次值下降时,都会运行垃圾收集器

 SpriteBatch.DrawInt64(FONT, GC.GetTotalMemory(false) / 1000 /* in kilobytes */, new Vector2(5, 30), Color.White, 0f);
SpriteBatch.DrawInt64是一个SpriteBatch扩展,它不会在int、long等上生成垃圾。您也可以使用SpriteBatch.DrawString(…,(GC.GetTotalMemory(false)/1000).ToString(),…)

SpriteBatchExtensions.cs: