cocos2d中对CCMenu 实现扩展使触摸正常图片的透明区域不触发事件

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。
http://blog.csdn.net/azhou_hui/article/details/8185830
 
下面的代码是一位朋友提供的,扩展了CCMenu
(1)MenuExtras.h
//
//  MenuExtras.h
//  CCSpriteTouchedNonAlpha
//
//

#import <Foundation/Foundation.h>
#import "cocos2d.h"

/**
 * 对 CCMenu 实现扩展使触摸正常图片的透明区域不触发事件
 *
 */
@interface MenuExtras : CCMenu {
    CGImageRef inImage_;
}

- (CGContextRef)createARGBBitmapContextFromImage:(CGImageRef)inImage;

- (int)getPixelColorAtLocation:(CGPoint)point imageRef:(CGImageRef)inImage;

@end

(2)MenuExtras.m
//
//  MenuExtras.m
//  CCSpriteTouchedNonAlpha
//


#import "MenuExtras.h"
#import "UIImage-ToSprite.h"


@implementation MenuExtras

/**
 * 触摸元素的图片是否在图片的非透明范围内
 *
 */
-(BOOL)containsNonAlpha:(UITouch *)touch item:(CCMenuItem *) item{
    CCMenuItemSprite *spriteItem = (CCMenuItemSprite *)item;
    UIImage *image = [UIImage convertSpriteToUIImage:(CCSprite *)spriteItem.normalImage];
    inImage_ = CGImageRetain(image.CGImage);
    
    //得到图片触摸的位置
    CGPoint pos = [spriteItem.normalImage convertTouchToNodeSpace:touch];
    
    //得到像素值
    int pixel = [self getPixelColorAtLocation:pos imageRef:inImage_];
    CGImageRelease(inImage_);
    return pixel == 0 ? false : true;
}

/**
 * copy CCmenu
 */
-(CCMenuItem *) itemForTouch: (UITouch *) touch{
	CGPoint touchLocation = [touch locationInView: [touch view]];
	touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
	
	CCMenuItem* item;
	CCARRAY_FOREACH(children_, item){
		// ignore invisible and disabled items: issue #779, #866
		if ( [item visible] && [item isEnabled] ) {
			
			CGPoint local = [item convertToNodeSpace:touchLocation];
			CGRect r = [item rect];
			r.origin = CGPointZero;
			if( CGRectContainsPoint( r, local ) && [self containsNonAlpha:touch item:item]){
				return item;
            }
		}
	}
	return nil;
}

-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
    if( state_ != kCCMenuStateWaiting || !visible_ )
		return NO;
	
	selectedItem_ = [self itemForTouch:touch];
    
    if(selectedItem_ != nil ){
        [selectedItem_ selected];
        state_ = kCCMenuStateTrackingTouch;
        return YES;
    }
	
	return NO;
}

/**
 * 传入图片上的一个点,返回图片上点的像素值,(如果返回值为0则表示是透明区域).
 *
 * @param point    图片上的点
 * @param inImage  一个图片的CGImageRef实例
 */
- (int)getPixelColorAtLocation:(CGPoint)point imageRef:(CGImageRef)inImage {
    
    CGContextRef cgctx = [self createARGBBitmapContextFromImage:inImage];
    if (cgctx == NULL) { 
        return -1; /* error */ 
    }
    
    size_t w = CGImageGetWidth(inImage);
    size_t h = CGImageGetHeight(inImage);
    CGRect rect = {{0,0},{w,h}};
    
    //不知道哪里把图片旋转180度???这里必须要旋转180度才能对称过来.旋转之后模拟器可以通过,真机不能通过???解决不了。。
    //    CGContextRotateCTM(cgctx, 180);
    CGContextDrawImage(cgctx, rect, inImage);
    CGContextSaveGState(cgctx);
    
    unsigned char* data = CGBitmapContextGetData (cgctx);
    
    int alpha;
    if (data != NULL) {
        @try {
            int offset = 4 * ((w * round(h - point.y)) + round(point.x));
            
            alpha =  data[offset];
        } @catch (NSException * e) {
            
        } @finally {
            
        }
    }
    CGContextRelease(cgctx);
    
    if (data) { free(data); }
    
    return alpha;
}

/**
 * 得到图片的上下文
 *
 * @param inImage  一个图片的CGImageRef实例
 */
- (CGContextRef)createARGBBitmapContextFromImage:(CGImageRef)inImage{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;
    
    size_t pixelsWide = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);
    
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);
    
    colorSpace = CGColorSpaceCreateDeviceRGB();
    if (colorSpace == NULL)
        return nil;
    
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL){
        CGColorSpaceRelease( colorSpace );
        return nil;
    }
    
    context = CGBitmapContextCreate (bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst|kCGBitmapByteOrder32Big);
    
    if (context == NULL) {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }
    
    CGColorSpaceRelease( colorSpace );
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    
    return context;
}

@end

这里提供的是扩展的MenuExtras,使用的时候就是 _menu = [MenuExtras menuWithItems:nil];
这是OC的

你可能感兴趣的:(cocos2d中对CCMenu 实现扩展使触摸正常图片的透明区域不触发事件)