Cocos2d和并发:如何正确停止场景之间的动画

时间:2013-06-13 22:19:07

标签: objective-c multithreading concurrency cocos2d-iphone thread-safety

我有一个GameScene(这里叫做ShooterScene),我会退出到MainMenu。我使用sprite表,我加载在纹理缓存中。有各种动画正在进行(背景元素,敌人,玩家等......)。我有几个月的问题,在敌人的“setTexture”方法中有一个断言失败。我通过在替换场景之前暂停共享的CCDirector来解决这个问题。这具有停止动画的效果。但是我只是部分解决了这个问题游戏不再在Enemy setTexture上崩溃,但现在在AnimatedBackgroundElement setTexture方法上崩溃了。

背景元素被添加到精灵批处理节点,该节点是作为子类添加到GameScene的Background类的子节点。我想知道,由于某些层次结构原因,暂停调用的传播有一些延迟,或者“暂停”线程与“暂停”线程之间是否存在一些并发问题 CCAnimate->背景元素的setTexture线程。

有任何建议/想法吗?

PS:我检查了“[[CCDirector sharedDirector] stopAnimation]”并说:

CCLOG(@"cocos2d: Director#stopAnimation. Override me");

我是想“覆盖”这种方法来解决上述问题?我想这将是一个很好的地方,可以通过递归调用来真正停止所有子节点的所有动画,但同样,由于后续“replaceScene”方法的潜在并发性,我不确定延迟。我可以通过使用一系列回调来解决这个问题(CCSequence with action1 = call stop animation and action2 = replace scene)但我再也不能100%确定action2的调用只会在调用结束后才会发生停止动画(action1)。我可以用pheraphs为(所有孩子)写一个递归并将它放在replaceScene之前..或者用延迟回调replaceScene(这不是一个优雅的解决方案,因为它是半任意的)..

-(void) restartLevel
{
    [self resetSharedData];
    [[CCDirector sharedDirector] pause];
    LevelName currentLevel = [GameController sharedGameController].currentlyPlayedLevelName;
     [[CCDirector sharedDirector] replaceScene:[ShooterScene sceneWithLevelName:currentLevel]];
}


-(void) exitToMainMenu
{
    [self resetSharedData];
    [[CCDirector sharedDirector] pause];
    [[CCDirector sharedDirector] replaceScene:[MainMenu scene]];
}

PPS:我发现在尝试posts场景时有各种相关的stop。我想其他人可能会有类似的问题,因此可能会有最先进的解决方案/设计模式。

编辑:我已尝试实现此功能,但仍然失败。

-(void) restartLevel
{
    [self resetSharedData];
    [[CCDirector sharedDirector] pause];
    LevelName currentLevel = [GameController sharedGameController].currentlyPlayedLevelName;

    [self stopAllActions];   //Does this actually stopAllActions and Animations for ALL child nodes?
    [self unscheduleAllSelectors];
    //Do I need something else here?
     [[CCDirector sharedDirector] replaceScene:[ShooterScene sceneWithLevelName:currentLevel]];
}

2 个答案:

答案 0 :(得分:1)

愚蠢的问题,为什么[self stopAllAnimations];不工作?我称之为[self uncheduleAllSelectors];在场景改变之前,它会破坏整个层中的每个动画对象和计时器,这样可以安全地切换没有断言失败的场景。

关于暂停的事情,我知道!!说真的,整个暂停的事情真的很狡猾,似乎暂停了一些东西,但它并不总是暂停的东西。据我所知,当你暂停时:定时器停止(并且dt没有增加),加速度计和触摸仍然有效,动画对象和移动物体停止移动,菜单按钮仍然有效,所有代码都在函数内部菜单按钮调用仍然运行。此外,它完成调用暂停的函数内的所有代码,因此如果您执行暂停然后取消计时器并在一个函数中更改场景,则仍会出现分配错误。

这是我的工作,更具体地说: - 停止所有动画 - 停止所有计时器 - 将变量“gameRunning”设置为false,并在gameLogic的第一行if(!gameRunning)返回; - 设置一个0.1秒的计时器,仅激活一次以调用makeTransition功能 - 在计时器内进行实际场景更改。

答案 1 :(得分:1)

[self stopAllActions];并没有真正停止添加到图层子节点的所有操作。您需要在特定节点上手动调用stopAllActions。

-(void)onExit
{
   [self.gameHeroSprite  stopAllActions]; //call this for all animated sprite
   [self stopAllActions];
   [super onExit];
}