2011-10-25 56 views
2

我是新來的cocos2d,所以請原諒我的無知,但我想知道如何檢測何時觸摸了精靈並在觸摸時調用方法。在CCSprite上檢測觸摸

我已經定義並添加我的精靈這樣的:

CCSprite *infoButton = [CCSprite spriteWithFile: @"info.png"]; 
[infoButton setPosition:CGPointMake(450, 290)]; 
[menuBG addChild:infoButton]; 

我已經按照各方面的資源,但他們一直很模糊,其中大部分的精靈在自己的類設置。

在此先感謝。

回答

5

爲什麼不使用CCMenuItemImage?

CCMenuItemImage* info = [CCMenuItemImage itemFromNormalImage:@"info.png" selectedImage:@"info.png" target:self selector:@selector(pressed:)]; 
CCMenu* menu = [CCMenu menuWithItems:info, nil]; 
menu.position = ccp(450,290); 
[menuBG addChild:menu]; 

,每當用戶按下按鈕其他功能..

-(void)pressed:(id)sender 
{ 
// whatever you would like to do here... 
} 
0

的解決方案取決於你的代碼架構。對於菜單項使用xuanweng變種。或者,您可以在父層的方法ccTouchBegan中檢查觸摸點與精靈邊界的交集。你需要變換觸摸點到層空間(在通常情況下這種變換身份),並檢查CGRectContainsPoint ([sprite boundingBox], touchPos)

11

在常規的Cocos2D:

-(void) ccTouchesBegan:(NSSet*)touches withEvent:(id)event 
{ 
    CCDirector* director = [CCDirector sharedDirector]; 
    UITouch* touch = [touches anyObject]; 
    CGPoint touchLocation = [touch locationInView:director.openGLView]; 
    CGPoint locationGL = [director convertToGL:touchLocation]; 
    CGPoint locationInNodeSpace = [infoButton convertToNodeSpace:locationGL]; 

    CGRect bbox = CGRectMake(0, 0, 
          infoButton.contentSize.width, 
          infoButton.contentSize.height); 

    if (CGRectContainsPoint(bbox, locationInNodeSpace)) 
    { 
     // code for when user touched infoButton sprite goes here ... 
    } 
} 

爲了證明Kobold2D多少簡化了這種過度的Cocos2D的做法:

-(void) update:(ccTime)delta 
{ 
    KKInput* input = [KKInput sharedInput]; 
    if ([input isAnyTouchOnNode:infoButton touchPhase:KKTouchPhaseBegan]) 
    { 
     // code for when user touched infoButton sprite goes here ... 
    } 
} 
+0

我嘗試使用您的代碼進行一些小修改。現在它將檢查arrayOfCCSprite。但它沒有檢測到。 –

+0

說'openGLView'已被棄用。雖然仍然有效。替換爲'view'。 – Jonny

0

我做了這個自定義事件監聽器前一陣子

這是CCNode + events.h文件(的H EADER文件)

// 
// CCNode+events.h 
// Save the world´s 
// 
// Created by Sebastian Winbladh on 2013-10-14. 
// Copyright (c) 2013 Sebastian Winbladh. All rights reserved. 
// 

#import "cocos2d.h" 
#import <objc/runtime.h> 

//We are using CCLayer so we can capture events that occurs on top of it 

@interface EventLayer : CCLayer 

@property (nonatomic,assign) NSMutableArray *nodes; 
@property (nonatomic,assign) void (^callback)(NSArray*nodeArray,NSSet*touches,NSString *event); 
+(id)sharedEventLayer:(CCNode *)on callback:(void(^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode; 

@end 

@interface CCNode (props) 

@property (nonatimic,assign) id rotationCX; 
@property (nonatomic,assign) id rotationCY; 
@property (nonatomic,assign) id scaleCX; 
@property (nonatomic,assign) id scaleCY; 

@end 

//Sprite category 
//Used to capture sprite cords and eval events 
@interface CCNode (events) 

-(void)addEventWithEvent:(NSString *)event callback:(void(^)(CCNode*node))back useDispatcher:(BOOL)disp; 

@end 

這是CCNode + events.m文件(主文件)

// 
// Created by Sebastian Winbladh on 2013-10-14. 
// Copyright (c) 2013 Sebastian Winbladh. All rights reserved. 
// 

#import "CCNode+events.h" 

@implementation EventLayer 
@synthesize callback,nodes; 

//Shared instance 
+(id)sharedEventLayer:(CCNode *)on callback:(void (^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode{ 

    static dispatch_once_t onceToken; 
    static EventLayer *eventLayer; 
    dispatch_once(&onceToken, ^{ 

     eventLayer = [[[EventLayer alloc]init]autorelease]; 
     eventLayer.callback = block; 
     [[eventLayer getParent:on] addChild:eventLayer]; 

    }); 

    [eventLayer.nodes addObject:addNode]; 
    return eventLayer; 
} 

//Find top level parent child 
-(id)getParent:(CCNode*)on{ 
    id ret=on; 
    BOOL done=false; 

    while(done == false){ 
     ret = [ret parent]; 
     if(![[ret parent] children]){ 
      done = true; 
     } 
    }return ret; 
} 

-(void)callbackWithEvent:(NSString*)event nsSet:(NSSet *)set{ 
    for(NSArray *lNodeArray in nodes){ 
     self.callback(lNodeArray,set,event); 
    } 
} 

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
    [self callbackWithEvent:@"touchBegan" nsSet:touches]; 
} 

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{ 
    [self callbackWithEvent:@"touchEnded" nsSet:touches]; 
} 

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 
    [self callbackWithEvent:@"touchDrag" nsSet:touches]; 
} 

//Initilize 
-(id)init{ 
    if(self = [super init]){ 
     [self setTouchEnabled:YES]; 
     nodes = [[NSMutableArray alloc]init]; 
    } 
    return self; 
} 

-(void)dealloc{ 

    //Dealloc nodes 
    [nodes release]; 
    nodes = nil; 

    [super dealloc]; 

} 

@end 


@implementation CCNode (props) 

@dynamic rotationCX,rotationCY,scaleCX,scaleCY; 

-(void)setRotationCX:(id)rotationCX{ 
    objc_setAssociatedObject(self, @selector(rotationCX), rotationCX, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
-(id)rotationCX{return objc_getAssociatedObject(self, @selector(rotationCX));} 

-(void)setRotationCY:(id)rotationCY{ 
    objc_setAssociatedObject(self, @selector(rotationCY), rotationCY, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
-(id)rotationCY{return objc_getAssociatedObject(self, @selector(rotationCY));} 

//Scales 
-(void)setScaleCX:(id)scaleCX{ 
    objc_setAssociatedObject(self, @selector(scaleCX), scaleCX, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
-(id)scaleCX{return objc_getAssociatedObject(self, @selector(scaleCX));} 

-(void)setScaleCY:(id)scaleCY{ 
    objc_setAssociatedObject(self, @selector(scaleCY), scaleCY, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 
-(id)scaleCY{return objc_getAssociatedObject(self, @selector(scaleCY));} 

@end 

@implementation CCNode (events) 

-(void)createEventLayerWithEvent:(void(^)(NSArray*nodeArray,NSSet*touches,NSString *event))block node:(NSArray *)addNode{ 
    [EventLayer sharedEventLayer:self callback:block node:addNode]; 
} 

//Get top level child parent 
-(id)getParent:(CCNode*)on{ 
    id ret=on; 
    BOOL done=false; 

    while(done == false){ 
     ret = [ret parent]; 
     if(![[ret parent] children]){ 
      done = true; 
     } 
    }return ret; 
} 

//This function creates a custom bounding box. 
//It takes all childrens in the loop and calculate widths, hights, anchorPoints, positions, scales and rotations 
//to get the exact bounding box of the node. 
-(void)toggleRotationOnItems:(NSMutableArray *)items func:(NSString*)type{ 

    for(NSArray *item in items){ 

     CCNode *innerItems=[item objectAtIndex:0]; 

     if([type isEqualToString:@"zero"]){ 
      innerItems.rotationX=0; 
      innerItems.rotationY=0; 
     } 
     if([type isEqualToString:@"reset"]){ 
      innerItems.rotationX=((NSNumber*)innerItems.rotationCX).floatValue; 
      innerItems.rotationY=((NSNumber*)innerItems.rotationCY).floatValue; 
     } 
    } 

} 
-(CGPoint)getScalesOnChild:(CCNode *)item mother:(CCNode *)items{ 

    CCNode *i=item; 
    BOOL didFinish=false; 
    CGPoint scales; 

    scales.x = item.scaleX; 
    scales.y = item.scaleY; 

    while(didFinish == false){ 

     if([i isEqual:items])didFinish=true; 
     i = [i parent]; 

     scales.x *= i.scaleX; 
     scales.y *= i.scaleY; 
    } 

    return scales; 

} 
-(BOOL)isVisible:(CCNode*)node mother:(CCNode*)m{ 

    CCNode *i=node; 
    BOOL didFinish=false; 


    while(didFinish == false){ 

     if(i.visible == false){ 
      return false; 
      continue; 
     } 
     if([i isEqual:m])didFinish=true; 
     i = [i parent]; 

    } 

    return true; 


} 
-(NSMutableArray*)createBoundingBox:(CCNode *)node{ 

    node.rotationCX = [NSNumber numberWithFloat:node.rotationY ]; 
    node.rotationCY = [NSNumber numberWithFloat:node.rotationY ]; 
    node.scaleCX = [NSNumber numberWithFloat:node.scaleX ]; 
    node.scaleCY = [NSNumber numberWithFloat:node.scaleY]; 

    NSMutableArray *l=[[[NSMutableArray alloc]initWithObjects:node, nil]autorelease]; 
    int c=1; 

    NSMutableArray *ret=[[[NSMutableArray alloc]init]autorelease]; 
    if(node.visible == true)ret=[[[NSMutableArray alloc]initWithObject:[NSArray arrayWithObjects:node,nil]]autorelease]; 

    //This first loop will loop until the count var is stable// 
    for(int r=0;r<c;r++){ 
     //This loop will loop thru the child element list// 
     for(int z=0;z<[[l objectAtIndex:r] children].count;z++){ 
       //Push the element to the return array. 

       CCNode *nodeItem = ((CCNode*)[[[l objectAtIndex:r] children] objectAtIndex:z]); 
       nodeItem.rotationCX = [NSNumber numberWithFloat:nodeItem.rotationX ]; 
       nodeItem.rotationCY = [NSNumber numberWithFloat:nodeItem.rotationY ]; 
       nodeItem.scaleCX = [NSNumber numberWithFloat:nodeItem.scaleX ]; 
       nodeItem.scaleCY = [NSNumber numberWithFloat:nodeItem.scaleY]; 

       if([self isVisible:nodeItem mother:node])[ret addObject:[NSArray arrayWithObjects:nodeItem, nil]]; 

      if([[[[[l objectAtIndex:r] children] objectAtIndex:z] children] objectAtIndex:0]){ 
       [l addObject:[[[l objectAtIndex:r] children] objectAtIndex:z]]; 
       c++; 
      }//IF 
     }//FOR 
    }//FOR 

    NSMutableArray *statickPoints = [[[NSMutableArray alloc]init]autorelease]; 
    NSMutableArray *dynamicPoints = [[[NSMutableArray alloc]init]autorelease]; 

    //Set the rotation to 0 so we can calculate the values better 
    [self toggleRotationOnItems:ret func:@"zero"]; 


    for(NSArray *items in ret){ 

     //Create variables to hold the node point and the item it self 
     CGPoint nodePoint; 
     CCNode *innerItems=[items objectAtIndex:0]; 

     //Check wich node world we will use 
     nodePoint = [[innerItems parent] convertToWorldSpace:innerItems.position]; 

     CGPoint scales=[self getScalesOnChild:innerItems mother:node]; 

     float widthOffsetP1 = innerItems.contentSize.width*innerItems.anchorPoint.x*scales.x; 
     float heightOffsetP1 = innerItems.contentSize.height*innerItems.anchorPoint.y*scales.y; 

     float widthOffsetP1Flip = innerItems.contentSize.width*(1-innerItems.anchorPoint.x)*scales.x; 
     float heightOffsetP1Flip = innerItems.contentSize.height*(1-innerItems.anchorPoint.y)*scales.y; 

     //statick positions 
     CGPoint point1 = CGPointMake(nodePoint.x-widthOffsetP1,nodePoint.y+heightOffsetP1Flip); 
     CGPoint point2 = CGPointMake(nodePoint.x-widthOffsetP1+innerItems.contentSize.width*scales.x, 
            nodePoint.y-heightOffsetP1+innerItems.contentSize.height*scales.y); 
     CGPoint point3 = CGPointMake(nodePoint.x-widthOffsetP1+innerItems.contentSize.width*scales.x, 
            nodePoint.y-heightOffsetP1); 
     CGPoint point4 = CGPointMake(nodePoint.x-widthOffsetP1,nodePoint.y-heightOffsetP1); 

     //Append to array 
     [statickPoints addObject:[NSArray arrayWithObjects:innerItems, 
            [NSValue valueWithCGPoint:point1], 
            [NSValue valueWithCGPoint:point2], 
            [NSValue valueWithCGPoint:point3], 
            [NSValue valueWithCGPoint:point4],nil]]; 


    } 

    //Callculate mother and child rotations 
    for(NSArray *items in statickPoints){ 

     NSValue *point1 = [items objectAtIndex:1]; 
     NSValue *point2 = [items objectAtIndex:2]; 
     NSValue *point3 = [items objectAtIndex:3]; 
     NSValue *point4 = [items objectAtIndex:4]; 

     int matrix_length=3; 
     CGPoint points[matrix_length]; 
     points[0] = [point1 CGPointValue]; 
     points[1] = [point2 CGPointValue]; 
     points[2] = [point3 CGPointValue]; 
     points[3] = [point4 CGPointValue]; 

     // Seting the statick positions to the rotations 
     for(int i=0;i<=matrix_length;i++){ 

      CGPoint nodePoint; 
      CCNode *item = [items objectAtIndex:0]; 
      BOOL didFinish = false; 

      while(didFinish == false){ 

       nodePoint = [[item parent] convertToWorldSpace:item.position]; 

       float widthOffsetP1 = (points[i].x - (nodePoint.x)); 
       float heightOffsetP1 = (points[i].y - (nodePoint.y));    

       float radians1=sqrt(fabs(powf(widthOffsetP1, 2))+fabs(powf(heightOffsetP1,2))); 

       float newRotation1 =CC_RADIANS_TO_DEGREES(atan2(widthOffsetP1,heightOffsetP1)) + ((NSNumber*)item.rotationCX).floatValue ; 

       float p1RotApplyed=(radians1) * sinf(CC_DEGREES_TO_RADIANS(newRotation1)); 
       float p2RotApplyed=(radians1) * cosf(CC_DEGREES_TO_RADIANS(newRotation1)); 

       points[i].x-=-p1RotApplyed+(widthOffsetP1); 
       points[i].y-=-p2RotApplyed+(heightOffsetP1); 

       if([item isEqual:node]){ 
        didFinish=true; 
       } 
       item = [item parent]; 

      } 

     } 

     [dynamicPoints addObject:[NSArray arrayWithObjects:[NSValue valueWithCGPoint:points[0]], 
            [NSValue valueWithCGPoint:points[1]], 
            [NSValue valueWithCGPoint:points[2]], 
            [NSValue valueWithCGPoint:points[3]], 
            nil]]; 

     /* CCLabelTTF *la=[CCLabelTTF labelWithString:@"O" fontName:@"Arial" fontSize:6]; 
     la.anchorPoint=ccp(0.5,0.5); 
     la.position=points[3]; 
     [[self getParent:node ]addChild:la]; 

     CCLabelTTF *la1=[CCLabelTTF labelWithString:@"O" fontName:@"Arial" fontSize:6]; 
     la1.anchorPoint=ccp(0.5,0.5); 
     la1.position=points[2]; 
     [[self getParent:node ]addChild:la1]; 

     CCLabelTTF *la2=[CCLabelTTF labelWithString:@"O" fontName:@"Arial" fontSize:6]; 
     la2.anchorPoint=ccp(0.5,0.5); 
     la2.position=points[1]; 
     [[self getParent:node ]addChild:la2]; 

     CCLabelTTF *la3=[CCLabelTTF labelWithString:@"O" fontName:@"Arial" fontSize:6]; 
     la3.anchorPoint=ccp(0.5,0.5); 
     la3.position=points[0]; 
     [[self getParent:node ]addChild:la3];*/ 


    } 

    //Reset rotations 
    [self toggleRotationOnItems:ret func:@"reset"]; 

    return dynamicPoints; 

} 
-(BOOL)boxContainsPoint:(CGPoint)p box:(NSMutableArray*)a test:(CCNode*)t{ 

    BOOL returns=false; 
    NSMutableArray *ret=[[[NSMutableArray alloc]init]autorelease]; 

    for(NSArray *items in a){ 

     NSValue *point1 = [items objectAtIndex:0]; 
     NSValue *point2 = [items objectAtIndex:1]; 
     NSValue *point3 = [items objectAtIndex:2]; 
     NSValue *point4 = [items objectAtIndex:3]; 

     int matrix_length=4; 
     CGPoint points[matrix_length*2+1]; 
     points[8] = points[4] = points[0] = [point1 CGPointValue]; 
     points[5] = points[1] = [point2 CGPointValue]; 
     points[6] = points[2] = [point3 CGPointValue]; 
     points[7] = points[3] = [point4 CGPointValue]; 

     NSMutableArray *hits=[[[NSMutableArray alloc]init]autorelease]; 

     int p1=0; 
     float max=0; 
     for(int i=0;i<=matrix_length;i++){if(points[i].y>=max)p1=i;max=points[i].y;} 

     for(int i=0;i<matrix_length;i+=2){ 

      CGPoint graphOrigo = ccp(points[p1+i+1].x,points[p1+i].y); 

      double x = (graphOrigo.x-p.x); 
      double k = (graphOrigo.y-points[p1+i+1].y)/(graphOrigo.x-points[p1+i].x); 
      double m = (graphOrigo.y-points[p1+i+1].y); 
      double y = (-k*x+m); 

      if((graphOrigo.y-p.y)>(y) && i <=1){ 
       [hits addObject:[NSNumber numberWithBool:YES]]; 
      }else if((graphOrigo.y-p.y)<(y) && i >=1){ 
       [hits addObject:[NSNumber numberWithBool:YES]]; 
      }else{ 
       [hits addObject:[NSNumber numberWithBool:NO]]; 
      } 

      graphOrigo = ccp(points[p1+i+1].x,points[p1+i+2].y); 

      y = (graphOrigo.y-p.y); 
      k = (graphOrigo.x-points[p1+i+2].x)/(graphOrigo.y-points[p1+i+1].y); 
      m = (graphOrigo.x-points[p1+i+2].x); 
      x = (-k*y+m); 

      if((graphOrigo.x-p.x)>(x) && i <=1){ 
       [hits addObject:[NSNumber numberWithBool:YES]]; 
      }else if((graphOrigo.x-p.x)<(x) && i >=1){ 
       [hits addObject:[NSNumber numberWithBool:YES]]; 
      }else{ 
       [hits addObject:[NSNumber numberWithBool:NO]]; 
      } 

     } 
     BOOL hit=YES; 
     for(NSNumber *bools in hits){ 
      if(bools.boolValue == NO){ 
       hit=NO; 
      } 
     } 
     [ret addObject:[NSNumber numberWithBool:hit]]; 
    } 
    for(NSNumber *b in ret){ 
     if(b.boolValue == YES){ 
      returns=true; 
     } 
    } 
    return returns; 
} 
-(BOOL)validateToush:(NSSet *)touches nodePoint:(CCNode *)node{ 

    UITouch *touch = [touches anyObject]; 
    id parent = [self getParent:self]; 

    //Touch to global node space 
    CGPoint touchPoint = [parent convertTouchToNodeSpace:touch]; 
    NSMutableArray *nodeBox = [self createBoundingBox:(CCNode *)node]; 
    //Validating of hit point 

    if([self boxContainsPoint:touchPoint box:nodeBox test:node])return true; 
    return false; 

} 
-(void)addEventWithEvent:(NSString *)event callback:(void (^)(CCNode*node))back useDispatcher:(BOOL)disp{ 

    //Add a cc layer so we can capture toushes 
    [self createEventLayerWithEvent:^(NSArray*nodeArray,NSSet*touches,NSString *event) { 

     //Calback block 
     NSArray *lNodeArray=nodeArray; 
     CCNode *lNode = [lNodeArray objectAtIndex:0]; 
     void(^nodeBack)(CCNode*node) =[nodeArray objectAtIndex:2]; 

     BOOL disp =((NSNumber *)[nodeArray objectAtIndex:3]).boolValue; 

     if([[lNodeArray objectAtIndex:1] isEqualToString:@"touchBegan"]){ 

      //Return to callback block 
      if([event isEqualToString:@"touchBegan"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:@"touchBegan"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]); 

     }else if([[lNodeArray objectAtIndex:1] isEqualToString:@"touchEnded"]){ 

      //Return to callback block 
      if([event isEqualToString:@"touchEnded"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:@"touchEnded"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]); 

     }else if([[lNodeArray objectAtIndex:1]isEqualToString:@"touchDrag"]){ 

      //Return to callback block 
      if([event isEqualToString:@"touchDrag"] && [lNode validateToush:touches nodePoint:lNode] || disp==NO && [event isEqualToString:@"touchDrag"])nodeBack((CCNode*)[nodeArray objectAtIndex:0]); 

     } 

    } node:[NSArray arrayWithObjects:self,event,Block_copy(back),[NSNumber numberWithBool:disp], nil]]; 


} 

@end 

要使用此事件偵聽器是非常簡單的

  1. 包含的CCSprite +事件。 h文件在您的項目中。
  2. 創建一個您想添加一個eventlistener的CCNode/CCSprite(yourNode)。@ 「touchBegan」 回調:
  3. 然後你通過編寫此

    [yourNode addEventWithEvent創建事件^(CCNode *節點){

    的NSLog(@ 「觸摸開始節點」);

    } useDispatcher:YES];

的addEventWithEvent參數採用三種

  • touchBegan =發射時你的手指觸摸節點
  • touchEnded =發射時手指釋放節點移動你的時候
  • touchDrag ==解僱手指在節點上

該回調需要一個回調塊,該回調塊將被激發關於上述事件。

useDispatcher採用BOOL值(YES或NO)。 如果它被設置爲YES,則事件將在CCNode上觸發。 如果它被設置爲NO,則該事件將在屏幕上觸發