還要能判斷是不是點到圖的透明部份..
首先是 CCSprite的 touch event 部份
自訂一個MySprite的類別.
MySprite.h
@interface MySprite : CCSprite < CCTargetedTouchDelegate > {
}
@end
加上 < CCTargetedTouchDelegate > 就好..
然後
MySprite.h
@implementation MySprite
- (void)onEnter{
[[[CCDirector sharedDirector] touchDispatcher] addTargetedDelegate:self priority:1 swallowsTouches:NO];
[super onEnter];
}
- (void)onExit{
[[[CCDirector sharedDirector] touchDispatcher] removeDelegate:self];
[super onExit];
}
- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{
CCLog(@"touch ");
return YES;
}
@end
加上onEnter跟 onExit中的設定, 就可以取得touch event.
之後就可以在對應的函式中接收到點擊事件 做想做的事.
OnEnter中的設定 . :
priority 設定這個物件的優先度 .
swallowsTouches 設定是否要吃掉touch events 不往下傳.
(這跟- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event 的回傳值也有關)
---------
再來就是檢查是不是在sprite範圍內,並檢查點擊位置的alpha值.
//判段是否在sprite範圍, 並檢查alpha值,是否透明.
- (BOOL)containsTouchLocation:(UITouch *)touch
{
CGPoint touchLocation = [touch locationInView: [touch view]];
touchLocation = [[CCDirector sharedDirector] convertToGL: touchLocation];
CGPoint local = [self convertToNodeSpace:touchLocation];
CGRect r = [self rect];
r.origin = CGPointZero;
BOOL isTouched = CGRectContainsPoint( r, local );
if (isTouched) {
//在sprite上的座標 , 由GL系統轉成UI系統.
CGPoint uilocal = CGPointMake(local.x, self.boundingBox.size.height-local.y);
int alpha = [self getPixelColorAtLocation:uilocal];
if (alpha < 85) { //小於85 表示透明,不攔截事件.
return NO;
}
return isTouched;
}
return isTouched;
}
-(CGRect) rect
{
return CGRectMake( position_.x - contentSize_.width*anchorPoint_.x,
position_.y - contentSize_.height*anchorPoint_.y,
contentSize_.width, contentSize_.height);
}
以上是判斷是否在sprite範圍內 的code.
接下來用getPixelColorAtLocation: 取得sprite上的某點的color中的alpha
//取得某pixel的color 的alpha值.
- (int)getPixelColorAtLocation:(CGPoint)point
{
CGContextRef cgctx = [self createARGBBitmapContextFromImage];
if (cgctx == NULL) { return -1; /* error */ }
size_t w = [self boundingBox].size.width;
size_t h = [self boundingBox].size.height;
CGRect rect = {{0,0},{w,h}};
//取得的offset不是原始texture上對應的資料,所以自己算.
int oriOffsetX = self.offsetPosition.x - (w-self.textureRect.size.width )/2 ;
int oriOffsetY = self.offsetPosition.y - (h-self.textureRect.size.height)/2 ;
if (self.flipX) {
oriOffsetX *= -1;
}
if (self.flipY) {
oriOffsetY *= -1;
}
CGPoint oriOffset = CGPointMake(oriOffsetX , oriOffsetY);
//使用CCSpriteFrame 從目前的CCSprite中建立新的CCSprite .
//解決CCSprite從spritesheet產生會造成texture是整張大圖的問題.
CCSpriteFrame *sprFrame = [CCSpriteFrame frameWithTexture:[self texture] rectInPixels:self.textureRect rotated:self.textureRectRotated offset:self.offsetPosition originalSize:CGSizeMake(w, h)];
CCSprite *spr = [CCSprite spriteWithSpriteFrame:sprFrame];
//做跟目前圖形對應的翻轉,這樣取值才正確.
[spr setFlipX:self.flipX];
[spr setFlipY:self.flipY];
unsigned char* data = CGBitmapContextGetData (cgctx);
int alpha;
if (data != NULL) {
@try {
int offset = 4*((w*round(point.y))+round(point.x));
alpha = data[offset];
}
@catch (NSException * e) {
}
@finally {
}
}
CGContextRelease(cgctx);
if (data) { free(data); }
return alpha;
}
- (CGContextRef)createARGBBitmapContextFromImage
{
CGContextRef context = NULL;
CGColorSpaceRef colorSpace;
void * bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
size_t pixelsWide = [self boundingBox].size.width;
size_t pixelsHigh = [self boundingBox].size.height;
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);
if (context == NULL)
{
free (bitmapData);
fprintf (stderr, "Context not created!");
}
CGColorSpaceRelease( colorSpace );
CGContextSetBlendMode(context, kCGBlendModeCopy);
return context;
}
其中會用到
+(UIImage *) convertSpriteToImage:(CCSprite *)sprite
{
CGPoint p = sprite.anchorPoint;
[sprite setAnchorPoint:ccp(0,0)];
CCRenderTexture *renderer = [CCRenderTexture renderTextureWithWidth:sprite.contentSize.width height:sprite.contentSize.height];
[renderer begin];
[sprite visit];
[renderer end];
[sprite setAnchorPoint:p];
return [renderer getUIImage];
}
這個 convertSpriteToImage 去將sprite轉成UIImage, 然後再從UIImage 取CGImage 再去處理.
取得對應某一個點的ARGB 的 color[4] , 將alpha 值回傳就是判斷透明度會需要的.
加上offset計算 跟flip 處理.
回覆刪除offset的部份是因為做spritesheet時 如果開 Trim , 那在讀texture時的 offset 跟從ccsprite物件中再去取得的offsetpostion不一樣.
所以自己算一個原本的正確讀texture用的offset來取圖.
flip則是如果ccsprite有翻轉的話, 那產出檢查用的圖也要翻轉, 這樣取得的點才正確.