我正在进行塔防游戏,而且我坚持寻路的多线程。如果我不进行NSInvocationOperation的寻路操作,那么在渲染中会有越来越多的停顿,我有更多的恶魔和塔。
但是我无法解决“锁定”问题。关于枚举我的恶魔NSMutableArray,我会经常发生崩溃。如果我在完成寻路时尝试锁定主线程中的枚举,游戏仍会锁定,我已经失去了多线程的全部内容..
我如何解决这类问题?
答案 0 :(得分:3)
想想放置另一座塔时会发生什么。敌人要么在他们的路径决定中要么考虑新塔,要么不考虑。确定这些新路径需要时间,无论您选择何种多线程解决方案,都会导致延迟。问题最终在于你的寻路算法。如果计算时间太长,那么你会看到延迟。
看看你可以避免找到这些路径的方法。在位置(x,y)下降塔会影响所有敌人吗?你能算出一些路径,敌人会选择跟随哪一条路径吗?您是否可以缓存路径并重复使用已经计算过的部分(例如河流如何通过分支支流流动)?
我认为有很多方法可以减少问题中路径查找的影响。
答案 1 :(得分:1)
我同意Tim Rupe的观点,即优化寻路可能会有所帮助。
另一种(附加)方法是将“当前”路径数组与“下一个”路径数组分开。因此,游戏继续使用当前的路径数组,而下一个数组则在另一个线程中计算。这可以避免死锁,崩溃等等。
然后,在某个明确定义的点上,您将'next'替换为'current'(由互斥锁或其他任何东西保护)。基本上,您总是处理快照 - 但您可以控制快照交换的速率(前提是您的寻路算法不会太慢)。
答案 2 :(得分:1)
线程肯定有助于延迟策略,例如在路径查找完成之前开始向总体方向移动。
编辑:我错过了你说你的恶魔阵列造成了问题。我认为你最好的选择是松耦合。尽量不要让路径查找器依赖于你的恶魔阵列。只发送一个恶魔所需数据的副本(起始位置,目标位置等)并获得一系列积分。不要让它访问整个数组,甚至不能引用任何恶魔对象。
答案 3 :(得分:1)
跨线程边界发送可变数据是解决问题的好方法。在将对象发送到另一个线程时,应始终使用NSArray
,NSString
,NSSSet
等代替其可变子类。这个简单的规则使多线程变得更加愉快。
值得庆幸的是,所有集合类都实现了NSCopying
协议,因此有一个漂亮的-[copy]
方法返回s本身的不可变副本。
接下来你需要决定的是如果改变原始数组该怎么做。你能不能:
选项1.只添加一个新操作是最简单的,但如果您的原始数组经常变异,可能会浪费时间。 选项2.需要您做更多的工作。更具体地说:
-[NSOperation cancel]
消息。或者,如果您有一个仅限于路径查找的队列,则可以使用[NSOperationQueue cancelAllOperations]
取消对其进行的所有操作。NSOperation
,您不能再按原样使用NSInvocationOperation
。 您的NSOperation
子类实现应该如下所示:
@implementation CWPathfinderOperation
-(id)initWithFiends:(NSArray*)fiends delegate:(id<CWPathfinderOperation>)delegate {
self = [super init];
if (self) {
self.fiends = fiends;
self.delegate = delegate;
}
return self;
}
-(void)main {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
while (notDone) {
if ([self isCancelled]) goto bailOut;
// Do smallpart of work
}
[self.delegate performSelectorOnMainThread:@selector(pathfinderOperatioDidFindPaths:)
withObject:result
waitUntilDone:NO];
bailOut:
[pool release];
}
@end