Cocos2d和SpriteBatchNode:无法识别导致Assertion失败的精灵帧

时间:2013-02-20 12:05:22

标签: cocos2d-iphone frame sprite assertions spritebatch

我已经问了类似的东西,但我无法弄清楚如何调试这个。这是question

我添加了一些Exceptions处理程序(捕获所有Objective-C)异常,这是我看到的结果:

call stack trace

console output

问题在于setTexture方法,它在断言时失败,验证需要显示的纹理名称是否与当前sprite批处理节点中的纹理名称相同。

尝试将一个场景替换为另一个场景但不会一直发生时会发生这种情况。它与新场景有关,因为我试图通过从游戏的不同部分调用替换来“隔离”问题,但它仍然会给它带来麻烦。

在游戏场景中,我有几个精灵表和精灵批处理节点,但由于我没有设法隔离一个精灵表ID,我无法理解哪个精灵框架给我的问题,以及我不明白为什么有时会发生这种情况。

我想:

  • 了解哪个精灵框架名称为我提供了AssertionFailure
  • 了解它属于哪个精灵表

这应该有助于我理解它是否是命名问题,或者是否与其他问题有关。

希望这个问题不要太蹩脚..

编辑:我尝试了答案,但我无法读取'fileName'信息,这是调试器所说的“摘要不可用”:

Summary unavailable

这就是我创建文件名属性的方法:

/** TMP: Bug solving filename */
@property (copy) NSString *fileName;

-(id) initWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize
{
    if( (self=[super init]) )
    {
        self.fileName = [NSString stringWithFormat:@"GLUINT texture name: %i", texture.name];
        self.texture = texture;
        rectInPixels_ = rect;
        rect_ = CC_RECT_PIXELS_TO_POINTS( rect );
        offsetInPixels_ = offset;
        offset_ = CC_POINT_PIXELS_TO_POINTS( offsetInPixels_ );
        originalSizeInPixels_ = originalSize;
        originalSize_ = CC_SIZE_PIXELS_TO_POINTS( originalSizeInPixels_ );
        rotated_ = rotated;
    }
    return self;
}

-(id) initWithTextureFilename:(NSString *)filename rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize
{
    if( (self=[super init]) )
    {
        self.fileName = fileName; //TMP
        texture_ = nil;
        textureFilename_ = [filename copy];
        rectInPixels_ = rect;
        rect_ = CC_RECT_PIXELS_TO_POINTS( rect );
        offsetInPixels_ = offset;
        offset_ = CC_POINT_PIXELS_TO_POINTS( offsetInPixels_ );
        originalSizeInPixels_ = originalSize;
        originalSize_ = CC_SIZE_PIXELS_TO_POINTS( originalSizeInPixels_ );
        rotated_ = rotated;
    }
    return self;
}

2 个答案:

答案 0 :(得分:2)

在这种情况下,日志记录是你的朋友。每次创建CCAnimate动作(或CCAnimation)时,都应该记录下面的内容:

// during 'create sprite frames from sprite frame names' loop
NSLog(@"adding sprite frame name for CCAnimate: %@", spriteFrameName);

// after CCAnimate was created
NSLog(@"creating CCAnimate %@ with sprite frames: %@, animate, arrayOfSpriteFrames);

您可能希望添加更多细节,例如将哪些精灵帧名称添加到该CCAnimate。如果您缓存CCAnimations并在以后重复使用它们,则可能还必须添加其他日志记录(在重用时记录每个CCAnimation)。

现在,当您收到该错误时,您应该在调用堆栈中选择[CCSprite setDisplayFrame:]方法。然后调试器将显示它想要设置的CCSpriteFrame的值。查找指针值,它将读取0x254fb22e

之类的内容

在日志中搜索该值,这将返回到“创建CCAnimate ..”日志之一。从上面的日志行中可以看到它包含的精灵帧名称。由于您还记录了'arrayOfSpriteFrames',您可以获取它们的指针值,将其与导致断言的CCSpriteFrame的指针值进行比较。

如果匹配,并且它是精灵帧数组中的第四项,只需查找添加到CCAnimate的第四个精灵帧名称。

根据调试器中可用的信息(以及您在调试中的精通程度),可能有更快的方法来执行此操作,但这是一种方法,肯定会导致您相对于相对违规的精灵帧名称时间很短。

请注意,指针值不是唯一的 - 可能是使用相同的指针值创建了不同的CCAnimate。特别是如果CCAnimate播放和停止的频率很高,则可能发生另一个CCAnimate分配在前一个CCAnimate的完全相同的内存位置。如果结果似乎不匹配,请小心谨慎。一种快速的方法是在不同的设备或模拟器与设备上进行测试,因为指针值和分配策略各不相同。

您无需记录哪个精灵框架名称属于哪个纹理图集。只需打开每个地图集的plist并搜索精灵框架名称。 plist是一个XML文件。

提示:此问题的常见原因可能是在两个不同的纹理图集中使用相同的精灵框架名称 - 当您请求具有重复名称的精灵框架时,cocos2d可能会使用任一纹理。

另一个提示:如果日志记录看起来令人生畏,我只需执行以下操作:

  • CCSpriteFrame类的开源代码
  • 使用'copy'属性
  • 添加NSString *属性'filename'
  • 每次创建CCSpriteFrame对象时,都要将文件名指定给CCSpriteFrame

现在每当您在调试器中看到CCSpriteFrame时,它都会在调试器视图中显示相关的文件名。

答案 1 :(得分:1)

好吧,看起来你曾经去过那里......评论第一个NSAssert,取消注释if块。然后在新取消注释的NSAssert上放置一个断点。执行将在异常之前暂停,您应该检查调用堆栈中每个类实例的iVars(至少我可以使用AppCode,希望xCode允许)。也许你会得到足够的暗示来弄清楚哪个纹理/动画/蝙蝠侠给你带来了困难。

另外...... fyi。每当我使用cocos2d(任何版本)启动项目时,我会对它应用一些“标准”修复程序,以便我的生活更容易调试。标准的“补丁”是为CCNode添加一个名称,我将其设置为一些有意义的值:always。我也覆盖descpription方法返回我的名字。分配有意义的名称已经帮助了很多次,尤其是在向下(或向上)节点层次结构以找出错误时。我还会在很多情况下(尤其是在ctors中)核对许多NSAsserts,返回nil并记录错误消息。根据Stefen的建议,如果cocos2d ctor给我一个零,我会发出错误日志消息。然后,我可以打破该日志声明并深入解决问题。