Clip CCSprite/CCNode with another CCSprite/CCNode - Cocos2D - ios

I can clip using native coding within iOS however, as I wish to port across to Android using SpriteBuilder I want to clip 2 CCSprites using Cocos2D.
I am looking to do the following :
I have seen libraries which support only Cocos2D 2 however I am using the latest version and these no longer seem to work.
How would I achieve this affect?

For anyone looking for a similar fix the following is native to Cocos2D.
//Get Screen size
CGSize winSize = [[CCDirector sharedDirector] viewSize];
//Set Clipping Sprite
CCSprite *heroClip = [CCSprite spriteWithImageNamed:#"stamina/MenuHappinessWhite.png"];
heroClip.position = ccp(winSize.width/2, winSize.height/2); // Middle of screen
//Set Sprite below Clipping
CCSprite *heroUnder = [CCSprite spriteWithImageNamed:#"stamina/MenuLevel.png"];
heroUnder.position = ccp(winSize.width/2, winSize.height/2);
heroUnder.scaleY = 0.5f;
// Create Clipping Node
CCClippingNode *scissor = [CCClippingNode clippingNodeWithStencil:heroClip];
[scissor setContentSize:self.contentSize];
[scissor setPositionType:CCPositionTypeNormalized];
[scissor setAlphaThreshold:0.0];
//[scissor setInverted:YES];
[self addChild:scissor];
// Add nodes to Clipping Node
[scissor addChild:heroUnder];
and add this to app delegate
//Load Clipping Mask
[cocos2dSetup setObject:#GL_DEPTH24_STENCIL8_OES forKey:CCSetupDepthFormat];

Related

cocos2d v3: physicsBody of a CCSprite is positioned incorrectly

I'm very new to cocos2d development.
What I am trying to implement is some sprite nodes with physics bodies. As far as I understand, you're supposed to add them to the scene like this ("physics" here is the name of CCPhysicsNode declared earlier):
[physics addChild:node];
instead of
[self addChild:node];
The second one is pretty self-explanatory, I never had any trouble with it. But with the first the position of collision shapes does not match the position of the actual sprite (as seen in debug drawing, and by offset I mean greatly offset, like 2x the actual position). This is how I declare and add the node:
CCSprite *sprite = [CCSprite spriteWithImageNamed:#"sprite.png"];
sprite.position = position;
sprite.physicsBody = [CCPhysicsBody bodyWithRect:[sprite boundingBox] cornerRadius:0];
sprite.physicsBody.collisionType = #"SomeCollisionType";
sprite.name = #"Name";
[physics addChild:sprite];
What am I doing wrong? Please explain me how to make the positions match. TIA.

CCSprite not showing Background Image

I am facing an unknown error since from yesterday. I am creating CCSprites or CCMenuItemImage but it set black background instead of background image. Following is my code, I know its fine because I used it before many times.
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"challenge_screen.plist"];
CCSprite *bg = [CCSprite spriteWithFile:#"ads.png"];
[bg setPosition:background.position];
// [bg setContentSize:CGSizeMake(100, 100)];
[self addChild:bg z:1000];
//CGSize windowSize = [[CCDirector sharedDirector] winSize];
CCMenuItemImage *coinMenuItem = [[CCMenuItemImage alloc] initWithNormalSprite:[CCSprite spriteWithSpriteFrame:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:#"coin.png"]] selectedSprite:nil disabledSprite:nil block:^(id sender)
{
NSLog(#"I am Tapped");
}];
coinMenuItem.position = ccp(100, 100);
CCMenu *mainMenu = [CCMenu menuWithItems:coinMenuItem, nil];
mainMenu.position = CGPointZero;
[self addChild:mainMenu];
Attached is screenshot.
Thanks in advance.
I am guessing that you are loading this sprite sheet (challenge_screen.plist and the associated texture file, which frequently is challenge_screen.png or challenge_screen.pvr.*) in a color mode that doesn't have transparency.
First, make sure that the associated texture file shows transparency itself. Maybe something messed with this particular texture.
Once you checked that, if the associated texture is .PNG. then you have to set the texture loading format in code like this. You have to set the texture format before loading the texture itself (the texture loads as a side effect of adding the SpriteFrames to the cache).
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444];
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"challenge_screen.plist"];`
...
You can also try the kCCTexture2DPixelFormat_RGBA8888 mode if RGBA444 produces banding with your graphics and if you are good regarding free memory.
On the other hand, if the texture is a PVR.*, then the format in which the texture loads is embedded in the file, and setting the texture format in code doesn't make a difference. You will then need to regenerate your sprite sheet using the appropriate format (through TexturePacker or similar).
Is your background in the sprite sheet? If so try:
CCSprite *bg = [CCSprite spriteWithSpriteFrameName:#"ads.png"];
If it is the menu item and you know the code works, it must be an asset issue.

""CCSprite is not using the same texture id"" workaround?

I am animating a whole body through SpriteSheets with CCSpriteBatchNode and CCSpriteFrameCache. Now user can add his own pic to that body which when i try to addChild to Spritesheet crashes with error "CCSprite is not using the same texture id"
Now i know the face CCSprite was not in that cache/texture(it was created through texturepacker) and the crash was normal but i wanted to know if there was a workaround to this as i have to add a face to that body through user interaction and animate that body. And by far using spritesheets is the best option for animation. anyone??
In this case what you can do is You take picture of user , then you make texture from user's image .
Then Add that texture to the CCTextureCache . Now you have texture of user image. Now you can use that texture in animation.
Make Texture from Sprite(You can make sprite from user image)
CCSprite *spr = nil;//your sprite
CCRenderTexture* renderTexture = [CCRenderTexture renderTextureWithWidth:spr.contentSize.width height:spr.contentSize.height];
spr.anchorPoint = ccp(0, 0);
spr.position = ccp(0, 0);
[renderTexture addChild:spr];
[renderTexture begin];
[spr draw]; // or [spr visit];
[renderTexture end];
CCTexture2D *result = renderTexture.sprite.texture;
Add that Texture in to Texture Cache.
[[CCTextureCache sharedTextureCache] addTexture]
When you create a CCSpriteBatchNode it is linked to a single texture. This is the point of a CCSpriteBatchNode: to draw different sprites that use the same texture to reduce OpenGL draw calls and increase efficiency.
The easiest workaround (if you have not reached a performance-critical point) would be to use a regular CCLayer instead of a CCSpriteBatchNode.
If you still want to add different CCSprites (say, the body, the limbs and the head of your character) to the same CCSpriteBatchNode, the you need to build a single sprite sheet (or texture pack) which contains all the body parts that you need to add to the CCSpriteBatchNode. This single sprite sheet will be the only one that the CCSpriteBatchNode will use. You won't be able to add CCSprites that are not using this sprite sheet.
You can not Manually add CCSprite to SpriteSheets. Because When you create animated Sprite using texturepacker then i hope that you know it also created with .plist file and it loas image from it with its size.
When you add manually CCSprite then it is nor found from SpriteFramesWithFile. may be you got error.
another way for add animated CCSprite without use of texturepacker
CCSprite *dog = [CCSprite spriteWithFile:#"dog1.gif"];
dog.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:dog z:2];
NSMutableArray *animFrames = [NSMutableArray array];
for( int i=1;i<=5;i++)
{
NSString* file = [NSString stringWithFormat:#"dog%d.gif", i];
CCTexture2D* texture = [[CCTextureCache sharedTextureCache] addImage:file];
CGSize texSize = texture.contentSize;
CGRect texRect = CGRectMake(0, 0, texSize.width, texSize.height);
CCSpriteFrame* frame = [CCSpriteFrame frameWithTexture:texture rect:texRect];
[animFrames addObject:frame];
}
CCAnimation * animation = [CCAnimation animationWithSpriteFrames:animFrames];
animation.delayPerUnit = 0.07f;
animation.restoreOriginalFrame = YES;
CCAnimate *animAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:animation]];
[dog runAction:animAction];
Above code is just describe that how can you add animated CCSprite without use of texturepacker
Here you can also change array of Images so you may be add manually image also.

CCRenderTexture and CCDirector render differently?

i wanted to use CCRenderTexture in my project because i have a lot of CCLabelBMFont that are mostly static. Adding them all to my Scene caused some performance issues (Yes you can use BatchNotes etc. but it didnt really help). So I rendered them into a single Texture which increased the performance significantly! But the problem is that the rendered texture and the directly rendered node look different. I have no idea why!
I created a cocos2d-sample project and and created this:
CCSprite* testImage = [CCSprite spriteWithFile:#"N.png"];
testImage.position = ccp(100,100);
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:786 height:1024];
[rt beginWithClear:0 g:0 b:0 a:0];
[testImage visit];
[rt end];
CCSprite* renderedSprite = [CCSprite spriteWithTexture:rt.sprite.texture];
renderedSprite.position = ccp(386,512);
// Flip because CCRenderTexture is flipped
renderedSprite.flipY = YES;
// Add normal node an the rendered sprite
testImage.position = ccp(130,100);
[self addChild:testImage];
[self addChild:renderedSprite];
The results look like this:
How can this be? How can i make them look the same?
The N on the right is the sprite added the "normal" way and it is displayed correctly. The N on the left is the texture.
Edit:
i found this tutorial which hints that the blend functions are different. so can i am looking for the correct function to make them look the same.
I found the solution!
I used this example to create the sprite but when i looked into the cocos2d-manual again i saw, that you can add the CCRenderTexture directly to your scene. Thats what i did and it solved the problem!
So the correct code should be:
CCSprite* testImage = [CCSprite spriteWithFile:#"N.png"];
testImage.position = ccp(100,100);
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:786 height:1024];
[rt begin];
[testImage visit];
[rt end];
rt.position = ccp(386,512);
// Add normal node an the rendered sprite
testImage.position = ccp(130,100);
[self addChild:testImage];
[self addChild:rt];

Cocos2d: creating an instance of CCRenderTexture crashes my App but can't figure out how to debug this

EDIT (shorter version after additional testing):
I only added:
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:winSize.width height:winSize.height];
to my BulletCache in my game project (that has a GameScene where an instance of BulletCache is added) and now the app does crash whilst trying to load the gamescene instance (before this I had no problems with this crash).
NOTE: I added a breakpoint in the init method of CCRenderTexture and it does seem to run through smoothly, it must be something after the init.
Conversely I tried the same in the init method of the GameScene and it does not crash the App. Likewise if I add it to an empty cocos2d-ios helloworld template project.
Hence in the cocos2d-ios helloworld template I did an additional testing thinking to see if there was a conflict in having a batchnode and a CCRenderTexture instance and added the following at the end of the helloworldlayer.m init method:
CCSpriteFrameCache* frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[frameCache addSpriteFramesWithFile:#"art1-hd.plist"];
CCSpriteBatchNode* spriteBatch = [CCSpriteBatchNode batchNodeWithFile:#"art1-hd.png"];
[self addChild:spriteBatch];
CGSize winSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture *rt = [CCRenderTexture renderTextureWithWidth:winSize.width height:winSize.height];
[self addChild:rt];
There was no crash.
I am left with not many glues on how to solve this.
EDIT: Removed original question where I mentioned a pixelperfect collision project where I had found CCRenderTexture
Maybe the problem is simply that the original code assumes each sprite to use their own textures. Now if you have a texture atlas, each sprite renders only from a smaller area (rect) of that texture. You'll have to initialize the collision test accordingly with the sprite frame's part of the texture.
All in all, it's possible to do pixel perfect collision detection with sprite frames and texture atlas, but more complicated depending on the actual implementation of the collision test.

Resources