cocos2d v3:如何基于CCScene的触摸以及UILongPressGestureRecognizer

时间:2014-08-25 00:50:13

标签: objective-c cocos2d-iphone

在整个网站上使用各种关于如何做目标c的例子,我想创建一个需要识别长按和单击的应用程序。我的应用程序的代码具有以下功能(为简洁起见省略了部分,实际代码编译正常,下面的代码是手动输入的,所以请不要指出语法错误):

从CCScene派生的基类(让我们称之为LongPressHandlingScene)    一个。此类在“init”期间设置UILongPressGestureRecognizer并将其“onExit”删除    湾这个类有一个方法,作为“长按”手势的事件处理程序(它自己使用时工作正常)    湾该类的其余部分与任何其他CCScene类相同。

//LongPressHandlingScene.h
@interface LongPressHandlingScene : CCScene {  
......  
}  
..........  
@end  

//LongPressHandlingScene.m  
@implementation LongPressHandlingScene{  
.............  
}  

-(id)init{  
{  
   if(!(self = [super init]))  
      return nil;  
.........  
   UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTouchAction:)];  

   return self;  
}  
..............  
-(void)longTouchAction:(UILongPressGestureRecognizer *)longTouch{  
..........  
}  

-(void)onExit{  
   NSArray *grs = [[[CCDirector sharedDirector] view] gestureRecognizers];  

   for(UIGestureRecognizers *gesture in grs){  
      if([gesture isKindOfClass:[UILongPressGestureRecognizer class]]){  
         [[[CCDirector sharedDirector] view] removeGestureRecognizer:gesture];  
}  
@end  

从CCSprite派生的基类(我们称之为DragHandlingSprite)    一个。这个类重写了touchBegan,touchMoved和touchEnded。 (在CCScene或CCScene派生类中单独使用时,一切正常)    C。该类的其余部分与任何其他CCSprite类相同。

//DragHandlingSprite.h  
@interface DragHandlingSprite : CCSprite {  
..........  
}  
@end  

//DragHandlingSprite.m  
@implementation DragHandlingSprite {  
..............  
}  

-(void)onEnter{  
   self.userInteractionEnabled = YES;  
..............  
}  

-(void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event{  
............  
}  

-(void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event{  
   CGPoint touchLocation = [touch locationInNode:self.parent];  
   self.position = touchLocation;  
}  

-(void)touchEnded:(UITouch *)touch withEvent:(UIEvent *)event {  
.............  
}  

// MainScene.h  
@interface MainScene : LongPressHandlingScene{  
.............  
}  

+(MainScene *)scene;  
@end  

// MainScene.m  
@implementation MainScene  

+(MainScene) scene {  
   MainScene *scene = [self node];  

   return scene;  
}  

-(id) init {  
   if(!(self = [super init]))  
      return nil;  

   self.userInteractionEnabled = YES;  
...............
   NSArray *itemsArray = ProperlyPopulatedArrayFromSomewhereElse;  
   for(id obj in itemsArray){  
      if([obj isKindOfClass:[NSDictionary class]]){  
         NSDictionary *vDict = (NSDictionary *)obj;  
         float posX = [[vDcit objectForKey:@"posXKey"] floatValue];  
         float poxY = [[vDict objectForKey:@"posYKey"] floatValue];  
         NSString *name = [vDict objectForKey:@"imageName"];  

         DragHandlingSprite *newImage = [DragHandlingSprite spriteWithImageNamed:name];  
         newImage.name = name;  
         newImage.position = CGPointMake(posX, posY);  

         [self addChild:newImage];  
    }  

@end  

我将一个或多个“DragHandingSprites”添加到“LongPressHandlingScene”后我遇到的问题如下:

点击任何“DragHandlingSprite”一次有效。在第一个之后单击相同或任何其他“DragHandlingSprite”会使应用程序崩溃,并显示错误“:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil key'

LongPressRecognition 100%的工作时间,但只要单击一次,就会发生与上述相同的异常。

有什么想法吗?

提前致谢。

1 个答案:

答案 0 :(得分:0)

对于那些可能偶然发现这个问题寻找答案的人来说,这就是我想出来的。

在正常情况下,UILongPressGestureRecognizer(可可)和onTouch事件(Cocos2d)可以共存而不会出现任何问题。一旦两者都在相同的“CCScene”中声明,所有它们各自的选择器/事件处理程序将在“触摸”生命周期中被调用。这通过允许运行所有基于触摸/手势的代码而导致我上面提到的错误。在我的例子中,一些事件处理程序正在删除UILongPRessGestureRecognizer操作选择器需要使用的信息,反之亦然,因此在某些时候尝试处理“nil”键并导致错误。

出于这个原因,我决定实现一个基于枚举的状态变量,该变量将跟踪应用当前所处的“触摸”状态,以防止代码执行不顺。

enum TouchStates {DRAG_BEGAN, DRAG_MOVED, DRAG_ENDED, LONG_TOUCH_BEGAN, LONG_TOUCH_ENDED, DEFAULT};  
enum TouchStates touchState;
........  

-(id)init{  
   ................  
   UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longTouchAction:)];  
   ............  
}

-(void)longTouchAction:(UILongPressGestureRecognizer *)longTouch{  
   if(/*[touchState is the correct one to do something here]*/){  
      if(longTouch.state == UIGestureRecognizerStateBegan){  
         touchState = LONG_TOUCH_BEGAN;
         .............
         //DO WHAT'S NECESSARY HERE
         .............  
   }
   // Do something similar for the "UIGestureRecongizerEnded" flag  
}

-(void)onTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event{  
   if(/*[touchState is the correct one to do something here]*/){  
      touchState = DRAG_BEGAN;
      ..............  
      //DO WHAT'S NECESSARY HERE  
      ...............
}  

// Do something similar for the onTouchMoved and onTouchEnded event handlers.