在ccTouchMoved上吞下ccTouch

时间:2013-08-31 19:40:16

标签: iphone cocos2d-iphone

我试图让玩家将游戏中的物体从屏幕的一部分拖到另一部分。问题是,要拖动的对象下面还有需要接收触摸的图层。通常我只是吞下触摸,但据我所知,这只能在ccTouchBegan期间完成。我无法判断用户是否试图拖动对象直到调用ccTouchMoved之后,所以我需要一种方法来明确吞下(或以其他方式防止下层)在我确定它之后接收触摸是我感兴趣的(ccTouchMoved内)。

1 个答案:

答案 0 :(得分:1)

我遇到了几乎相同的问题,但我不知道我的解决方案是否适合这里。主要思想是应该拖动的对象是同一CCNode层次结构中具有项目下方的子项。解决方案包括父母禁用儿童的触摸事件,然后拦截这些事件。在某些对象被拖动的情况下,父项将所有事件发送给它,在另一种情况下,父项处理事件本身。

让我试着表明我的意思。为可以吞下触摸的项目创建协议ccTouchMoved:

@protocol SwallowingOnTouchMovedNode
{
    -(BOOL) ccTouchMoved:(UITouch*)touch;  // not full signature for simpleness (UIEvent should be also here)
}

然后创建图层,它将手动处理其子项的触摸:

@interface TouchHandler : CCLayer
{
    NSMutableArray *draggableChildren_, nonDraggableChildren_, *claimedChildren_;
    BOOL isDragging_;
}

@implementation TouchHandler

-(id) init
{
    ...
    self.isTouchEnabled = YES;
    draggableChildren_ = [[NSMutableArray alloc] init];
    nonDraggableChildren_ = [[NSMutableArray alloc] init];
    claimedChildren = [[NSMutableArray alloc] init];
    ...
}

TouchHandler创建两种方法,用于添加两种类型的子项 - 可以拖动的子项和其他子项。这些方法将禁用对孩子的触摸,因此父母将手动处理它们。

-(void) addChild:(CCNode*)child shouldBeDragged:(BOOL)shouldBeDragged
{
    NSMutableArray *arrayToAddChild = shouldBeDragged ? draggableChildren_ : nonDraggableChildren_;
    [arrayToAddChild addObject:child];
    // note, that if the child has its own children, you will need to 
    // set isTouchEnabled on all of them, as adding all children to array recursively
    if ([child respondsToSelector:@selector(setIsTouchEnabled:)]) ((CCLayer*)child).isTouchEnabled = NO;
    [self addChild:child]; // maybe you need to call -addChild:zOrder:tag: here
}

然后覆盖这样的触控手柄:

-(BOOL) ccTouchBegan:(UITouch*)touch
{
    for (CCNode *child in draggableChildren)
    {
        if ([child ccTouchBegin:touch])
        {
            // this behavior looks like the one in CCTouchDispatcher - 
            // we claim children which return YES for touchBegin
            [claimedChildren addObject:child];
        }
    }
}

-(void) ccTouchMoved:(UITouch*)touch
{
    for (CCNode *child in claimedChildren)
    {
        if ([(id<SwallowingOnTouchMovedNode>)child ccTouchMoved:touch])
        {
            isDragging_ = YES;
        }
    }

    // if no one swallowed touches
    if (!isDragging_)
    {
        for (CCNode *child in nonDraggableChildren)
        {
            // we did not called ccTouchBegan earlier for these items,
            // so for consistency we need to call it now
            if ([child ccTouchBegin:touch])
            {
                [child ccTouchMoved:touch];
                [claimedChildren addObject:child];
            }
        }
    }
}

-(void) ccTouchEnded:(UITouch*)touch
{
    isDragging_ = NO;
    for (CCNode *child in claimedChildren)
    {
        [child ccTouchEnded];
    }
}

不要忘记实施-ccTouchCancelled。这段代码非常具体,所以你可能需要做一些修改,但我希望我已经解释了我的想法。一般情况下,TouchHandler甚至可能不会像CCLayer那样工作,只需将其添加为接收触摸的目标代理。

还有另一种方式,从OOP的角度来看似乎更加一致和正确,但我不确定。 ccTouchBeginccTouchMovedccTouchEnded中的行为几乎与CCTouchDispatcher中的行为重复。您可以对其进行子类化并覆盖一些接收触摸事件的方法并实现-(BOOL)ccTouchMoved,就像我所做的那样。另外,我不知道我们是否可以替换默认CCTouchDispatcher。希望这会有所帮助!