在单独的线程中更新物理引擎,这是明智的吗?
我对线程是 100% 的新手,作为开始,我决定用它来在单独的线程中更新我的物理。我正在使用名为 Farseer 的第三方物理引擎,这就是我正在做的事情:
// class level declarations
System.Threading.Thread thread;
Stopwatch threadUpdate = new Stopwatch();
//In the constructor:
PhysicsEngine()
{
(...)
thread = new System.Threading.Thread(
new System.Threading.ThreadStart(PhysicsThread));
threadUpdate.Start();
thread.Start();
}
public void PhysicsThread()
{
int milliseconds = TimeSpan.FromTicks(111111).Milliseconds;
while(true)
{
if (threadUpdate.Elapsed.Milliseconds > milliseconds)
{
world.Step(threadUpdate.Elapsed.Milliseconds / 1000.0f);
threadUpdate.Stop();
threadUpdate.Reset();
threadUpdate.Start();
}
}
}
这是更新物理的好方法还是应该有一些我应该注意的东西?
I'm 100% new to threading, as a start I've decided I want to muck around with using it to update my physics in a separate thread. I'm using a third party physics engine called Farseer, here's what I'm doing:
// class level declarations
System.Threading.Thread thread;
Stopwatch threadUpdate = new Stopwatch();
//In the constructor:
PhysicsEngine()
{
(...)
thread = new System.Threading.Thread(
new System.Threading.ThreadStart(PhysicsThread));
threadUpdate.Start();
thread.Start();
}
public void PhysicsThread()
{
int milliseconds = TimeSpan.FromTicks(111111).Milliseconds;
while(true)
{
if (threadUpdate.Elapsed.Milliseconds > milliseconds)
{
world.Step(threadUpdate.Elapsed.Milliseconds / 1000.0f);
threadUpdate.Stop();
threadUpdate.Reset();
threadUpdate.Start();
}
}
}
Is this an ok way to update physics or should there be some stuff I should look out for?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在游戏中,您需要将物理更新与游戏的帧速率同步。这是因为您的渲染和游戏玩法将取决于物理引擎每帧的输出。您的物理引擎将取决于每帧的用户输入和游戏事件。
这意味着在单独的线程上计算物理的唯一优点是它可以在单独的 CPU 核心上运行,而与游戏逻辑和渲染的其余部分无关。 (现在对于 PC 来说相当安全,移动领域才刚刚开始获得双核。)
这允许它们同时运行物理和游戏/渲染 - 但缺点是您需要某种机制来阻止一个线程当另一个线程正在使用该数据时修改数据。这通常很难实施。
当然,如果您的物理不依赖于用户输入 - 例如《愤怒的小鸟》或《不可思议的机器》(即:用户按下“播放”并且模拟运行) - 在这种情况下,您就有可能提前计算物理模拟,记录其输出以供回放。但是,您可以将这个耗时的操作移至后台线程,而不是阻塞主线程 - 这是一个很好理解的问题。您甚至可以在主线程中开始播放录音,甚至在录音完成之前!
In a game you need to synchronise your physics update to the game's frame rate. This is because your rendering and gameplay will depend on the output of your physics engine each frame. And your physics engine will depend on user input and gameplay events each frame.
This means that the only advantage of calculating your physics on a separate thread is that it can run on a separate CPU core to the rest of your game logic and rendering. (Pretty safe for PC these days, and the mobile space is just starting to get dual-core.)
This allows them to both physics and gameplay/rendering run concurrently - but the drawback is that you need to have some mechanism to prevent one thread from modifying data while the other thread is using that data. This is generally quite difficult to implement.
Of course, if your physics isn't dependent on user input - like Angry Birds or The Incredible Machine (ie: the user presses "play" and the simulation runs) - in that case it's possible for you to calculate your physics simulation in advance, recording its output for playback. But instead of blocking the main thread you could move this time-consuming operation to a background thread - which is a well understood problem. You could even go so far as to start playing your recording back in the main thread, even before it is finished recording!
一般来说,你的方法没有任何问题。将物理引擎计算等耗时的操作移至单独的线程通常是一个好主意。但是,我假设您的应用程序在 UI 中包含物理对象的某种视觉表示?如果是这种情况,您将会遇到问题。
Silverlight 中的 UI 控件具有线程关联性,即您无法在上例中创建的线程内更新它们的状态。为了更新它们的状态,您必须通过调度程序调用,例如 TextBox.Dispatcher.Invoke(...)。
另一种替代方法是使用 Silverlight BackgroundWorker。这是一个有用的小类,可以让您完成耗时的工作。它将您的工作移至后台线程,从而无需创建您自己的 System.Threading.Thread。它还将为您提供将结果编组回 UI 线程的事件。
简单多了!
there is nothing wrong with your approach in general. Moving time-consuming operations, such as physics engine calculations to a separate thread is often a good idea. However, I am assuming that your application includes some sort of visual representation of your physics objects in the UI? If this is the case you are going to run into problems.
The UI controls in Silverlight have thread affinity, i.e. you cannot update their state from within the thread you have created in the above example. In order to update their state you are going to have to invoke via the Dispatcher, e.g. TextBox.Dispatcher.Invoke(...).
Another alternative is to use a Silverlight BackgroundWorker. This is a useful little class that allows you to do time-consuming work. It will move your work onto a background thread, avoiding the need to create your own
System.Threading.Thread
. It will also provide events that marshal results back onto the UI thread for you.Much simpler!