0

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

4

1 回答 1

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 的角度来看,这似乎更一致和正确,但我不确定。中的行为ccTouchBegin,几乎与 中ccTouchMoved的行为相同。您可以将其子类化并覆盖一些用于接收触摸事件和实现的方法,就像我所做的那样。另外,我不知道我们是否可以替换 default 。希望这会有所帮助!ccTouchEndedCCTouchDispatcher-(BOOL)ccTouchMovedCCTouchDispatcher

于 2013-09-01T00:03:51.333 回答