在C#中优化多个调度通知算法?

抱歉标题,我想不出更好的方式来描述问题。 基本上,我正在尝试在游戏中实现碰撞系统。 我希望能够注册一个“碰撞处理程序”来处理可以转换为特定类型的两个对象(按任意顺序给出)的任何碰撞。 因此,如果Player : Ship : EntityLaser : Particle : Entity ,以及(Ship, Particle)(Laser, Entity)处理程序被注册而不是(Laser, Player)的碰撞,则应通过参数通知两个处理程序按正确的顺序, (Laser, Laser)的碰撞应该只通知第二个处理程序。

一个代码片段说了千言万语,所以这就是我现在正在做的事情(naieve方法):

  public IObservable<Collision> onCollisionsOf() where T1 : Entity where T2 : Entity { Type t1 = typeof(T1); Type t2 = typeof(T2); Subject<Collision> obs = new Subject<Collision>(); _onCollisionInternal += delegate(Entity obj1, Entity obj2) { if (t1.IsAssignableFrom(obj1.GetType()) && t2.IsAssignableFrom(obj2.GetType())) obs.OnNext(new Collision((T1) obj1, (T2) obj2)); else if (t1.IsAssignableFrom(obj2.GetType()) && t2.IsAssignableFrom(obj1.GetType())) obs.OnNext(new Collision((T1) obj2, (T2) obj1)); }; return obs; } 

然而,这种方法非常慢(可测量;实现此后我丢失了~2 FPS),所以我正在寻找一种方法来削减几个周期/分配。

我想过(因为花了一个小时实现然后把我的头撞到墙上是因为这样一个白痴)一种方法,根据他们的哈希码将类型放入一个顺序,然后将它们放入字典中,每个条目都是用于该类型对的处理程序的链接列表,其具有布尔指示处理程序是否需要反转的参数顺序。 遗憾的是,这对派生类型不起作用,因为如果传入派生类型,它将不会通知订阅者基本类型。 任何人都可以想到比检查每个类型对( 两次 )以查看它是否匹配更好的方法?

谢谢,罗伯特

所有这些反思都不会很快。 注意每次碰撞时reflection是如何发生的。 那就是问题所在。

一些想法。

思想第一:访客模式。

在OO语言中实现合理快速的双虚拟调度的标准方法是通过构建访问者模式的实现。

您是否可以实施一种访客模式,即访问者中的每个接受者都会保留一份“在这种情况下要做的事情”的列表? 然后你的加法器方法包括确定编写新“要做的事情”的正确位置,然后将委托添加到该事物。 当碰撞发生时,您启动访问者进行双重调度,找到要做的事情的委托,并调用它。

你需要的不仅仅是双重调度吗? 高效的多虚拟调度是可行的,但并不简单。

思想二:动态调度

C#4具有动态调度function。 它的工作方式是我们在第一次遇到呼叫站点时使用reflection来分析呼叫站点。 然后,我们动态生成新的IL以执行调用,并缓存IL。 在第二次调用时,我们会反思这些参数,看它们是否与以前完全相同。 如果是,我们重新使用现有的IL并调用它。 如果没有,我们再次进行分析。 如果参数通常只有几种类型,那么缓存很快就会开始只是点击而没有未命中,并且所有事情都考虑了性能。 当然比每次reflection都要快。 我们每次做的唯一反映就是分析参数的运行时类型。

思想三:实施自己的动态调度

DLR正在做什么并不神奇。 它做了一次分析,吐出一些IL并缓存结果。 我怀疑你的痛苦正在发生,因为你每次都在重新进行分析。

如果每个Entity都有一个标识其实体类型的属性,并且您刚刚获取了该属性的值,那么这会不会更快?

然后,如果你有一个处理程序中实体顺序的约定,那么激光总是在玩家之前等等。

您的实体类型可以是枚举,枚举顺序可以是您的处理程序对象顺序。

 public IObservable> onCollisionsOf() where T1 : Entity where T2 : Entity { EntityTypeEnum t1 = T1.EntityType; EntityTypeEnum t2 = T2.EntityType; Subject> obs = new Subject>(); _onCollisionInternal += delegate(Entity obj1, Entity obj2) { if (t1 < t2) obs.OnNext(new Collision((T1) obj1, (T2) obj2)); else obs.OnNext(new Collision((T1) obj2, (T2) obj1)); }; return obs; } 

我假设你有两套碰撞:激光/播放器和激光/激光。 如果您愿意使IObservable >匹配这两种情况,那么您将能够将委托减少到只有一个检查并且为比较提供所有强类型。

 _onCollisionInternal += delegate(T1 obj1, T2 obj2) { obs.OnNext(new Collision( obj1, obj2)); }; public IObservable> onCollisionsOf() where T1 : Entity where T2 : Entity { Subject> obs = new Subject>(); _onCollisionInternal += delegate(T1 obj1, T2 obj2) { obs.OnNext(new Collision( obj1, obj2)); }; return obs; } Observable> lp = onCollisionsOf(); Observable> ll = onCollisionsOf();