检测CCSprite上的触摸

时间:2011-10-25 01:11:14

标签: ios xcode cocos2d-iphone touch ccsprite

我是cocos2d的新手,请原谅我的无知,但我想知道如何检测精灵何时被触摸并在触摸时调用方法。

我已经定义并添加了我的精灵:

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

我已经遵循了各种资源,但它们一直很模糊,其中大部分精灵都是在自己的类中设置的。

提前致谢。

4 个答案:

答案 0 :(得分: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 ...
    }
} 

通过Cocos2D的方法证明Kobold2D简化了多少:

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

答案 1 :(得分: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...
}

答案 2 :(得分:0)

解决方案取决于您的代码架构。对于菜单项,请使用 xuanweng 变体。或者,您可以在父图层的ccTouchBegan方法中检查触点与精灵边界的交点。您需要将触摸点转换为图层空间(通常情况下,此转换是标识)并检查CGRectContainsPoint ([sprite boundingBox], touchPos)

答案 3 :(得分:0)

我不久前制作了这个自定义事件监听器

这是CCNode + events.h文件(头文件)

//
//  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 + events.h文件。
  2. 创建一个您想要添加eventlistener的CCNode / CCSprite(yourNode)。
  3. 然后您通过编码

    来创建活动

    [yourNode addEventWithEvent:@“touchBegan”callback:^(CCNode * node){

    NSLog(@“Touch on node”);

    } useDispatcher:YES];

  4. addEventWithEvent参数有三种类型

    • touchBegan =当您的手指触摸节点时触发
    • touchEnded =手指释放节点时触发
    • touchDrag ==在节点上移动手指时触发

    回调采用将在上述事件中触发的回调块。

    useDispatcher采用BOOL值(YES或NO)。 如果将其设置为YES,则会在CCNode上触发事件。 如果将其设置为NO,则会在屏幕上触发事件

相关问题