16

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...

enter image description here

How do I do that? thanks.

Duck
  • 34,902
  • 47
  • 248
  • 470
  • Is the transparent layer clear or is it the pattern as you show above? Also do you know already how to detect touches on ANY area? – SimplyKiwi Jun 05 '12 at 00:35
  • the pattern is representing the transparency. Yes, I know how to detect touches, I just check if the touch is inside the sprite.boundingBox... what I need is to know if it is inside the boundingBox and is a non-transparent pixel. – Duck Jun 05 '12 at 02:50
  • Hmm, ok so what I recommend is just put a blank CCMenuItemImage on the non-transparent parent and do it that way. Otherwise you'll be dealing with a LOT of pixel code which you do not want. – SimplyKiwi Jun 05 '12 at 03:03
  • Do you want the touch to pass through transparent areas ? (i.e. the top most layer is transparent but you touch it in a position where in the layer below there is a non-transparent pixel at the same location) – giorashc Jun 05 '12 at 10:29
  • yes, I want it to ignore any touch given on a transparent area of a layer but if there is a layer below and this touched point corresponds to a non-transparent point on that layer, I want this layer below be triggered. – Duck Jun 05 '12 at 18:43

4 Answers4

6

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);
}
Lio
  • 4,225
  • 4
  • 33
  • 40
  • Can you expand on the answer. I tried making "an extension", but should it actually be a category? Also kHITTEST_WIDTH and kHITTEST_HEIGHT are undefined. Should them be 1x1 or 40x40? Can someone post the whole solution? – mevdev Aug 16 '12 at 22:32
  • Hello, an extension is indeed a category on that class. You can create it and add this method right away as part of it. As for the undefined constants, you can replace them by 1 ones. – Lio Aug 17 '12 at 12:13
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.

SentineL
  • 4,682
  • 5
  • 19
  • 38
0

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

Paresh Rathod
  • 737
  • 7
  • 8
-1

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.

amyn
  • 922
  • 11
  • 24