1

私の cocos2d ゲームでは、すべてのゲーム レイヤーに表示される共通のヘッダーとフッターを共有する必要があります。

ヘッダーにはキャッシュやスプライトなどが含まれますが、フッターにはさまざまなゲーム シーン間を移動するための CCMenuItem ボタンが含まれます。

ヘッダー/フッターは、表示されているすべてのものの上に表示されるように、現在のシーン/レイヤーよりもわずかに高い Z インデックスに表示されます。

たとえば、ヘッダーは次のようになります。

現金: $5,000

フッターは、たとえば、次のように、スプライト ボタンを備えた CCMenu のように見えます。

ホーム | 市場

これは hud システムと見なされます。

今、私はこれに似た方法ですべてのシーンに HUD を追加しようとしました。

HudLayer *hud = [HudLayer node]
[self addChild:hud z:1];

ただし、アサーション エラーが発生します。

* -[CCMenuItemSprite addChild:z:tag:] でのアサーションの失敗 ...

これは、別のシーンで HUD を再度追加できないために発生します。これは、私が cocos2d に対して持っている本当のフラストレーションです。

私が今までこの問題を解決できた唯一の方法は、CCLayer として a を持つ aBaseSceneを持ち、HUDNSNotifications を使用して後続のすべての CCLayer をロードすることです。

コードは次のとおりです。

#define HudBase 1
#define kHUDTag 9000

#import "cocos2d.h"

@interface BaseScene : CCScene

@end

@class HeaderHUDLayer;
@interface BaseLayer : CCLayer
{
    CCNode *currentNode;
    CCLayer *thisLayer;
    HeaderHUDLayer *hud;
}

@property (nonatomic, retain) CCNode *currentNode;
@property (nonatomic, retain) CCLayer *thisLayer;
@property (nonatomic, retain) HeaderHUDLayer *hud;

-(void) changeNodeTo:(CCNode *)thisNode;
-(void) changeHUDSceneObserver:(NSNotification *)notification;

@end

@implementation BaseScene

- (id)init
{
    self = [super init];
    if (self) {
        [self addChild:[BaseLayer node] z:0 tag:800];
    }
    return self;
}
@end

@implementation BaseLayer
@synthesize currentNode, thisLayer;
@synthesize hud;

-(id) init
{
    if ((self =[super init]))
    {
        NSLog(@"HUD Scene");

        self.hud = [HeaderHUDLayer node];

        if (self.currentNode == nil)
        {
            self.currentNode = [MyDashboardScene node];
            [self changeNodeTo:self.currentNode];
        }

        [self addChild:self.hud z:TopZLayer];

        [[NSNotificationCenter defaultCenter] addObserver:self selector: @selector(changeHUDSceneObserver:) name: @"changeHUDScene" object: nil];
    } // end if
    return self;
}


- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super dealloc];
}


-(void) changeNodeTo:(CCNode *)thisNode
{
    NSLog(@"changeNodeTo");
    [self removeChild:self.currentNode cleanup:YES];
    [self addChild:thisNode z:0];
    self.currentNode = thisNode;
}

-(void) changeHUDSceneObserver:(NSNotification *)notification
{
    NSLog(@"changeHUDSceneObserver = %@", notification.name);

    if ([notification.name isEqualToString:@"changeHUDScene"]==YES) {
        if ([notification object]!=nil) {
            [self changeNodeTo:[notification object]];
        }
    }
}

@end

ヘッダー自体は非常に複雑ですが、簡単に言えば、次のような CCLabel があります。

NSString *txtCash = [NSString stringWithFormat:@"Cash: %d", [player.cash intValue]];
            self.lblCash = [CCLabelBMFont labelWithString:txtCash fntFile:@"font_minipixi_16.fnt"];
            [lblCash setTag:kCashLabelTag];
            [lblCash setAnchorPoint:CGPointMake(1, 0)];
            [lblCash setPosition:CGPointMake(100, 8)];
[self addChild:lblCash];

これはうまく機能し、ゲームのすべての異なる部分間を移動でき、ヘッダー/フッターはすべてのシーンで共通です。

ただし、NSNotifications を使用してノードを変更すると、本当に頭痛の種になります。つまり、HUD 内のラベル (lblCash) を変更できないようで、これを解決する方法がわかりません。

たとえば、現金を減らす CCMenuItem をクリックすると、HUD ラベルは更新されません。

この問題を回避するために、別の NSNotification を使用してこれを解決します。複数の NSNotifications (ヘッダーの変更、ページの更新など) が必要な場合を除き、再送信できないため、アサーション エラーが発生します。

ヘッダーを更新するための NSNotification がある場合があり、その直後に別の NSNotification があり、ノードを提示したい別のノードにリダイレクトします。これもアサーション エラーを引き起こします。

全体があちこちで NSNotifications の混乱に陥っているように感じ、cosos2d に非常に不満を感じています。

私が試してみました:

ベース シーンで HUD (およびそのすべての子) を削除し、再度追加します。これによりアサーション エラーが発生し、実行できないようです。私はおそらくそれを間違ってコーディングしています

タグを使用して BaseScene/Layer をキャストし、HUD を取得して、そのようにラベルを更新しようとしています。

つまり、

    BaseLayer *baseLayer = (BaseLayer *) [self.parent getChildByTag:800];
    [baseLayer.hud updateCashAmount];

何もしません。(基本レイヤー/シーンと hud レイヤーにはすべてタグがあります)。

どちらも、

    HeaderHUDLayer *hud = (HeaderHUDLayer *)[base getChildByTag:kHUDTag];
    [hud updateCashAmount];

キャストできない理由は、NSNotifications がコンテキストを変更したためだと思います。

このすべてが私をcosos2dに非常に苛立たせました。

私が欲しいのは、多くのシーンで共通のヘッダー/フッターだけです。大騒ぎせずにヘッダーのラベルを更新できるようにしたいのです。

この場合、共通のヘッダー/フッター CCLayer を共有し、ヘッダー/フッター内の要素を更新可能にするにはどうすればよいでしょうか?

大量の NSNotifications をあちこちに配置せずにこれを行う簡単な方法はありますか?

感謝を込めて。

4

3 に答える 3

1

共通のメニューレイヤーを持つプロジェクトでは、このメソッドを使用して、あるシーンから別のシーンにレイヤーを転送します(Kobold2Dでは、このメソッドはすでに使用可能です)。

-(void) transferToNode:(CCNode*)targetNode
{
    NSAssert(self.parent != nil, @"self hasn't been added as child. Use addChild in this case, transferToNode is only for reassigning child nodes to another node");
    CCNode* selfNode = [self retain];
    [self removeFromParentAndCleanup:NO];
    [targetNode addChild:selfNode z:selfNode.zOrder tag:selfNode.tag];
    [selfNode release];
}

それはこのように動作します:

CCScene* newScene = [MyNewScene node];
[menuLayer transferToNode:newScene];
[[CCDirector sharedDirector] replaceScene:newScene];

これで、メニューレイヤーは次のシーンで存続します。それでおしまい。

PS:ARCを使用する場合は、保持行と解放行を省略してください。

于 2012-10-16T12:48:59.873 に答える
0

この問題には別の解決策があると思います。

要点をまとめると、

複数のシーン/レイヤーで共通のヘッダー/フッターを使用または共有したいと考えています。

私が行っていた方法は、私の HD である単一の子で BaseScene (CCScene) として使用し、次に NSNotification オブザーバーを使用して基になる子 (CCLayer) を変更することでした。

これは非常に厄介で、HUD のようなものがモーダル ダイアログに重なってしまいました。

モーダル ダイアログの問題はまだ解決できませんが、共通のヘッダー/フッターを共有するという点では、解決策があると思います。

Steffen Itterheim 著「Learn cocos2d game development with iOS5」の第 5 章あたりで、「セミシングルトン」の使用について説明しています。

以下は引用です。

static MultiLayerScene* multiLayerSceneInstance;
+(MultiLayerScene*) sharedLayer {
NSAssert(multiLayerSceneInstance != nil, @"MultiLayerScene not available!");
return multiLayerSceneInstance; }

-(void) dealloc {
// MultiLayerScene will be deallocated now, you must set it to nil multiLayerSceneInstance = nil;
// don't forget to call "super dealloc"
[super dealloc]; }

簡単に言うと、multiLayerSceneInstance は、現在の MultiLayerScene オブジェクトを存続期間中に保持する静的グローバル変数です。static キーワードは、multiLayerSceneInstance 変数が、それが定義されている実装ファイル内でのみアクセスできることを示します。同時に、これはインスタンス変数ではありません。クラスのスコープ外に存在します。そのため、メソッドの外側で定義され、sharedLayer などのクラス メソッドでアクセスできます。

使いやすくするために、GameLayer と UserInterfaceLayer へのアクセスは、プロパティ getter メソッドを通じて許可されます。

これにより、MultiLayerScene の任意のノードからさまざまなレイヤーに簡単にアクセスできます。

オープンソース ゲームで、著者のCastleHassleは同様の手法を使用しており、これを見て、シーンからシーンへと移動できる方法で「複製」し (実際には CCLayers です)、それらなしで同じ共通ヘッダーを共有することができました。迷惑な「...子は既に追加されました」というエラー。

私はそれをもう少し調査していますが、CastleHassle はこの問題を解決するのに大いに役立ちました。本のコードを試してみれば、さらなる解決策があるかもしれません。

要約すると、私が行った方法は、CastleHassle に従ってインスタンスの概念を使用することです。しかし、この本が共有インスタンスの概念でどのようにそれを行ったかを見ていきます。

于 2012-10-22T18:42:27.057 に答える