1

我正在对我的 cocos2d 游戏的主游戏层/场景使用半单例方法,如后面的代码所示。

目标是通过调用[[GameLayer sharedGameLayer] restart]方法使用暂停或游戏结束层中的按钮正确重新启动/重新创建此单例场景。

问题是如果我为此使用 CCTransition 效果,并用sharedGameLayer = nil;覆盖 GameLayer 的dealloc方法。行(以确保静态变量的重置),sharedGameLayer 变量在第一次重新启动后(又名第一次 dealloc 之后)保持为零,因此调用重新启动方法什么也不做。

值得怀疑的是根本不覆盖dealloc方法,而是在使用replaceScene:重新启动场景之前,我将 sharedGameLayer 设置为 nil。

问题:这是重新启动/重新创建这个半单例类的正确方法吗?

提前致谢。

代码:

游戏层.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

不要使用 dealloc 将静态变量设置为 nil。Dealloc您的对象停止使用后发生。永远不要用它来控制你的应用程序的行为。

就您所知,从您设置sharedGameLayer为到调用nil该方法之间可能已经过去了 30 分钟。dealloc或者也许dealloc永远不会被调用

您的代码看起来不错,只需删除注释掉的“dealloc”代码即可。

另外,这段代码:

[[NSNotificationCenter defaultCenter] removeObserver:self];

-dealloc除了您的自定义方法之外,还应该在方法中完成-cleanup。移除观察者两次是完全没问题的,如果它已经被移除,则不会发生任何事情。

另一个注意事项,+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 回答
0

我敢打赌,您的新游戏层是在第一个释放之前创建的,因此它将静态 var 设置为 nil。检查 sharedGameLayer 在 dealloc 中是否等于 self。

于 2013-06-30T23:48:35.673 回答