【问题标题】:Sprite Sheet animation fails after upgrading from Cocos2d 1.0.1 to 2.0从 Cocos2d 1.0.1 升级到 2.0 后 Sprite Sheet 动画失败
【发布时间】:2012-04-19 07:59:35
【问题描述】:

我根据在网上找到的一些教程创建了一个简单的 2 帧精灵动画。我拍了两张图片,用 plist 和 png 文件创建了一个精灵表,并将它们合并到我的代码中,如下所示。此设置在 Cocos2d V 1.0.1 中运行良好。我刚刚将我的项目升级到 2.0rc0a,现在我的应用程序在应该从第一帧切换到第二帧时崩溃并出现以下错误:'CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteBatchNode'

我查看了这个SO question,但我不确定这是否与我做错的事情相同,并且因为我对 Cocos2d 还是很陌生,我不确定如何正确调整我的代码。这是我在注释中没有看到的 2.0 更改的内容,我应该报告的错误,还是我的编码不正确?我仍然有一个 1.0.1 项目的副本,其代码相同,并且动画可以正常工作。

//CHAMELEON
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"front page/mainchameleon.plist"];
mainChameleon = [CCSpriteBatchNode batchNodeWithFile:@"front page/mainchameleon.png"];
[self addChild:mainChameleon z:7];
NSMutableArray *chameleonFrames = [NSMutableArray array];
for (int i = 1; i <= 2; ++i) 
{
    [chameleonFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"chameleon%d.png", i]]];
}

CCAnimation *mouthAnim = [CCAnimation animationWithSpriteFrames:chameleonFrames delay:0.3f];
chameleon = [CCSprite spriteWithSpriteFrameName:@"chameleon1.png"];
CCAnimate *chameleonAction = [CCAnimate actionWithAnimation:mouthAnim];
CCDelayTime *chameleonDelay = [CCDelayTime actionWithDuration:10];
CCRepeatForever *chameleonRepeat = [CCRepeatForever actionWithAction:[CCSequence actions:chameleonDelay, chameleonAction, chameleonDelay, nil]]; 
[chameleon runAction:chameleonRepeat];
[mainChameleon addChild:chameleon];

如果我注释掉chameleon = [CCSprite spriteWithSpriteFrameName:@"chameleon1.png"];,那么应用程序不会崩溃,但变色龙根本不会出现,正如当前编写代码的方式所预期的那样。

或者,如果我注释掉 [chameleon runAction:chameleonRepeat];,那么变色龙就会出现并显示帧 chameleon1.png,但显然没有通过动画。

好的,为了让我更加困惑,因为我肯定遗漏了一些东西,我尝试将代码的底部部分更改为此,动画从第 1 帧转到第 2 帧,然后无限期地停留在第 2 帧。但是,如果我使延迟时间超过 1.0,我会收到与之前相同的错误。如果我在操作之前重新包含 chameleonDelay 而没有永远重复语句,我也会遇到同样的崩溃。如果应用程序必须等待超过 1 秒才能执行切换,它似乎会崩溃。我需要的是让第 1 帧坐一会儿(10 秒)然后切换到第 2 帧 0.3 秒,然后切换回第 1 帧并再次坐一会儿。

尝试的代码 #2:

CCAnimation *mouthAnim = [CCAnimation animationWithSpriteFrames:chameleonFrames delay:0.3f]; //<--- maxes out at 1.0. Anything more causes crash
chameleon = [CCSprite spriteWithSpriteFrameName:@"chameleon1.png"];
CCAnimate *chameleonAction = [CCAnimate actionWithAnimation:mouthAnim];     
[chameleon runAction:chameleonAction];
[mainChameleon addChild:chameleon];

YvesLeBorg 建议使用 restoreOriginalFrame 语句,但在 2.0 版中已弃用。我尝试使用

CCAnimation *mouthAnim = [CCAnimation animationWithAnimationFrames:chameleonFrames delayPerUnit:0.3f loops:5];

并得到错误'-[CCSpriteFrame delayUnits]: unrecognized selector sent to instance'。我不确定为什么这不起作用或从这里尝试什么。

编辑:现在它正在工作......但没有像我想要的那样有效地编码:

新代码:

//CHAMELEON
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"front page/mainchameleon.plist"];
mainChameleon = [CCSpriteBatchNode batchNodeWithFile:@"front page/mainchameleon.png"];
[self addChild:mainChameleon z:7];
NSMutableArray *chameleonFrames = [NSMutableArray array];

//Frame 1 - closed mouth
[chameleonFrames addObject:[CCSpriteFrame frameWithTexture:mainChameleon.texture rect:CGRectMake(0, 124, 149, 122)]];
//Frame 2 - Open Mouth
[chameleonFrames addObject:[CCSpriteFrame frameWithTexture:mainChameleon.texture rect:CGRectMake(0, 0, 149, 122)]];
//Frame 1 - closed mouth
[chameleonFrames addObject:[CCSpriteFrame frameWithTexture:mainChameleon.texture rect:CGRectMake(0, 124, 149, 122)]];

CCAnimation *mouthAnim = [CCAnimation animationWithSpriteFrames:chameleonFrames delay:0.9f];
    chameleon = [CCSprite spriteWithTexture:mainChameleon.texture rect:CGRectMake(0,124,149,122)];
CCAnimate *chameleonAction = [CCAnimate actionWithAnimation:mouthAnim];
CCDelayTime *chameleonDelay = [CCDelayTime actionWithDuration:10];
CCRepeatForever *chameleonRepeat = [CCRepeatForever actionWithAction:[CCSequence actions:chameleonDelay, chameleonAction, nil]]; 
[chameleon runAction:chameleonRepeat];
[mainChameleon addChild:chameleon];

我真的很喜欢我在 1.0.1 中的做法,因为如果我有 2 帧或 100 帧,我只需要对 if 语句做一个小的调整。这种方式需要对每个单独的帧进行编码,这似乎与使用 plist 有悖常理。如果在接下来的几天内没有人能够提供更好的解决方案或“真实”答案,我会将其发布为答案并接受它以结束问题。

【问题讨论】:

    标签: animation cocos2d-iphone xcode4.2 ccsprite


    【解决方案1】:

    这是我最终得到的可以正常工作的代码。不知道为什么我必须进行这些更改,但确实如此。 (当我开始一个新项目来解决这个问题时,一些名称已经改变,但我的原始代码和这之间的差异是显而易见的)。对于其他找到此线程的人,我的原始代码基于Ray Wenderlich's sprite sheet tutorial

    CCSpriteBatchNode *chameleonBN = [CCSpriteBatchNode batchNodeWithFile:@"chameleonimages.png"];
        [self addChild:chameleonBN];
    
    //ADDED the texture part to resolve: 'CCSprite: setTexture doesn't work when the sprite is rendered using a CCSpriteBatchNode'   
    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"chameleonplist.plist" texture:chameleonBN.texture];
    
    NSMutableArray *chameleonframes = [NSMutableArray array];
    
    for (int i = 1; i <= 2 ; i++) 
    {
        [chameleonframes addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"chameleon%d.png", i]]];
    }
    
    CCAnimation *mouthAnim = [CCAnimation animationWithSpriteFrames:chameleonframes delay:0.9f];
    
    //ADDED this sprite frame to resolve texture id assert error
    CCSpriteFrame *frame = [CCSpriteFrame frameWithTexture:chameleonBN.texture rect:CGRectMake(0, 0, 149, 122)];
    CCSprite *chameleon = [CCSprite spriteWithSpriteFrame:frame];
    chameleon.position = ccp(512,384);
    CCAnimate *chameleonAnimate = [CCAnimate actionWithAnimation:mouthAnim];
    
    CCDelayTime *chameleonDelay = [CCDelayTime actionWithDuration:10];
    CCDelayTime *chameleonDelay2 = [CCDelayTime actionWithDuration:0.1];//Had to use this to ge tthe mouth to close. Using restore original frame doesn't work for me.
    CCRepeatForever *chameleonRepeat = [CCRepeatForever actionWithAction:[CCSequence actions:chameleonDelay, chameleonAnimate, chameleonDelay2, nil]]; 
    [chameleon runAction:chameleonRepeat];
    [chameleonBN addChild:chameleon];
    

    【讨论】:

    • 你好。首先感谢详细的问题+答案。我今天偶然发现了同样的问题,但我以不同的方式解决了它。现在我不知道哪个是最好的,或者即使我所做的完全正确。在我的一次尝试中,我注意到精灵尺寸剪裁有问题,因此我添加了对 Retina 的检查并据此加载文件。和吹!问题(似乎)已解决。那么你如何处理 Retina 呢?
    • 最后一件事,我的是一个非常简单的动画,只有帧。这可能是相关的。不幸的是,我现在没有时间测试更多帧:(
    • @EngineerGio,我很抱歉延迟回复。我没有更改代码中的任何内容来处理视网膜图形。我从来没有遇到过让视网膜工作的问题。很高兴听到您找到了另一种方法。我想看看代码。
    【解决方案2】:

    不确定这是否是 2.0 问题,但我注意到您在同一序列中使用了两次 chameleonDelay 对象。这真的是你想要完成的吗,即

    delay,action,delay,delay,action,delay,delay,action ....等

    试试这个看看它是否有效:

    CCRepeatForever *chameleonRepeat = [CCRepeatForever actionWithAction:[CCSequence actions:chameleonDelay, chameleonAction, nil]];
    

    【讨论】:

    • 是的,这是故意的。这是一个问题的组合。我发现如果不添加它,由于某种原因,这些动作不会按照我的意图进行,即从第 1 帧到第 2 帧,然后很快回到第 1 帧。没有第二次延迟,它会停留在第 2 帧。我'确定这是我处理它的方式,但无论如何,时间实际上都适合我想要完成的事情。感谢您指出这一点。
    • 为了防止快速返回到第一帧,您可能需要使用 [CCAnimate actionWithAnimation:mouthAnim restoreOriginalFrame:NO]。但无论如何,如果您在同一序列中有两次使用,请尝试创建另一个 CCDelayTime 实例。
    • 抱歉,我的措辞可能不正确。我确实希望它回到第一帧。这是一张嘴巴张开和关闭。在结束此代码之前,我尝试了 restoreOriginalFrame:YES,但它实际上并没有返回到第一帧。不知道为什么。这种编码完全符合我的要求,所以我就不管它了。关于创建第二个实例的观点,我会这样做。
    • 哦,刚刚发现:restoreOriginalFrame: 在 2.0 版中已被弃用。在actionWithAnimation 下甚至不再是一个选项。
    • 我在编辑中发布的新代码解决了必须在序列中复制 chameleonDelay 操作的问题。我还发现虽然声明 [CCAnimate actionWithAnimation:mouthAnim restoreOriginalFrame:YES]; 已弃用,但您可以将 mouthanim.restoreOriginalFrame = YES; 放在它自己的行上,并且不会抛出弃用的警告。这没有达到我预期的效果,(我看不到),所以我只是删除了该声明。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    • 1970-01-01
    • 2014-10-03
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多