Cocos2d и SpriteBatchNode: не может определить, какой фрейм спрайта вызывает сбой подтверждения
Я уже спрашивал что-то подобное, но я не могу понять, как правильно это отлаживать. Это вопрос.
Я добавил обработчик исключений (перехватывает все исключения Objective-C), и это результат того, что я вижу:
Проблема заключается в методе setTexture, и при проверке он не может проверить, совпадает ли имя текстуры, которое необходимо отобразить, с именем в текущем пакете узлов спрайта.
Это происходит при попытке заменить одну сцену другой, но не всегда. Это связано с новой сценой, поскольку я пытался "изолировать" проблему, вызывая замену из другой части игры, и это все еще доставляет проблемы.
В игровой сцене у меня есть пара листов спрайтов и узлов пакетных спрайтов, но так как мне не удается выделить идентификатор листа спрайта, я не могу понять, какой фрейм спрайта создает мне проблему, а также я не понимаю, почему это бывает только иногда.
Я бы хотел:
- понять, какое имя фрейма спрайта дает мне AssertionFailure
- понять, к какому спрайтовому листу он принадлежит
Это должно помочь мне понять, если это проблема с именами или это связано с чем-то другим.
Надеюсь, что не быть слишком хромым с этим вопросом..
РЕДАКТИРОВАТЬ: Я попробовал ответ, но я не могу прочитать информацию 'fileName', вот что отладчик говорит: "Сводка недоступна":
Вот как я создаю свойство 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;
}
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 будет размещен в той же самой ячейке памяти, что и предыдущий. Так что будьте осторожны, если результаты не совпадают. Быстрый способ выяснить это - протестировать на разных устройствах или на симуляторе против устройства, так как значения указателей и стратегии распределения различаются.
Вам не нужно регистрировать, какое имя фрейма спрайта принадлежит какому атласу текстуры. Просто откройте список для каждого атласа и найдите имя рамки спрайта. Плист является XML-файлом.
Совет: частой причиной этой проблемы может быть одинаковое имя фрейма спрайта в двух разных атласах текстур - cocos2d может использовать любую текстуру при запросе фрейма спрайта с дублированным именем.
Другой совет: если регистрация кажется сложной, я бы просто сделал следующее:
- открытый исходный код для класса CCSpriteFrame
- добавить NSString* свойство 'filename' с атрибутом 'copy'
- каждый раз, когда вы создаете объект CCSpriteFrame, присваивайте имя файла CCSpriteFrame
Теперь, когда вы видите CCSpriteFrame в отладчике, он будет показывать вам связанное имя файла в представлении отладчика.
Хорошо, похоже, что вы были там раньше... Прокомментируйте первый NSAssert, раскомментируйте блок if. Затем поставьте точку останова на вновь закомментированном NSAssert. Выполнение приостановит ПЕРЕД исключением, и вам следует проверить iVars каждого экземпляра класса в стеке вызовов (по крайней мере, я могу это сделать с AppCode, надеюсь, xCode позволяет это). Может быть, вы получите достаточно подсказки, чтобы выяснить, какая текстура / анимация / батчод доставляет вам трудности.
Также... к вашему сведению. Всякий раз, когда я запускаю проект с cocos2d (любой версии), я применяю к нему некоторые "стандартные" исправления, чтобы облегчить отладку моей жизни. Стандартный "патч" - это добавление имени в CCNode, для которого я установил какое-то значимое значение: всегда. Также я переопределяю метод descpription, чтобы вернуть МОЕ имя. Назначение значимых имен помогло мне много раз, особенно когда я шел (или вверх) по иерархии узлов, чтобы выявить ошибку. Я также уничтожил многие NSAsserts и по возможности (особенно в ctors) возвращаю nil и записываю сообщение об ошибке. Согласно предложению Стефена, если кокосовый коктор возвращает мне ноль, я выдаю сообщение об ошибке. Затем я могу разбить эту запись в журнале и изучить проблему.