タップとドラッグを区別する方法


7

アプリを作成していて、画面上でスプライト(2つ目のスプライトを上にして)をドラッグできるようにアプリを作成しようとしていますが、スプライトをタップするだけで他のメソッドが呼び出されます。

スプライトの端に触れるとドラッグがうまく機能しましたが、スプライトの中央(2番目のスプライトが上にあるところ)からドラッグしようとすると、ドラッグがまったく機能しませんが、タップが呼び出されます。

なぜこれを行わないのか、わかっています。両方のスプリットからのタッチが競合しています。なぜなら、一番上のタッチが下の2番目のタッチに当たる前にタッチを飲み込んでいるからです。

指が動いたときにスプライトをドラッグしたいが、タップのみが与えられたときにタップを登録したい(つまり、指が画面上で動かなかった)場合、これをどのように実装できますか?

私が作業しているスプライトのビジュアル(役立つ場合): ここに画像の説明を入力してください

黄色のルーンはその下の石とは別のスプライトです(アニメーションが含まれているため)。

--------Touch for the top sprite----------
-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event{
    lastTouchLocation = [RuneScene locationFromTouch:touch];
    BOOL isTouchHandled = CGRectContainsPoint([charSprite boundingBox], lastTouchLocation);

    return isTouchHandled;
}
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent *)event{
    NSLog(@"Tap received!");

}

------Touch for the bottom sprite--------

-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event{
    lastTouchLocation = [RuneScene locationFromTouch:touch];
    BOOL isTouchHandled = NO;

    // Check if this touch is on the Spider's sprite.
    if (CGRectContainsPoint([current.runeSprite boundingBox], lastTouchLocation)){
        mover = current;
        isTouchHandled = YES;
    }
    else if(CGRectContainsPoint([rune1.runeSprite boundingBox], lastTouchLocation)){
        mover = rune1;
        isTouchHandled = YES;
    }
    else if(CGRectContainsPoint([rune2.runeSprite boundingBox], lastTouchLocation)){
        mover = rune2;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune3.runeSprite boundingBox], lastTouchLocation)){
        mover = rune3;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune4.runeSprite boundingBox], lastTouchLocation)){
        mover = rune4;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune5.runeSprite boundingBox], lastTouchLocation)){
        mover = rune5;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune6.runeSprite boundingBox], lastTouchLocation)){
        mover = rune6;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune7.runeSprite boundingBox], lastTouchLocation)){
        mover = rune7;
        isTouchHandled = YES;
    }else if(CGRectContainsPoint([rune0.runeSprite boundingBox], lastTouchLocation)){
        mover = rune0;
        isTouchHandled = YES;
    }

    // Stop the move action so it doesn't interfere with the user's scrolling.
    //[self stopActionByTag:ActionTagCastingLayerMovesBack];

    // Always swallow touches, GameLayer is the last layer to receive touches.
    return isTouchHandled;

}

-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent *)event{
    CGPoint currentTouchLocation = [RuneScene locationFromTouch:touch]; 

    // Take the difference of the current to the last touch location.
    CGPoint moveTo = ccpSub(lastTouchLocation, currentTouchLocation);

    // Then reverse it since the goal is not to give the impression of moving the camera over the background, 
    // but to touch and move the background.
    moveTo = ccpMult(moveTo, -1);

    lastTouchLocation = currentTouchLocation;

    [self moveActionWithLocation: moveTo];
}

-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent *)event{
    if (!current.isPlaced && mover == current && currentR < Rune6) {
        // Move the game layer back to its designated position.
        CCMoveTo* move = [CCMoveTo actionWithDuration:1 position:curPt];
        CCEaseIn* ease = [CCEaseIn actionWithAction:move rate:0.5f];
        //ease.tag = ActionTagCastingLayerMovesBack;
        [current.runeSprite runAction:ease];

        [current setIsPlaced:YES];
        current.charSprite = [characters objectAtIndex:currentR];
        current.charSprite.position = curPt;
        //charSprite.visible = YES;
        [current performSelector:@selector(fade:) withObject:current.charSprite afterDelay:1];
        [current reorderChild:current.charSprite z:10];

        [self updateCurrentRune:currentR];
        [self updateCurrentCastNum:currentP];
        [self reorderChild:current z:10];
    }
}

私はUITapGestureRecognizerを調べてみましたが、それを実装しようとするすべてのことは機能しません。レイヤー/スプライトでジェスチャーとして追加できません。私はCCGrstureRecognizerやcocos2dフォーラムで何かについても読みましたが、そのクラスに関するドキュメントが見つからず、実際にそれを使用する方法もわかりません...

私の問題を解決する方法を知っている人はいますか?

回答:


5

cocos2dについて具体的にお話しすることはできませんが、一般に、タップとドラッグは、マウスクリックとドラッグと同じ入力認識問題です。

これを処理する標準的な方法は、後で参照できるように、マウスダウン(またはタッチ)がいつ発生したかを記録し、発生した場所を保存することです。マウス移動(またはタッチ移動)イベントを監視して、移動するかどうかを確認します。元のクリック/タッチから特定の距離以上離れた位置に移動する場合(通常、マウス操作では3ピクセル-タッチコントロールの場合、このしきい値はやや高くなると考えられます)、クリック/タッチをドラッグとして分類します。そのように扱い始めます(オブジェクトの移動など)。マウスダウン/タッチがドラッグに変換されずに離された場合、格納されたクリック/タッチ位置を単純なクリック/タッチイベントとして処理します。

この単純な認識システムを、各タッチについて少し余分な状態を保存するだけで、すでに持っているTouchBegan、TouchMoved、TouchEndedの目的Cメッセージ内に完全に実装できるはずです。


単純すぎるわけではありませんが、プレスとリリースの違いについても考える必要があります。これは、長押しかタップかを理解するのに役立ちます。たとえば、画面に触れて1秒以上経過してリリースイベントが発生した場合、それを長押しとして扱い、次のリリースイベントを無視します。1秒経過する前にリリースを取得した場合は、リリースをタップとして扱います。
Gustavo Maciel 2012年

0

iOSはすでにタップ/ドラッグの検出を実装しています。

ccTouchMovedは、指が(許容範囲で)移動したときにのみ呼び出されます。したがって、ccTouchMovedをtopSpriteに実装するだけです。呼び出された場合、それはドラッグであると考えることができます。

-(BOOL) ccTouchBegan:(UITouch*)touch withEvent:(UIEvent *)event{
    lastTouchLocation = [RuneScene locationFromTouch:touch];
    BOOL isTouchHandled = CGRectContainsPoint([charSprite boundingBox], lastTouchLocation);
    dragged=NO;

    return isTouchHandled;
}
-(void) ccTouchMoved:(UITouch*)touch withEvent:(UIEvent *)event{
    NSLog(@"Drag !");

    dragged=YES;
}
-(void) ccTouchEnded:(UITouch*)touch withEvent:(UIEvent *)event{
    NSLog(@"Tap received!");
    if (!dragged) {
        //Follow tap event to the mainSprite
        //...TODO
    }
    dragged=NO;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.