Cocos2d animation with mask - cocos2d-iphone

I've got an animation of a man walking. The background image contains some trees. I've a mask with those trees and I want to apply it over the man, so it'll look like that the man walks behind the trees.
This is my code:
CCRenderTexture * rt = [CCRenderTexture
renderTextureWithWidth:maskSprite.contentSizeInPixels.width
height:maskSprite.contentSizeInPixels.height];
rt.position = ccp(maskSprite.contentSize.width/2, maskSprite.contentSize.height/2);
[rt.sprite setBlendFunc: (ccBlendFunc) { GL_ONE_MINUS_SRC_ALPHA, GL_ZERO }];
[rt beginWithClear:0.0f g:0.0f b:0.0f a:1.0f];
[walkingManSprite visit];
[rt end];
[maskSprite setBlendFunc: (ccBlendFunc) { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }];
[rt beginWithClear:0.0f g:0.0f b:0.0f a:1.0f];
[maskSprite visit];
[rt end];
CCSprite *retval = [CCSprite spriteWithTexture:rt.sprite.texture];
retval.flipY = YES;
return retval;
The result is that the man walks behinds the trees, but my mask is being shown as a black shadow over the background. How can I not show the mask but apply it over the animation?

Related

How to detect/workaound a fully transparent screenshot on applicationDidEnterBackground?

I'm using this snippet of code to save a screenshot on applicationDidEnterBackground, which is presented later as the loading screen while the scene is loading in the background.
#implementation CCDirector(ScreenShot)
+(void)saveScreenshotWithFilename: (NSString*) filename {
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = CCDirector.sharedDirector.winSize;
CCRenderTexture * renderTexture = [CCRenderTexture renderTextureWithWidth:winSize.width
height:winSize.height
pixelFormat:kCCTexture2DPixelFormat_RGBA8888
depthStencilFormat:GL_DEPTH_COMPONENT16];
[renderTexture beginWithClear:0 g:0 b:0 a:0 depth:1.0f];
[CCDirector.sharedDirector.runningScene visit];
[renderTexture end];
UIImage *image = [renderTexture getUIImage];
NSString *filePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingFormat:#"/%#", filename];
[UIImagePNGRepresentation(image) writeToFile:filePath atomically:YES];
}
#end
It works ok, but in the case when the user taps the app icon to run the app, then pulses the home button, then taps the app icon again in a quick succession, the resulting screenshot is a transparent PNG file, with the right dimensions, but fully transparent.
How can I check for this special case to present some other image as the loading screen?
...or better yet, is there a workaround for the transparent screenshot?

Cocos2d Screen capture and get sprite from UIImage

I'm very headache about this problem, I'm using these code for capturing a part of the screen
-(UIImage *) glToUIImage {
userphotoCount++;
[CCDirector sharedDirector].nextDeltaTimeZero = YES;
CGSize winSize = [CCDirector sharedDirector].winSize;
CCLayerColor* whitePage = [CCLayerColor layerWithColor:ccc4(255, 255, 255, 0) width:winSize.width height:winSize.height];
whitePage.position = ccp(winSize.width/2, winSize.height/2);
CCRenderTexture* rtx = [CCRenderTexture renderTextureWithWidth:815 height:532];
[rtx begin];
[whitePage visit];
[[[CCDirector sharedDirector] runningScene] visit];
[rtx end];
return [rtx getUIImageFromBuffer];
}
I can get my UIImage by
image = [self glToUIImage];
Then I try to use this code to generate a sprite by the UIImage
-(void) ImageSprite{
image = [self glToUIImage];
userAns = [CCSprite spriteWithCGImage:image.CGImage key:[NSString stringWithFormat:#"photoCap%d.png", userphotoCount]];
userAns.position=ccp(780,410);
userAns.scale=0.6;
[self addChild:userAns z:20];
}
I can get image by these code at first time, but after I changed the screen's contents and use these code to generate new sprite(new UIImage) with the new contents, I'm failed.... the image doesn't change to new image...
How can I get the new image sprite when every time I run the "imageSprite" code?
You can get the new image sprite, but you must to change key
[CCSprite spriteWithCGImage:image.CGImage key:key];

Blur a CCLayerColor (for pause menu)

I'm curious if anyone knows of an already-implemented way to blur an entire CCLayer. I use a simple CCLayerColor set to black with a little opacity, but I would like to be able to blur the background enough to be indistinguishable blobs.
You can do this with CCLayerColor.
-(void)fadeBackground
{
ccColor4B color = {0,0,0,255};
CCLayerColor *fadeLayer = [CCLayerColor layerWithColor:color];
[self addChild:fadeLayer z:7];
fadeLayer.opacity = 0;
id fade = [CCFadeTo actionWithDuration:1.0f opacity:160];//200 for light blur
id calBlk = [CCCallBlock actionWithBlock:^{
//show pause screen buttons here
//[self showPauseMenu];
}];
id sequen = [CCSequence actions:fade, calBlk, nil];
[fadeLayer runAction:sequen];
}
Couldn't you just create a small tile that is translucent with some noise in it, and create a sprite that covers the screen where the texture parameters are set to repeat it?
CCSprite *blurSprite = [CCSprite spriteWithFile:#"blurtile.png" rect:CGRectMake(0, 0, 1024, 768)];
blurSprite.position = ccp(512,384);
ccTexParams params = {GL_LINEAR,GL_LINEAR,GL_REPEAT,GL_REPEAT};
[blurSprite .texture setTexParameters:&params];
[self addChild:blurSprite];
I might have those params slightly wrong, but it should give the general idea.

How to Convert a CCSprite image to UIImage?

As the title, I have mentioned the code below
CCSprite *sprite = (CCSprite *)node;
CCTexture2D *texture2d = [sprite texture];
How can I get a UIImage *p from sprite?
In your case just add next methood into your class:
- (UIImage *) imageFromSprite :(CCSprite *)sprite
{
int tx = sprite.contentSize.width;
int ty = sprite.contentSize.height;
CCRenderTexture *renderer = [CCRenderTexture renderTextureWithWidth:tx height:ty];
sprite.anchorPoint = CGPointZero;
[renderer begin];
[sprite visit];
[renderer end];
return [renderer getUIImage];
}
how to use:
CCSprite *sprite = (CCSprite *)node;
UIImage *p = [self imageFromSprite:sprite]
uhh...
I think this is a better to way. Add this as a category on CCNode.
-(UIImage*)image {
CCRenderTexture* renderer = [CCRenderTexture renderTextureWithWidth:self.contentSize.width height:self.contentSize.height];
const CGPoint ANCHORBEFORE = self.anchorPoint;
self.anchorPoint = CGPointZero;
[renderer begin];
[self visit];
[renderer end];
self.anchorPoint = ANCHORBEFORE;
return [renderer getUIImage];
}
If you are using cocos2d 2.x, render sprite into CCRenderTexture and call getUIImage method of that render texture.
By looking at the source code of both CCSprite and CCTexture2D you can see that the image is used only for creating the texture data and the image object is not kept but temporarily used.
CCTexture2D source :
http://code.google.com/p/cocos2d-iphone/source/browse/trunk/cocos2d/CCTexture2D.m?r=1882
CCSprite source :
http://code.google.com/p/cocos2d-iphone/source/browse/trunk/cocos2d/CCSprite.m?r=1747
Look in the init methods that use CGImageRef

Cocos2d 2.0 - Ignoring touches to transparent areas of layers/sprites

I have an app where I have several layers created from PNG images with transparency. These layers are all on the screen over each other. I need to be able to ignore touches given to transparent areas of layers and just be able to detect as touches, when the user taps on a non-transparent area of a layer... see pic...
How do I do that? thanks.
Here you have a possible solution.
Implement an extension on CCLayer and provide this method:
- (BOOL)isPixelTransparentAtLocation:(CGPoint)loc
{
//Convert the location to the node space
CGPoint location = [self convertToNodeSpace:loc];
//This is the pixel we will read and test
UInt8 pixel[4];
//Prepare a render texture to draw the receiver on, so you are able to read the required pixel and test it
CGSize screenSize = [[CCDirector sharedDirector] winSize];
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:screenSize.width
height:screenSize.height
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
//Draw the layer
[self draw];
//Read the pixel
glReadPixels((GLint)location.x,(GLint)location.y, kHITTEST_WIDTH, kHITTEST_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, pixel);
//Cleanup
[renderTexture end];
[renderTexture release];
//Test if the pixel's alpha byte is transparent
return (pixel[3] == 0);
}
if Lio's solution doesn't work, you may add add transparent sprite as a child you yours, place it just under your non-transparent area with size of this non-tranparent area and resive all touches by this new transparent sprite, but not by original sprite.
Here is my solution to your requirement, let me know if it works or not
Create a Category on CCMenu with Name Transparent
File CCMenu+Tranparent.h
#import "CCMenu.h"
#interface CCMenu (Transparent)
#end
File CCMenu+Tranparent.m
#import "CCMenu+Transparent.h"
#import "cocos2d.h"
#implementation CCMenu (Transparent)
-(CCMenuItem *) itemForTouch: (UITouch *) touch{
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
CCMenuItem* item;
CCARRAY_FOREACH(children_, item){
UInt8 data[4];
// ignore invisible and disabled items: issue #779, #866
if ( [item visible] && [item isEnabled] ) {
CGPoint local = [item convertToNodeSpace:touchLocation];
/*
TRANSPARENCY LOGIC
*/
//PIXEL READING 1 PIXEL AT LOCATION
CGRect r = [item rect];
r.origin = CGPointZero;
if( CGRectContainsPoint( r, local ) ){
if([NSStringFromClass(item.class) isEqualToString:NSStringFromClass([CCMenuItemImage class])]){
CCRenderTexture* renderTexture = [[CCRenderTexture alloc] initWithWidth:item.boundingBox.size.width * CC_CONTENT_SCALE_FACTOR()
height:item.boundingBox.size.height * CC_CONTENT_SCALE_FACTOR()
pixelFormat:kCCTexture2DPixelFormat_RGBA8888];
[renderTexture begin];
[[(CCMenuItemImage *)item normalImage] draw];
data[3] = 1;
glReadPixels((GLint)local.x,(GLint)local.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
[renderTexture end];
[renderTexture release];
if(data[3] == 0){
continue;
}
}
free(data);
return item;
}
}
}
return nil;
}
#end
This will check for pixel for returning the CCMenuItem.
Its working fine here.. let me know if you face any issues
-Paresh Rathod
Cocos2d Lover
The solution that worked great for me was using Sprite sheets. I use TexturePacker to create sprite sheets. Steps to create sprite sheet using TexturePacker:
1. Load all the image (.png) files into TexturePacker.
2. Chose data format as coco2d and choose PVR as the texture format.
3. Load the sprite sheet into your code and extract images from your sprite sheet.
Detailed description can be found here.