1

後のコードに示すように、cocos2d ゲームのメイン ゲーム レイヤー/シーンにセミ シングルトン アプローチを使用しています。

目的は、 [[GameLayer sharedGameLayer] restart]メソッドを呼び出して、一時停止レイヤーまたはゲームオーバー レイヤーのボタンを使用して、このシングルトン シーンを適切に再起動/再作成することです。

問題は、そのために CCTransition 効果を使用し、GameLayer のdeallocメソッドをsharedGameLayer = nil;でオーバーライドする場合です。行 (静的変数のリセットを確実にするため) では、sharedGameLayer 変数は最初の再起動後 (別名、最初の dealloc 後) に nil のままであるため、restartメソッドを呼び出しても何も起こりません。

疑いを持って動作するのは、 deallocメソッドをまったくオーバーライドしないことですが、replaceScene:を使用してシーンを再起動する前に、sharedGameLayer を nil に設定します。

質問:これは、このセミシングルトン クラスを再起動/再作成するための正しいアプローチですか?

前もって感謝します。

コード:

GameLayer.m:

static GameLayer *sharedGameLayer;

@implementation GameLayer

- (id)init
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    // always call "super" init
    // Apple recommends to re-assign "self" with the "super's" return value
    if (self = [super initWithColor:ccc4(255, 255, 255, 255) width:[CCDirector sharedDirector].winSize.width
                             height:[CCDirector sharedDirector].winSize.height])
    {

        // Set the sharedGameLayer instance to self.
        sharedGameLayer = self;

        // Set the initial game state.
        self.gameState = kGameStateRunning;

        // Register with the notification center in order to pause the game when game resigns the active state.
        NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
        [center addObserver:self selector:@selector(pauseGame) name:UIApplicationWillResignActiveNotification object:nil];

        // Enable touches and multi-touch.
        CCDirector *director = [CCDirector sharedDirector];
        [director.touchDispatcher addTargetedDelegate:self priority:0 swallowsTouches:YES];
        director.view.multipleTouchEnabled = YES;


        // Set the initial score.
        self.score = 5;

        // Create the spiders batch node.
        [self createSpidersBatchNode];

        // Load the game assets.
        [self loadAssets];


        // Play Background music.
        if (![SimpleAudioEngine sharedEngine].isBackgroundMusicPlaying)
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"backgroundmusic.mp3" loop:YES];

        // Preload sound effects.
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"inbucket.mp3"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"outbucket.mp3"];
        [[SimpleAudioEngine sharedEngine] preloadEffect:@"gameover.mp3"];

        // Schdule updates.
        [self scheduleUpdate];
        [self schedule:@selector(releaseSpiders) interval:0.7];
    }

    return self;
}



- (void)createSpidersBatchNode
{
    NSLog(@"%s", __PRETTY_FUNCTION__);

    // BatchNode. (For Animation Optimization)
    self.spidersBatchNode = [CCSpriteBatchNode batchNodeWithFile:@"spiderAtlas.png"];

    // Spider sprite + BatchNode + animation action.
    for (int i = 0; i < 50; i++) {
        Spider *spider = [[Spider alloc] init];
        spider.spiderSprite.visible = NO;
    }

    [self addChild:self.spidersBatchNode];
}



- (void)restartGame
{
    // Play button pressed sound effect.
    [[SimpleAudioEngine sharedEngine] playEffect:@"button.mp3"];

    // Nil'ing the static variable.
    sharedGameLayer = nil;

    // Restart game.
    [[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[GameLayer scene]]];
}



+ (CCScene *)scene
{
    // 'scene' is an autorelease object.
    CCScene *scene = [CCScene node];

    // Game Layer.
     // 'gameLayer' is an autorelease object.
    GameLayer *gameLayer = [GameLayer node];

     // add gameLayer as a child to scene
    [scene addChild: gameLayer];

    // HUD Layer.
    HUDLayer *hudLayer = [HUDLayer node];
    [scene addChild:hudLayer];
    gameLayer.hud = hudLayer;

    // return the scene
    return scene;
}



+ (GameLayer *)sharedGameLayer
{
    return sharedGameLayer;
}



- (void)cleanup
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
    [self stopAllActions];
    [self unscheduleAllSelectors];
    [self unscheduleUpdate];

    [self removeAllChildrenWithCleanup:YES];
    self.hud = nil;

    [super cleanup];
}



//- (void)dealloc
//{
//    sharedGameLayer = nil;
//}


@end
4

2 に答える 2

0

最初のレイヤーが解放される前に新しいゲーム レイヤーが作成されるため、静的変数が nil に設定されます。dealloc で sharedGameLayer が self と等しいことを確認します。

于 2013-06-30T23:48:35.673 に答える
0

dealloc を使用して static 変数を nil に設定しないでください。オブジェクトの使用が停止すると、Dealloc が発生します。アプリの動作を制御するために使用しないでください。

ご存知のとおり、に設定sharedGameLayerしてからnilメソッドdeallocが呼び出されるまでに 30 分が経過した可能性があります。あるいは、まったく呼び出されないdeallocかもしれません。

あなたのコードはよさそうです。コメントアウトされた「dealloc」コードを削除してください。

また、このコード:

[[NSNotificationCenter defaultCenter] removeObserver:self];

-deallocカスタム メソッドに加えて、メソッドで実行する必要があります-cleanup。オブザーバーを 2 回削除してもまったく問題ありません。既に削除されている場合は何も起こりません。

別の注意として、+sharedGameLayerタイプの変数を返すinstancetype必要があり、変数の設定を担当する必要がありsharedGameLayerます。sharedGameLayerの中に-initいると、バグに遭遇します。

例えば:

+ (instancetype)sharedGameLayer
{
    if (sharedGameLayer)
        return sharedGameLayer;

    sharedGameLayer = [[[self class] alloc] init];

    return sharedGameLayer;
}

- (id)init
{
    if (!(self = [super init]))
        return nil;

    .
    .
    .

    return self;
}
于 2013-06-30T23:51:07.003 に答える