一个使用两个线程的简单 C# 游戏循环,这样好吗? [关闭]

Posted

技术标签:

【中文标题】一个使用两个线程的简单 C# 游戏循环,这样好吗? [关闭]【英文标题】:A simple C# game loop using two threads, is this good? [closed] 【发布时间】:2012-11-08 13:31:46 【问题描述】:

我正在使用 C# 中的 GDI+ 创建一个简单的游戏。

首先我需要一个游戏循环和一个渲染循环。我决定将它们分成两个单独的线程。它似乎可以工作,并且运行得非常快,但我在这里问的原因是因为我看到人们在他们的游戏循环中使用计时器来让它们以特定的帧速率运行。

这显然具有优势,您可以确定演员移动的速度。但我的游戏循环只是尽可能快地运行,就像 Unity3D 中的更新功能一样。现在为了确保演员总是以相同的速度移动,我所要做的就是将移动速度乘以帧增量时间(每帧之间的时间)。

我的渲染循环也尽可能快地运行。这是一个很好的游戏循环,为什么或为什么不?

// Constructor
public FormDisplay()

    // Create a thread object, passing in the GameLoop method
    var gameThread = new Thread(this.GameLoop);

    // Start the game thread
    gameThread.Start();

    // Create a thread object, passing in the GameLoop method
    var renderThread = new Thread(this.RenderLoop);

    // Start the render thread
    renderThread.Start();


private void GameLoop()

    while (true)
    
        // TODO: Insert Game Logic
    


private void RenderLoop()

    while (true)
    
        // TODO: Insert Render Logic
    

【问题讨论】:

我没有任何实际的游戏编程经验,但我的直觉是,将更新“推送”到渲染而不是轮询它可能会更好。我的意思是,如果有变化,你能通知 UI 并让它采取相应的行动吗?因此,当屏幕上没有任何变化并且用户处于空闲状态时,您不会浪费 CPU 周期。也许这不是一个好主意,正如我所说,没有经验,只是一个提示。 在我看来,您在这里有 三个 线程:GameLoop 线程、RenderLoop 线程和产生其他两个线程的 主线程。 . @Davio:大多数 3Dish 游戏必须在发生任何变化时推送整个场景。 (无论如何,OpenGL 和 Direct3D API 都是这样做的。)如果场景中有任何东西发生变化,则需要重新显示整个东西。 如果您的while(true) 中没有任何限制,每个线程将以 100% 的 CPU 负载运行,这可能会减慢您将来需要的其他线程(例如 KI)以及整个系统没有做任何有意义的事情。 哦,是的@cHao,你说得对,我有三个线程:-) 【参考方案1】:

您应该将屏幕刷新率视为限制因素。如果您的屏幕每秒只更新 100 次,那么每秒移动演员 300 次是没有意义的。

同样,当显示器刷新率仅为 100 Hz 时,每秒渲染屏幕 300 次可能会出现撕裂现象。当缓冲区出现在​​屏幕上时更新帧缓冲区时会发生这种情况,因此演员的上半部分出现在旧位置,下半部分出现在新位置。

一篇关于减少闪烁的好文章是 Stack Overflow question Reduce flicker with GDI+ and C++

理想情况下,作为一般的游戏循环,您的游戏线程应该处理并构建一个列表以传递给渲染线程以进行下一次屏幕刷新(也就是说,您始终在处理下一个显示的帧)。然后两个线程都等待下一帧。这当然意味着您需要知道何时会发生这种情况——我认为您无法找到使用 GDI+ 进行渲染的情况。

【讨论】:

我使用双缓冲,它可以很好地处理闪烁。我正在考虑拥有一个精灵列表,然后在渲染循环中对所有精灵调用渲染方法。我必须使用 GDI+,因为它是一个学校项目。我仍然不确定您是否希望游戏循环尽可能快地运行,或者这只是在浪费 CPU 周期。 它在浪费 CPU 周期。如果我正在编写它,我会尝试在每次屏幕刷新时运行一次游戏循环,理想情况下与刷新同步。就我个人而言,我仍然会按照您的建议使用基于时间的定位,这样丢帧就不那么重要了。【参考方案2】:

在不了解库本身(或.NET GUI)如何使用线程的情况下直接管理自己的线程的想法似乎是个坏主意。

我确定您将需要线程,但我不确定您是否需要自己显式地管理它。让底层库来处理这个问题,并将工作推送到主 UI 线程/从主 UI 线程推送。

【讨论】:

我真的不明白为什么我不应该管理自己的线程。我可能没有使用线程的经验,但至少我会学到一些东西。从主 UI 线程推送或拉取听起来更复杂 tbh :-) 多线程是一样的,不管你跨越哪个线程。最好使用内置机制,而不是重新创建***。看看ayende 对这个主题的一些想法:ayende.com/blog/search?q=multithread

以上是关于一个使用两个线程的简单 C# 游戏循环,这样好吗? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

C#多线程实现循环。界面会假死怎么办?

C# WPF 坦克大战

游戏循环 - 元素存在的时间越长越快

无需冻结gui的简单任务

C# 线程异步处理

构建和同步多线程游戏循环