0

私が書いている cocos2D プログラムでタッチ イベントを処理する際に興味深い問題があります。CCScene に 3 つの CCLayer サブレンズ レイヤーがあります。

backgroundLayer – z:0 – 背景画像を表示するために使用される単純な静的レイヤー。

PlanetLayer - z:3 – 表示レイヤー – データ変更の視覚化がここに表示されます。

gameControlsLayer – z:5 – スライダーやボタンなどのデータ コントローラーを表示するために使用されるレイヤー。

コントロールが影響を受けることを心配せずに惑星レイヤーをパンおよびズームしたいので、惑星レイヤーとコントロール レイヤーを分離しました。

これらのレイヤーを設定するシーンの初期化コードは次のとおりです。

- (id) init
{
    self = [super init];
    if (self != nil)
    {
        // background layer
        BackgroundLayer *backgroundLayer = [BackgroundLayer node];
        [self addChild:backgroundLayer z:0];

        // planet layer
        PlanetLayer *planetLayer = [PlanetLayer node];
        [self addChild:planetLayer z:3];

        // gameplay layer
        GameControlsLayer *gameControlsLayer = [GameControlsLayer node];
        [self addChild:gameControlsLayer z:5];
    }
    return self;
}

惑星レイヤーとコントロールレイヤーの両方でタッチ処理が必要です。コントロール レイヤーでは、タッチ処理はレイヤーの子であるコントロール オブジェクト内にあります。最初にこのコードをすべて書きましたが、問題なく動作します。

その後、惑星レイヤーのレイヤー全体のタッチ処理を記述して、タッチ スクロールとズームを実行できるようにしました。スクロールはできましたが(まだズームはできていません)、問題なく動作しています。私の問題は次のとおりです。コントロールレイヤーのコントロールをタッチして操作すると、正常に動作しますが、たとえば、スライダーの親指を上下に動かすと、コントロールレイヤーの背後にある惑星レイヤーが、タッチが意図されているかのようにパンしますそれ。

コードを含めるのは冗長かもしれませんが、関連するスニペットは次のとおりです。

スライダー コントロールの場合、コントロール レイヤーの子:

- (void) onEnterTransitionDidFinish
{
    [[CCTouchDispatcher sharedDispatcher] 
      addTargetedDelegate:self priority:1 swallowsTouches:YES];
}

- (void) onExit
{
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
}

#pragma mark Touch Delegate

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint location = [[CCDirector sharedDirector]
               convertToGL:[touch locationInView:[touch view]]];



    float distance = [self distanceBetweenPointOne:thumbPosition
                                       andPointTwo:location];
    if (distance > thumbRadius*2)
    {
        return NO;
    }

    // touch is on the thumb. store the location so we 
    // can calculate changes on ccTouchMoved events
    touched = YES;
    return YES;
}

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    if (!touched)
    {
        return;
    }

    CGPoint location = [[CCDirector sharedDirector]
               convertToGL:[touch locationInView:[touch view]]];
    location = [self convertToNodeSpace:location];

    // if we're too far off the thumb, abandon it
    float distance = [self distanceBetweenPointOne:thumbPosition
                                       andPointTwo:location];
    if (distance > thumbRadius*3)
    {
        //touched = NO;
        return;
    }

    // this call adjusts some ivars – not relevant
    [self updateValueAndPosition:location];
}

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
    if (touched)
    {
        touched = NO;
    }
}

- (void)ccTouchCancelled:(UITouch *)touch 
               withEvent:(UIEvent *)event
{
    [self ccTouchEnded:touch withEvent:event];
}

惑星レイヤーからの関連コードは次のとおりです。

// Yes, we want touch notifications please
//
- (void) onEnterTransitionDidFinish
{
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
       priority:0 swallowsTouches:NO];
}

#pragma mark Touch Delegate

- (BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    CGPoint touchLocation = [touch locationInView:[touch view]];
    touchLocation = [[CCDirector sharedDirector]
                      convertToGL:touchLocation];

    // ****NOTE – the following is a kludge I used it to break
    // ********** the behavior; the controls are all grouped
    // ********** at the bottom of the screen. But this is not
    // ********** an acceptable fix. I shouldn’t need to mask
    // ********** off certain areas of the screen. This strategy
    // ********** will not hold once I add other controls to the
    // ********** control layer.
    //
    if (touchLocation.y > 250.0f)
    {
        self.touched = YES;
        touchHash = [touch hash];
        return YES;
    }
    return YES;
}

- (void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    if (!touched)
    {
        return;
    }

    if ([touch hash] == touchHash)
    {
        CGSize screenSize = [[CCDirector sharedDirector] winSize];

        CGPoint touchLocation = 
                [touch locationInView:[touch view]];
        CGPoint prevLocation = 
                [touch previousLocationInView:[touch view]];

        touchLocation = [[CCDirector sharedDirector]
                          convertToGL:touchLocation];
        prevLocation = [[CCDirector sharedDirector]
                          convertToGL:prevLocation];

        CGPoint diff = ccpSub(touchLocation, prevLocation);

        CGPoint currentPosition = [self position];
        CGPoint newPosition = ccpAdd(currentPosition, diff);

        if (newPosition.x < lowestX)
            newPosition.x = lowestX;
        else if (newPosition.x > highestX-screenSize.width)
            newPosition.x = highestX-screenSize.width;

        if (newPosition.y < lowestY)
            newPosition.y = lowestY;
        else if (newPosition.y > highestY-screenSize.height)
            newPosition.y = highestY-screenSize.height;

        [self setPosition:newPosition];
    }
}

- (void)ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
{
    if ([touch hash] == touchHash)
    {
        if (touched)
        {
            touched = NO;
        }
    }
}

- (void)ccTouchCancelled:(UITouch *)touch 
               withEvent:(UIEvent *)event
{
    [self ccTouchEnded:touch withEvent:event];
}

ピンチ ズーム機能を追加したいのですが、その前にこの問題を解決する必要があります。誰かがここで答えを持っていますか? 明らかな何かが欠けているように感じます…</p>

ありがとう!

4

1 に答える 1

0

planetLayerで、タッチがいずれかのccTouchBegan:コントロール内にあるかどうかを判断する方法を見つける必要があります。そのような場合は、YES ではなく NO を返します。

あなたが持っている1つの可能性はチェックです[touch view](UIKitオブジェクトで作られたコントロールレイヤーがあり、そのように機能します)、そうでなければ、タッチの座標を取得して、それらがCGRectContainsPoint([control rect], location)).

于 2011-07-28T22:17:43.573 に答える