Cocos2d iphone Cocos2d和SpriteBatchNode:无法识别导致断言失败的sprite帧

Cocos2d iphone Cocos2d和SpriteBatchNode:无法识别导致断言失败的sprite帧,cocos2d-iphone,frame,sprite,assertions,spritebatch,Cocos2d Iphone,Frame,Sprite,Assertions,Spritebatch,我已经问过类似的问题,但我无法正确地找出如何调试这个问题。这就是问题所在 我添加了一些异常处理程序(捕获所有Objective-C)异常,这就是我看到的结果: 问题在于setTexture方法,在验证需要显示的纹理名称是否与当前sprite批处理节点中的纹理名称相同的断言时失败。 当试图用另一个场景替换一个场景时会发生这种情况,但并非总是如此。这与新场景有关,因为我试图通过从游戏的不同部分调用替换来“隔离”问题,但它仍然会带来麻烦 在游戏场景中,我有两个精灵表和精灵批处理节点,但由于我没有设

我已经问过类似的问题,但我无法正确地找出如何调试这个问题。这就是问题所在

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

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

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

在游戏场景中,我有两个精灵表和精灵批处理节点,但由于我没有设法隔离精灵表id,我无法理解是哪个精灵帧给了我这个问题,我也不理解为什么这种情况只是偶尔发生

我想:

  • 了解哪个sprite框架名称给了我断言失败
  • 了解它所属的精灵表
这应该有助于我理解这是否是一个命名问题,或者这是否与其他事情有关

希望不要在这个问题上显得太蹩脚

编辑:我尝试了答案,但无法读取“文件名”信息,以下是调试器所说的“摘要不可用”:

我就是这样创建filename属性的:

/** 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;
}

在这种情况下,日志记录是您的朋友。每次创建cAnimate操作(或cAnimation)时,都应该记录如下内容:

// 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);
您可能需要添加更多细节,例如哪些精灵帧名称被添加到了该cAnimate中。如果缓存CCAnimation并在以后重用它们(重用时记录每个CCAnimation),则可能还必须添加其他日志记录

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

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

当您有一个匹配项,并且它是精灵帧数组中的第四项时,只需查找添加到CCAnimate的第四个精灵帧名称的名称

根据调试器中的可用信息(以及您在调试中的熟练程度),可能有一种更快的方法来实现这一点,但这是一种肯定会在相对较短的时间内让您找到令人不快的sprite帧名称的方法

请注意,指针值不是唯一的-可能是使用相同的指针值创建了不同的CCAnimate。特别是当cAnimate播放和停止的频率很高时,另一个cAnimate可能被分配到与前一个cAnimate完全相同的内存位置。因此,如果结果似乎不一致,要小心。一个快速找到答案的方法是在不同的设备或模拟器与设备上进行测试,因为指针值和分配策略不同

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

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

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

  • CCSpriteFrame类的开放源代码
  • 添加具有“复制”属性的NSString*属性“filename”
  • 每次创建CCSpriteFrame对象时,将文件名指定给CCSpriteFrame

现在,无论何时在调试器中看到CCSpriteFrame,它都会在调试器视图中显示关联的文件名。

好的,看起来您以前去过那里。。。注释第一个NSAssert,取消注释if块。然后在新未注释的NSAssert上放置一个断点。执行将在异常之前暂停,您应该检查调用堆栈中每个类实例的IVAR(至少我可以使用AppCode,希望xCode允许)。也许你会得到足够多的提示来找出哪个纹理/动画/批处理节点给你带来了困难


还有。。。仅供参考。每当我使用cocos2d(任何版本)启动一个项目时,我都会对它应用一些“标准”修复程序,这样我的调试工作就会更轻松。一个标准的“补丁”是为CCNode添加一个名称,我将其设置为一些有意义的值:always。我还重写了descpription方法以返回我的名字。分配有意义的名称对我有很多帮助,特别是在向下(或向上)遍历节点层次结构以找出bug时。我还核化了许多NSASSERT,只要有可能(特别是在CTOR中),就返回nil并记录一条错误消息。根据Stefen的建议,如果cocos2d ctor返回我一个nil,我会抛出一条错误日志消息。然后,我可以打断日志语句并深入研究问题。

唯一的“坏”问题是没有被问到的问题。不要为这里的“亲密”爱好者担心太多:到处都是教条。@YvesLeBorg谢谢Yves,我感谢你去年在这个论坛上给我的帮助和鼓励。这很有帮助:)谢谢,我会在周末花一些时间来尝试正确的答案。我尝试了答案,但没有分配文件名。。调试器显示“不可用信息”。。