2

CCSpriteBatchNode の使用を最適化する方法を知りたいです。言い換えれば、私は次のことを理解しています:

  • 1) 各 CCSpriteBatchNode インスタンスは draw メソッドの呼び出しを 1 回実行するため、OpenGL 呼び出しが減少し、パフォーマンスが大幅に向上します。
  • 2) 各 CCSpriteBatchNode は、テクスチャ アトラスを 1 つだけ参照できます。

私は100%確信が持てませんが、あなたの答えは次のとおりです。

  • 3) game-art-hd.png などの 1 つのテクスチャ アトラスがあり、さまざまなクラスでいくつかの CCSpriteBatchNode を作成すると、複数の描画呼び出しが発生しますか? 言い換えると、CCSpriteBatchNode の各インスタンスが独自の描画メソッドを呼び出すと想定しているため、複数の GL 描画呼び出しが発生し、1 つの共有バッチ ノードを使用する場合よりもパフォーマンスが低下します。私は正しいですか?

    - 4) スプライトで複数のフレームからなるアニメーションを使用している場合、アニメーション フレームをスプライト バッチ ノードに追加する必要があると思います。どうすればそうできますか?

    以下は、通常スプライトをアニメーション化する方法に関するコード スニペットです。お気づきのように、スプライト フレームはスプライト バッチ ノードに追加されません。パフォーマンスを向上させるには、おそらく初期化時にこれを行う必要があります。これは正しいです?

        NSMutableArray* frames = [[NSMutableArray alloc]initWithCapacity:2];
    
        for (int i = 0; i < 4; i++)
        {
            NSString*bulletFrame = [NSString stringWithFormat:@"animation-%i.png", i];            
            CCSpriteFrame* frame = [[CCSpriteFrameCache sharedSpriteFrameCache]spriteFrameByName:bulletFrame];
            [frames addObject:frame];
        }
        CCAnimation* anim = [CCAnimation animationWithFrames:frames delay:0.1f];
        CCAnimate* animate = [CCAnimate actionWithAnimation:anim];
        CCRepeatForever* repeat = [CCRepeatForever actionWithAction:animate];
        [self runAction:repeat];
    
    } 
    
  • 5) 部分的に 4. を参照していますが、実行時にスプライト バッチ ノードにスプライトを追加したり削除したりすることは避けたいと思いますか?

  • 6) CCSpriteBatchNode は、visible が true に設定されているスプライト、または実際に画面領域の外に位置するスプライトのみを考慮しますか?


3に関するその他の考慮事項

3. での私の仮定に対処し、CCSpriteBatchNode インスタンスの数を減らすために、私の解決策は、この回答で @Suboptimus によって提案されたものに従います。私は、self.parent.parent.(...).parent.finallysharedbatchNode 経由で MainScene にアクセスさせるのではなく、MainScene クラスと同じバッチ ノードを共有したいクラスを初期化するという提案されたアプローチが好きです。

代わりに、self.parent.....parent を使用して MainScene を参照し、正しくキャストすることを提案する人もいます。

これは、ソフトウェア エンジニアリングの観点からも最善のアプローチですか?

MainScene クラスへの明示的な参照を使用して、スプライトが追加される場所を明確にすることを好みます。これは、チームで作業している場合やクラス階層を変更する場合に役立ちます。しかし、これの欠点は、後でスプライトをバッチ ノードに追加したい場合に参照を保存する必要があり、維持するコードが増えることです。

私がこの質問をしている理由は、私の従来の「ソフトウェア エンジニアリング」の考え方と「Cocos2d 親ノード」階層アプローチとの間にわずかな衝突を見つけた場合です。私はゲームプログラミングが初めてで、大規模なチームで働く経験豊富なゲーム開発者がどのアプローチを使用しているかを理解したいと思います:)。H

4

1 に答える 1

1
  1. draw正解ですが、「描画呼び出し」はメソッドの実行と同等ではありません。描画呼び出しは、ステートマシンをリセットするためにコストのかかる操作を実行する必要がある OpenGL 状態の変更です。新しいテクスチャをバインドするか、トランスフォームを変更すると、法案に適合します。
  2. 正しい。
  3. 正しい。
  4. その必要はありません。アニメーションはスプライトで実行されます。したがって、スプライトのみをバッチ処理する必要があります。1 つのアニメーション フレームが同じテクスチャ アトラスからのものではない場合、アニメーションがそのようなフレームを使用しようとすると、CCSpriteBatchNode はエラーを出します。
  5. 好ましいです。CCSpriteBatchNode でのスプライトの追加/削除は、他のノードの追加/削除よりもコストがかかります。スプライト バッチ ノードのクワッドを更新する必要があるためです。ただし、多くの子ノードがあり、頻繁に追加/削除する場合にのみ違いがあります。
  6. いいえ、いいえ。ここで私の答えを見てください。

3 に関するその他の考慮事項:

シーンの階層があまり深くない場合、場合によっては self.parent またはおそらく self.parent.parent を使用できますが、親子関係が実質的に固定されている場合に限ります (つまり、スプライト バッチ ノードを順番にバイパスするスプライト バッチ スプライトから)。基礎となる「真の」親に到達するため)。しかし、私はこれ以上深入りすることをお勧めしません。self.parent と保持サイクルの回避の両方のテクニックについては、こちらの回答を参照してください。

問題self.parent.parent.(…).parentは、階層内の親ノードを追加または削除するなど、親子関係を変更する必要がある場合、これが完全に壊れることです。これは EXC_BAD_ACCESS でひどくクラッシュし、実際にどのようなオブジェクトであるかを確認するために各親と親の親をチェックする必要があるため、デバッグが困難です。階層の 3 つ以上のレベルで親にアクセスすることは、悪い習慣だとは思いません。それはひどい習慣です。

個人的には、共有スプライト バッチなどの一般的に使用されるノードへのアクセスについては、「MainScene」がアクティブな間だけ一時的なシングルトン クラスになるソリューションを好みます。次に、任意の子ノードから次の操作を実行できます。

CCSpriteBatchNode* mainBatch = [MainScene sharedMainScene].spriteBatchNode;

この一時的なシングルトンを作成するには:

static MainScene* instance;
-(id) init
{
    self = [super init];
    if (self)
    {
        instance = self;
    }
    return self;
}
-(void) dealloc
{
    instance = nil;
}
-(MainScene*) sharedMainScene
{
    NSAssert(instance, @"MainScene is not initialized!");
    return instance;
}

実際のシングルトンとの違いは、インスタンスがまだ存在しない場合、インスタンスを初期化しないことです。したがって、sharedMainScene の NSAssert です。すでに実行中のシーン インスタンスにのみアクセスする必要があります。つまり、その特定のシーンの子ノードによってのみ使用されます。

このセミシングルトンにより、シーンのすべてのプロパティにアクセスできます。シーンが他のノードに中継できるメッセージを送信することもできます。または、削除する必要があるシーン内の物理オブジェクトをエンキューしますが、衝突処理自体では削除できません。

そのシングルトンが気になる場合は、ディレクターから実行中のシーンを取得する可能性が常にあります。

MainScene* mainScene = (MainScene*)[CCDirector sharedDirector].runningScene;

runningScene が実際に MainScene オブジェクトである場合にのみ、MainScene へのキャストに注意する必要があります。isKindOfClass: チェックまたはアサートが必要です。

于 2012-09-18T09:10:47.630 に答える