我试图在XNA 4,C#上创建类似粒子系统的东西。
我已经创建了一个函数,如果粒子足够接近,它们会让粒子彼此移动。它包含循环周期,因此它是滞后的。没有这个功能,程序开始滞后400-500颗粒,功能 - 接近180。
问题1.我可以通过创建后台线程来处理这些粒子碰撞来改善性能吗?
因此,创建了内部计时器工作的线程。当我启动我的游戏时,它开始正常,但当粒子数量超过接近130-150时,会出现运行时错误Collection has changed
。无法执行枚举。" (它是来自另一种语言的翻译,而不是确切的消息)。
收集"邻居" - 函数Particle.RunAwayFromNeighbours
中的局部变量 - 在枚举过程中被更改,然后,我认为,一个线程以某种方式调用函数,而前一个调用未完全执行。一件奇怪的事。
我尝试使用Threading.Monitor
类来同步调用,但我对多线程编程的经验很少,所以我觉得我做错了。它没有解决问题,但是在相同的粒子数下它仍然是同样的错误。
我也尝试使用lock
运营商,但情况仍然如此。
问题2.如何最终同步线程?
有班主任,他"拥有"一些粒子。其他线程在此类中有效。下面的代码是使用Monitor类编写的。 代码(......不是必需的部分):
class Player
{
...
Thread CollisionThread;
static double check_period=100;
System.Timers.Timer checktimer = new System.Timers.Timer(check_period);
public void StartCollisionChecking()
{
checktimer.AutoReset = true;
checktimer.Elapsed += (o, e) => { CheckCollisions(); };
CollisionThread = new Thread(this.CheckCollisionCycle);
CollisionThread.Start();
} //call in LoadContent
void CheckCollisionCycle()
{
checktimer.Start();
} //call 1 time in new thread
void CheckCollisions()
{
for (int i = 0; i < Army.Count - 1; i+=2 )
{
var p = Army[i];
p.RunAwayFromNeighbours();
}
} //called in CheckCollisionCycle
}
class Particle : VO
{
static float neighbour_search_radius = 2;
static float run_speed_q = 0.1f;
IEnumerable<Particle> CheckForNeighbours()
{
return owner.GetArmy().Where(a => Vector2.Distance(a.location.GetXY(), location.GetXY()) < neighbour_search_radius);
}
public void RunAwayFromNeighbours()
{
object x = new object() ;
Monitor.Enter(x);
try
{
var neighbours = CheckForNeighbours();
foreach (Particle p in neighbours)
{
Vector2 where_to_run = location.GetXY() - p.location.GetXY();
speed += where_to_run * run_speed_q;
}
}
finally
{
Monitor.Exit(x);
}
}
答案 0 :(得分:0)
有可能neighbours
期间正在修改foreach
,请尝试:
foreach (Particle p in neighbours.toList())
看看是否对其进行排序。
这将让您迭代neighbours
的副本。它不是最佳解决方案(你应该首先避免这种冲突),但它是一个快速的解决方法,看看它是否真正存在于故障所在。< / p>
答案 1 :(得分:0)
我通过做两件事解决了这个问题: 我在类Particle中添加了bool变量,它显示了线程是否完成了它的工作。它看起来像这样:
public bool thread_completed = true;
public void RunAwayFromNeighbours()
{
thread_completed = false;
object x = new object() ;
Monitor.Enter(x);
try
{
var neighbours = CheckForNeighbours().ToList();
foreach (Particle p in neighbours)
{
Vector2 where_to_run = location.GetXY() - p.location.GetXY();
speed += where_to_run * run_speed_q;
}
}
finally
{
Monitor.Exit(x);
thread_completed = true;
}
2。我换线了
return owner.GetArmy().Where(a => Vector2.Distance(a.location.GetXY(), location.GetXY()) < neighbour_search_radius).ToList();
行
return owner.GetArmy().ToList().Where(a => Vector2.Distance(a.location.GetXY(), location.GetXY()) < neighbour_search_radius);