我试图让玩家将游戏中的物体从屏幕的一部分拖到另一部分。问题是,要拖动的对象下面还有需要接收触摸的图层。通常我只是吞下触摸,但据我所知,这只能在ccTouchBegan
期间完成。我无法判断用户是否试图拖动对象直到调用ccTouchMoved
之后,所以我需要一种方法来明确吞下(或以其他方式防止下层)在我确定它之后接收触摸是我感兴趣的(ccTouchMoved
内)。
答案 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的角度来看似乎更加一致和正确,但我不确定。 ccTouchBegin
,ccTouchMoved
和ccTouchEnded
中的行为几乎与CCTouchDispatcher
中的行为重复。您可以对其进行子类化并覆盖一些接收触摸事件的方法并实现-(BOOL)ccTouchMoved
,就像我所做的那样。另外,我不知道我们是否可以替换默认CCTouchDispatcher
。希望这会有所帮助!