« 『黒い豚カレーうどん』を食ってみた♪ | トップページ | 『キーチェーンアクセス』で証明書が作れません!(泣) »

2010年2月 5日 (金)

『iPhone』のマルチタッチってどうやったら良いのかね?

マップの拡大縮小や移動にマルチタッチは、どうよ?

ってな話があって…

何となくマルチタッチに対応…。

何となくざっくりソース…。

[EAGLView.h]
//--------------------------------------
- ( void )touchesBegan:( NSSet* )touches withEvent:( UIEvent* )event;
- ( void )touchesMoved:( NSSet* )touches withEvent:( UIEvent* )event;
- ( void )touchesEnded:( NSSet* )touches withEvent:( UIEvent* )event;
- ( void )touchesCancelled:( NSSet* )touches withEvent:( UIEvent* )event;

[EAGLView.m]
- ( id ) initWithCoder:( NSCoder* )coder
{
    ...
    // ※マルチタッチに対応します。
    self.multipleTouchEnabled    = YES;
    ...
}

//******************************************************************************
//    タッチ処理
//******************************************************************************
//**************************************
//    Work
//**************************************
BOOL            touchFlag;                // タッチフラグ
CGPoint            touchPoint;                // タッチ位置
CGPoint            touchMove;                // タッチ移動量
//--------------------------------------
BOOL            touchMultiFlag;            // マルチタッチフラグ
BOOL            touchMultiLock;            // マルチタッチフラグ
CGPoint            touchMultiCenter;        // マルチタッチ中心位置
float            touchMultiLength;        // マルチタッチ距離
CGPoint            touchMultiMove;            // マルチタッチ移動量
float            touchMultiRotate;        // マルチタッチ回転量
//**************************************
//    touchesMultiParameterGet
//**************************************
- ( void ) touchesMultiParameterGet:( NSSet* )touches
{
    static float    lengthBase, rotateBase;
    static CGPoint    centerBase;
    CGPoint            point0, point1, center;
    float            length, rotate, x, y;
    UITouch            *touch;
    NSArray            *array;

    touch        = [touches anyObject];
    array        = [touches allObjects];
    point0        = [ [array objectAtIndex:0]locationInView: self];
    point1        = [ [array objectAtIndex:1]locationInView: self];
    x            = point0.x - point1.x;
    y            = point0.y - point1.y;
    length        = sqrt( x * x + y * y );
    center.x    = x / 2 + point1.x;
    center.y    = y / 2 + point1.y;
    rotate        = atan2( y, x );

    // 初期化
    // ※『touchMultiFlag』で判断しているので注意
    if( !touchMultiFlag )
    {
        lengthBase        = length;
        centerBase        = center;
        rotateBase        = rotate;
        touchFlag        = FALSE;
        touchMultiLock    =
        touchMultiFlag    = TRUE;
    }

    touchMultiLength    = length - lengthBase;
    touchMultiCenter    = center;
    touchMultiRotate    = rotate - rotateBase;
    touchMultiMove.x    = center.x - centerBase.x;
    touchMultiMove.y    = - center.y + centerBase.y;

    printf( "l:%f - r:%f - mx:%f - my:%f\n", touchMultiLength, touchMultiRotate, touchMultiMove.x, touchMultiMove.y );
}

//**************************************
//    touchesParameterGet
//**************************************
- ( void ) touchesParameterGet:( NSSet* )touches
{
    static CGPoint    pointBackup;
    UITouch            *touch    = [touches anyObject];

    // マルチタッチ起動のチェック
    // ※『[touches count]>1』は、『UITouchPhaseBegan』だけでなく『UITouchPhaseMoved』中にも来ます。
    // ※そのためフラグとの組み合わせて起動をチェックしています。
    if( !touchMultiFlag && ( [touches count] > 1 ) )
    {
        [self touchesMultiParameterGet:touches];
        // …何か処理…
    }

    // マルチタッチ処理
    if( touchMultiFlag )
    {
        if( ( touch.phase == UITouchPhaseEnded ) || ( touch.phase == UITouchPhaseCancelled ) )
        {
            touchMultiLock    =
            touchMultiFlag    = FALSE;
            return;
        }
        if( [touches count] <= 1 )
        {
            touchMultiFlag    = FALSE;
            return;
        }
        [self touchesMultiParameterGet:touches];
        // …何か処理…
        return;
    }

    if( touchMultiLock )
        return;

    // シングルタッチ処理
    touchPoint    = [touch locationInView:self];

    switch( touch.phase )
    {
    case UITouchPhaseBegan:
        touchFlag    = TRUE;
        pointBackup    = touchPoint;
        // …何か処理…
        break;

    case UITouchPhaseEnded:
        touchFlag    = FALSE;
        // …何か処理…
        break;

    default:
        if( !touchFlag )
            return;
        break;

    case UITouchPhaseCancelled:
        touchFlag    = FALSE;
        return;
    }

    touchMove.x    = touchPoint.x - pointBackup.x;
    touchMove.y    = -touchPoint.y + pointBackup.y;

    printf( "mx:%f - my:%f\n", touchMove.x, touchMove.y );

    // …何か処理…
}
//**************************************
//    touchesBegan
//**************************************
- ( void ) touchesBegan:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches];
}

//**************************************
//    touchesMoved
//**************************************
- ( void ) touchesMoved:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches];
}

//**************************************
//    touchesEnded
//**************************************
- ( void ) touchesEnded:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches];
}

//**************************************
//    touchesCancelled
//    ※電話の着信などの強制割り込み時に呼ばれます。
//**************************************
- ( void ) touchesCancelled:( NSSet* )touches withEvent:( UIEvent* )event;
{
    [self touchesParameterGet:touches];
}

//******************************************************************************
//    End
//******************************************************************************

※『touchMultiLock』は、タッチする指を二本から一本、一本から二本と変えた時に
初期情報を初期化したいので『touchMultiFlag = FALSE』にします。
このとき『touchMultiFlag = touchFlag = FALSE』の状態が発生します。
さらにタッチする時に『UITouchBegan』まで発生します。
この時『[touches count]<=1』でシングルタッチ処理に流れてしまいます。
『touchMultiLock』でシングルタッチ処理へ流れるのを回避します。

ちなみに二本指の移動は、『iPhoneシミュレーター』で
『option + shift + マウス』でできるそうだ。

こちらに書いてあって助かった…。

[iPhone] iPhone シュミレータでマルチタッチを平行に動かす方法

有難うございます…。

>if( [touches count] == [ [event touchesForView:self] count] )

で最後の指が離れたのをチェックしろってのもあるけど…

3Dエディタのようにウインドウが個別にあってそのウインドウ内の
表示を個別に拡大縮小するのなら必要なのかも?

多分、これには必要無いと思う…。

取り合えず、これでOK!

と思う一方で…

駄目かも…。

あんま調べてないんで…。(汗)

何かバグ見付けたら教えてください…。>誰か…

※シミュレータでしか動作を確認していないんで実機だと駄目かも…。(汗)

PS.

ちなみに、これを作った後に『iPhone OS Reference Library』の
『Touches』ってサンプル見たけど…
全く異なる方式なので参考にならん…。

一応こちらに何となくテストプログラムをアップしてみた…。

「touch.zip」をダウンロード

操作は、こんな感じ…。
■マウスドラッグ
・移動
■option + マウスドラッグ
・拡大縮小
・回転
■option + shift + マウスドラッグ
・移動

詳しくは、ソースを見てちょ…。

2010年2月16日追記----------------

実機で試して見たらバグバグだった…。(汗)

二本以上になったら「event」から情報を得ないと駄目!

って事がわかった…。

でソースの書き換え…。

//******************************************************************************
//    タッチ処理
//******************************************************************************
//**************************************
//    Work
//**************************************
extern    float            scale;
extern    float            rotate;
extern    CGPoint            position;
//--------------------------------------
#define        PI                3.1415926535897932384626433832795
#define        SCALE_RATE        120
#define        MOVE_RATE        80
//--------------------------------------
BOOL            touchFlag;                // タッチフラグ
//--------------------------------------
BOOL            touchSingleFlag;        // シングルタッチフラグ
CGPoint            touchSinglePoint;        // シングルタッチ位置
CGPoint            touchSingleMove;        // シングルタッチ移動量
//--------------------------------------
BOOL            touchMultiFlag;            // マルチタッチフラグ
BOOL            touchMultiLock;            // マルチタッチロックフラグ
CGPoint            touchMultiCenter;        // マルチタッチ中心位置
float            touchMultiLength;        // マルチタッチ距離
CGPoint            touchMultiMove;            // マルチタッチ移動量
float            touchMultiRotate;        // マルチタッチ回転量
//**************************************
//    touchesMultiParameterGet
//**************************************
- ( void ) touchesMultiParameterGet:( UIEvent* )event
{
    static float    lengthBase, rotateBase;
    static CGPoint    centerBase;
    CGPoint            point0, point1, center;
    float            length, rotate, x, y;
    NSArray            *array;

    array        = [[event touchesForView:self] allObjects];
    point0        = [[array objectAtIndex:0]locationInView:self];
    point1        = [[array objectAtIndex:1]locationInView:self];
    x            = point0.x - point1.x;
    y            = point0.y - point1.y;
    length        = sqrt( x * x + y * y );
    center.x    = x / 2 + point1.x;
    center.y    = y / 2 + point1.y;
    rotate        = atan2( y, x );

    // 初期化(※『touchMultiFlag』で判断しているので注意)
    if( !touchMultiFlag )
    {
        lengthBase        = length;
        centerBase        = center;
        rotateBase        = rotate;
        touchSingleFlag    = FALSE;
        touchMultiLock    =
        touchMultiFlag    = TRUE;
    }

    touchMultiLength    = length - lengthBase;
    touchMultiCenter    = center;
    touchMultiRotate    = rotate - rotateBase;
    touchMultiMove.x    = center.x - centerBase.x;
    touchMultiMove.y    = - center.y + centerBase.y;
}
//**************************************
//    touchesParameterGet
//**************************************
- ( void ) touchesParameterGet:( NSSet* )touches event:( UIEvent* )event
{
    static float    scaleBackup, rotateBackup;
    static CGPoint    positionBackup;
    static CGPoint    pointBackup;
    UITouch            *touch    = [touches anyObject];

    // キャンセル時の処理
    if( touch.phase == UITouchPhaseCancelled )
    {
        touchFlag        =
        touchSingleFlag    =
        touchMultiLock    =
        touchMultiFlag    = FALSE;
        return;
    }

    // マルチタッチ起動のチェック
    // ※『[touches count]>1』は、『UITouchPhaseBegan』だけでなく『UITouchPhaseMoved』中にも来ます。
    // ※そのためフラグとの組み合わせて起動をチェックしています。
    if( !touchMultiFlag && ( [[event touchesForView:self] count] > 1 ) )
    {
        [self touchesMultiParameterGet:event];
        scaleBackup        = scale;
        rotateBackup    = rotate;
        positionBackup    = position;
    }

    // マルチタッチ解除
    if( touchMultiLock && ( touch.phase == UITouchPhaseEnded ) && ( [touches count] == [[event touchesForView:self] count] ) )
    {
        touchFlag        =
        touchSingleFlag    =
        touchMultiLock    =
        touchMultiFlag    = FALSE;
        return;
    }

    // マルチタッチ処理
    if( touchMultiFlag )
    {
        if( [touches count] <= 1 )
        {
            touchMultiFlag    = FALSE;
            return;
        }
        [self touchesMultiParameterGet:event];
        scale    = scaleBackup + touchMultiLength / SCALE_RATE;
        rotate    = rotateBackup - touchMultiRotate * 180 / PI;
        position.x    = positionBackup.x + touchMultiMove.x / MOVE_RATE;
        position.y    = positionBackup.y + touchMultiMove.y / MOVE_RATE;
        return;
    }

    if( touchMultiLock )
        return;

    // シングルタッチ処理
    touchSinglePoint    = [touch locationInView:self];
    switch( touch.phase )
    {
    case UITouchPhaseBegan:
        touchFlag        =
        touchSingleFlag    = TRUE;
        pointBackup        = touchSinglePoint;
        positionBackup    = position;
        break;

    case UITouchPhaseEnded:
        touchFlag        =
        touchSingleFlag    = FALSE;
        break;

    default:
        if( !touchFlag )
            return;
        break;
    }

    touchSingleMove.x    = touchSinglePoint.x - pointBackup.x;
    touchSingleMove.y    = -touchSinglePoint.y + pointBackup.y;
    position.x    = positionBackup.x + touchSingleMove.x / MOVE_RATE;
    position.y    = positionBackup.y + touchSingleMove.y / MOVE_RATE;
}
//**************************************
//    touchesBegan
//**************************************
- ( void ) touchesBegan:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches event:event];
}
//**************************************
//    touchesMoved
//**************************************
- ( void ) touchesMoved:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches event:event];
}
//**************************************
//    touchesEnded
//**************************************
- ( void ) touchesEnded:( NSSet* )touches withEvent:( UIEvent* )event
{
    [self touchesParameterGet:touches event:event];
}
//**************************************
//    touchesCancelled
//    ※電話の着信などの強制割り込み時に呼ばれます。
//**************************************
- ( void ) touchesCancelled:( NSSet* )touches withEvent:( UIEvent* )event;
{
    [self touchesParameterGet:touches event:event];
}
//******************************************************************************
//    End
//******************************************************************************


よもや、クソみそに言った「[[event touchesForView:self] count]」…。
これがキーワードだったとは…。

「touch-new.lzh」をダウンロード

|

« 『黒い豚カレーうどん』を食ってみた♪ | トップページ | 『キーチェーンアクセス』で証明書が作れません!(泣) »

コメント

勉強中さん
コメント有難う♪
頑張ってプログラムを完成させてください!

投稿: kouyou | 2011年12月13日 (火) 19時55分

マルチタッチで行き詰まってたら辿り着きました!
参考にさせて頂きます!
どうもありがとうございます!

投稿: 勉強中 | 2011年12月13日 (火) 17時50分

ヒギさん
コメントどうも♪
こう言う、書き込みがあるととっても嬉しいんですよ。
参考になってよかったです。
プログラム頑張ってください。

投稿: kouyou | 2010年12月 1日 (水) 00時29分

回転と拡大が一緒にできない〜ってずっと悩んでてこのサイトに辿り着きました。
このサンプルコードとソースありがとうございます。私のやりたかったことがこれで実現できそうです。ほんとうに感謝です!

投稿: ヒギ | 2010年12月 1日 (水) 00時14分

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: 『iPhone』のマルチタッチってどうやったら良いのかね?:

« 『黒い豚カレーうどん』を食ってみた♪ | トップページ | 『キーチェーンアクセス』で証明書が作れません!(泣) »