2012-04-17 1 views
1

私は単純なマルチタッチ描画のiPadゲームを作成するためにQuartz 2Dを使用しています。このゲームでは、1/30秒ごとに指の位置に新しいストロークを描く必要があります。iOSのシンプルなマルチタッチ描画アプリケーション:余りにも遅い(drawRect()が加法的でないため)

私が知る限り、drawRect()は、呼び出されるたびにコンテキストをクリアしないようにする方法は基本的にありません(self.clearsContextBeforeDrawing = NO;動作しません)ので、私の解決策はバックバッファビットマップ(またはレイヤー、私は両方を使用することができます)は、各新しいストロークをそのバックバッファに各指ごとに描画し、drawRect()を呼び出すたびにバッファを画面にコピーします。言い換えれば:

backlayer = CGLayerCreateWithContext(context, CGSizeMake(W, H), NULL); 
offctx = CGLayerGetContext (backlayer); 

、その後

- (void)drawRect:(CGRect)rect 
{ 

    CGContextRef context = UIGraphicsGetCurrentContext(); 

    //code here to draw small strokes from old finger position to new one 

    CGContextDrawLayerInRect(context, [self bounds], backlayer); 
} 

私は私のiPad 2上でテストしていた間、これは問題なく働いたが、昨日、私はこれと同じコードが新しいiPad 3にはるかに遅く走ることに気づきました。パフォーマンスは、30FPSから約5倍にまで、ゲームの速度を落としてしまいます。これはおそらく、より大きな網膜ディスプレイのためです。別のCGBitmapContextを使用して作成した場合と、それからImageRefを作成してCGContextDrawImageを使用してペイントするたびに、同じ問題が発生します。

これに対処するにはどのような方法がありますか?それは、それがさらに変更されたものののdrawRectに小さなrectangeを渡すために十分ではありませんので、私はすべての繰り返し、すべてを再描画する必要がありますように思える

はあなたに

+0

なぜサークルを再描画する必要があると感じますか?サークルを含むレイヤーやビューを作成し、必要に応じてアニメーションや位置を変更してみましょう。これは、非常に高価な再描画操作を回避します。 –

+0

私は理解しているとは思わない。私のサークルはすべて、時間枠ごとに異なって見えます。それらが異なる色またはサイズでなければならないと仮定します。同じパターンを別の場所にコピーすることはできません。また、私は最終的に数千のオーダーで、おそらく多くのサークルを持つ必要があります。言い換えれば、純粋に相加的なキャンバスを何らかの方法で表示する方法が必要です。 – karpathy

+0

ユニークな円を描き、互いにオーバーレイさせる必要がある場合は、各サークルを独自のCALayerまたはUIViewに描画し、これらのレイヤーを重ねて配置して全体のシーンを作成します。そうすれば、各サークルを一度描くだけで済みますし、合成後に残りの部分を処理します。合成はCore Graphicsの描画よりはるかに高速です。特定の点を超えて、背景の円をまとめてメモリに保存することもできますが、もう一度そのラスタライズを行い、その上に新しいサークルを重ねる必要があります。 –

答えて

2
ありがとうございました(すべての反復ので、各指のためのいくつかの四角形があることが必要になります)

次のように私はこの問題を解決するために管理:

私は新しいUIViewのサブクラスのヘッダーと実装ファイルを作成します。

@interface fingerView : UIView { 
} 

その後、私のメインビューで、ヘッダに私はこれらのビューの5を宣言:

fingerView* fview[5]; 

私の主なビューの実装では、このインスタンスの5つのビューを作成します(各フィンガーごとに1つずつ)。また、それらを作成し、それぞれのマルチタッチを有効にし、clearsContextBeforeDrawingがNOに設定されていることを確認する必要があります。一度に小さなrectを更新するため、システムが作業。すべての指のビュー内の今

for(int i=0;i<5;i++) { 
     fview[i] = [[pView alloc] initWithFrame:topFrame]; 
     [self addSubview: fview[i]]; 
     [self sendSubviewToBack: fview[i]]; 
     fview[i].opaque= NO; 
     fview[i].clearsContextBeforeDrawing = NO; 
     fview[i].multipleTouchEnabled = YES; 
} 

指が上に描画したxとyの位置の大きな配列を(私は単純な配列を使用し、万が長いと言う)に保ちます。 [fview [i] updatePos(newx、newy)]を呼び出して、これらの座標を中心とした小さなポーションを更新するように指示します:

[fview[i] setNeedsDisplayInRect: fingerRect]; 

ここで、fingerRectは(newx、newy)を中心とする小さな矩形です。すべての指のビューのためのdrawRectメソッド内で、

- (void)drawRect:(CGRect)rect 
{ 
    if (movep==0) return; 

    CGContextRef context = UIGraphicsGetCurrentContext(); 
    CGContextSetRGBStrokeColor(context, r, g, b, 1); 
    CGContextSetLineWidth(context, linewidth); 

    //paint finger 
    CGContextBeginPath(context); 
    CGFloat slack= 15; 
    CGFloat minx= CGRectGetMinX(rect)-slack; 
    CGFloat maxx= CGRectGetMaxX(rect)+slack; 
    CGFloat miny= CGRectGetMinY(rect)-slack; 
    CGFloat maxy= CGRectGetMaxY(rect)+slack;  
    bool drawing = NO; 
    for(int i=0;i<movep;i++) { 
     CGFloat xx= x[i]; 
     CGFloat yy= y[i]; 
     if(xx>minx && xx<maxx && yy>miny && yy<maxy) { 

      if(drawing) { 

       // continue line 
       CGContextAddLineToPoint(context, xx, yy); 
       CGContextMoveToPoint(context, xx, yy); 

      } else { 

       // start drawing 
       CGContextMoveToPoint(context, xx, yy); 
       drawing= YES; 
      } 

     } else { 
      drawing= NO; 
     } 
    } 

    CGContextStrokePath(context); 

とも私は

- (void)updatePos: (CGFloat)xnew: (CGFloat) ynew 
{ 
    x[movep]= xnew; 
    y[movep]= ynew; 
    movep= movep+1; 

を述べたように、うまくいけば、あなたはこれがどのように機能するかを把握することができます。すべてのビューは、変更されたこの矩形を調べ、その矩形の周りにあるすべての指の位置をチェックし、それらを描画します。これは非常に少ないストロークになるため、コード全体が非常に高速に実行されます。

全体的なレッスンは、UIViewがきわめて最適化されていることです。できるだけたくさんのものを作ってみましょう。それをローカルでのみ更新して、Appleの魔法のすべてを融合させましょう。

関連する問題