adding a normal CCSprite to CCSpriteBatchNode crashes - cocos2d-iphone

I am getting this exception in logs
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'CCSprite is not using the same texture id'
What I am trying to do is adding a normal "myfile.png" file to a SpriteBatchNode
**declaration of batch node
CCSpriteBatchNode *_backgroundLayer = [CCSpriteBatchNode batchNodeWithFile:#"sprites.png"];
** usage
This line works perfect
CCSprite *sprite1 = [CCSprite spriteWithSpriteFrameName:#"PngFileKeptInSpriteSheet.png"];
[_backgroundLayer addChild:sprite1];
But, when I use a direct *.png file to add to batch node, It crashes
CCSprite *sprite2 = [CCSprite spriteWithFile:#"myfile.png"];
crashes on line
[_backgroundLayer addChild:sprite2];
On further debugging I found that:
The assertion failure is in file CCSpriteBatchNode.m
inside method -(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag
at line NSAssert( child.texture.name == textureAtlas_.texture.name, #"CCSprite is not using the same texture id");
P.S. : by "normal" I mean not taken from *.plist file

First and foremost, I'd update cocos2D. However, that isn't your problem and probably isn't "fixed" in the latest version anyway. This isn't really a bug
Batch nodes require that all the sprites that you intend to batch are using the same texture. When you load a sprite sheet, it uses one, large texture. When you call spriteWithFile, cocos2d creates a texture from that image.
It's rare that you'll want to create a batch node from a sprite using spriteWithFile. The only scenario I can think of is when you want to draw the same image many times. (Rather than many images from the same texture).
In short, what you are trying to do is unsupported and doesn't make much sense anyway as the two sprites wouldn't be batchable.

Related

Error adding sprites using addchild method: argument must to be non-nil

I've a problem using the method addchild adding sprites
previously I've never had this problem and I could add png files without problems,now sometimes if I try to add some sprites to the scene using the addchild method I receive these errors:
[2126:15503] cocos2d: CCTexture2D. Can't create Texture. cgImage is nil
[2126:15503] cocos2d: Couldn't add image:image_1.png in CCTextureCache
[2126:15503] * Assertion failure in -[HelloWorldLayer addChild:]
I think that the problem isn't in the code because if I try to add sprites using the images included in the default Cocos2d project it works... I receive this error only from some images...also if I've added it by the same way to the project and to the scene, what could be the cause?
I receive this error also using the default helloWorldLayer class, without changing anything, only adding
CCSprite * sprite = [CCSprite SpriteWithFile: #"image_1.png"];
[self addChild:sprite];
the rest of the code is exactly the same of the default HelloWorldLayer class
there could be something that might cause this error in some png files?
Add image_1.png to your Xcode project. Make sure you use the exact same filename, for example Image_1.PNG won't load on devices due to uppercasing.

Having trouble to change different sprite sheet on cocos2d

I am trying to change a different sprite sheet on my cocos2d project.
And i was using spriteSheet.plist and it was working fine. For some reason, I need to add more sprite and change the file to spriteSheet2.plist
And i already include files like spriteSheet2.plist, spriteSheet2.pvr.ccz
But it ends up return a error msg
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'CCSprite is not using the same texture id'
[[CCTextureCache sharedTextureCache] removeUnusedTextures];
[CCSpriteFrameCache purgeSharedSpriteFrameCache];
CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
// [frameCache addSpriteFramesWithFile:#"spriteSheet.plist" ];
[frameCache addSpriteFramesWithFile:#"spriteSheet2.plist" ];
and other issue if i remove my original 'spritesheet.plist' from Xcode. Sprits is still working on the screen.
would anyone tell what should I do to get ride of the error message?
you have a batch node somewhere which was created with the first texture, to which you are trying to add sprites from the second texture. All sprites contained in a batch node must be from the same texture as the texture with which the batch node was created.

reveal the contents of a layer through a rectangle "cut-out" with cocos2d?

I am looking for a way to mask out a layer and reveal the contents of the layer through a rectangle (actually I want multiple rectangles to reveal the underlying layer's content).
I came across this similar question:
Cocos2d iPhone - Sprite cliping/mask/frame
Which had a solution:
http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode/
However, when trying to use this class, I get the warning: "implicit declaration of function 'glPushMatrix' is invalid in C99"... I also get the error: "Property 'deviceOrientation' not found on object of type 'CCDirector *'"
What do I need to do to get this to work with the latest version of cocos2d?
... In any event, I commented out the deviceOrientation stuff, just to test if it will even work, and it doesn't seem to be.
I've got a CCBatchNode:
sheet = [CCSpriteBatchNode batchNodeWithFile:#"bg.png" capacity:500];
Then I add many sprites to that
[sheet addChild:sprite1];
[sheet addChild:sprite2];
[sheet addChild:sprite3];
Then I make the clipping node layer
ClippingNode *clipNode = [ClippingNode node];
clipNode.clippingRegion = CGRectMake(50, 50, 200, 200);
Then I add the sprite sheet and the clipNode:
[layer addChild:sheet];
[layer addChild:clipNode];
Then I add that to the CCSprite object
[self addChild:layer];
...
The result is, I see my many sprites from the sheet, but there is no clipping mask.. And my console shows a million: "OpenGL error 0x0502 in -[CCTextureAtlas drawNumberOfQuads:fromIndex:] 556"
so..... I am not sure what I am doing wrong-- or if this all has to do with the openGL warnings and device orientation errors... ?
UPDATE: I added #include <OpenGLES/ES1/gl.h> to the ClippingNode.m, and it got rid of the glpush/pop warnings.. But still results in the same OpenGL error once I add the clipNode child to the layer...
You can do it with shaders in cocos2d 2.0. Have a look at this tutorial.
http://www.raywenderlich.com/4428/how-to-mask-a-sprite-with-cocos2d-2-0

Cocos2D 2.0 - Can one CCSpriteBatchNode be used for multiple classes?

I don't know if this is possible, but I would like to create one big texture atlas and use it on all classes of the application.
Can one CCSpriteBatchNode be used for multiple classes?
Suppose I create this on the main class
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"atlasGeral.plist"];
self.batchNodeGeneral = [CCSpriteBatchNode batchNodeWithFile:#"atlasGeral.png"];
[self addChild:self.batchNodeGeneral];
and I have another class creating CCLayers on the main class, that is initialized, before using CCSpriteBatchNode, like this:
-(id) init
{
if( (self=[super init])) {
self.bg = [CCSprite spriteWithFile: #"cCircularBG.png"];
[self addChild:self.bg];
self.dr = [CCSprite spriteWithFile: #"cCircularDR.png"];
[self addChild:self.dr];
}
return self; // self is a CCLayer
}
can this be optimized using the self.batchNodeGeneral from the main class? My idea is to replace these two sprites and others with something like [CCSprite spriteWithSpriteFrameName:...
thanks
I'm not entirely sure I follow, but I'm pretty sure the answer is yes.
CCSpriteBatchNode doesn't have anything to do with classes, it has to do with assets. The important restriction on the use of batch nodes is that every sprite in the batch needs to reference the same texture atlas. So it is perfectly fine to have one batch node for your entire application and have every gameplay class add its own sprites to that batch. This can turn into a practical issue if your texture atlas becomes larger than the maximum texture size on your target hardware (see iOS device specs for details), but if you still want to have global batches and lots of assets it's not too hard to create a batch pool indexed by texture ID, create one batch node per atlas, and whenever you create a new sprite add it to the appropriate batch.
Honestly, I feel like the whole batch node thing is a terrible kludge on Cocos2D's part that could be made almost completely transparent to developers while still retaining its efficiency, but maybe this opinion is not entirely fair since I haven't dug around in the rendering code to understand their motivations. I guess it would mess with expectations of how depth sorting works, etc., but still I don't understand why batching objects for render is made the programmer's responsibility, it should be done by the engine.
Edit to add possible solution:
-(id) initWithMainClass:(MainClass*)mc
{
if( (self=[super init])) {
self.bg = [CCSprite spriteWithSpriteFrameName: #"cCircularBG.png"];
[mc.batchNodeGeneral addChild:self.bg];
self.dr = [CCSprite spriteWithSpriteFrameName: #"cCircularDR.png"];
[mc.batchNodeGeneral addChild:self.dr];
}
return self; // self is a CCLayer
}
`
So when you initialize one of the other classes, you pass the main class instance as a parameter so you can access its fields. Or make the main/manager class a singleton or find another architecture suitable to your needs.

cocos2d - Replacing cached sprite image

I'm new to cocos2d. I've been following a tutorial which I've got working but when I updated the image I used to shoot fireballs by deleting and replacing it from the resources folder, the image no longer renders. What do I have to do when replacing an image?
Before I swapped the images:
CCSprite *projectile = [CCSprite spriteWithFile:#"Projectile.png"
rect:CGRectMake(0, 0, 20, 20)];
After swapping images:
CCSprite *projectile = [CCSprite spriteWithFile:#"Fireball.png" rect:CGRectMake(0, 0, 20, 20)];
Do I need to delete the cache somehow and re-add the image?
EDIT:
I added this line below my code and it worked:
[projectile setTexture:[[CCTextureCache sharedTextureCache]
addImage:#"Fireball.png"]];
Strange how I have to add a new line of code to replace an image.
I find that sometimes i need to clean and build for the updated texture to finally make it to the app's bundle ... (I suspect this happens when i change a resource while the app is running, but frankly i have lost too much time with this to investigate). Now i de-facto clean and build when changing resources.
I am not certain this is a 'cocos2d' discussion, but rather an Xcode one. The cocos2d texture cache is entirely constructed in memory, during the execution of your app. It is a mechanism that 1) helps keep the memory footprint smaller, and 2) also boosts performance since a texture file is only loaded once if you dont clear the cache. Xcode on the other hand keeps copies of all your files in multiple places. By 'cleaning' a build, you ensure that previous versions of files are removed, and all the current resources (including textures) are placed in the appropriate places for the development environment to function properly.