Ios 从另一层重新启动游戏/场景

Ios 从另一层重新启动游戏/场景,ios,xcode,cocos2d-iphone,Ios,Xcode,Cocos2d Iphone,我现在很头痛,想安静地诊断一下这个问题 详细信息: 我有以下节点: 配子层;主游戏层,也是一个半单打 哈德勒;一个简单的HUD层(用于记分和暂停按钮),当然是和GameLayer一起添加到场景中的 波塞莱尔;一个CCLayerColor子类,包含一个简单的菜单(恢复、重新启动和主菜单) 每当按下暂停按钮时,PauseLayer将作为子对象添加到游戏层 问题: 通过在GameLayer本身中:[自重启游戏]重新启动游戏/场景,效果良好。 但是通过使用:[[GameLayer sharedGame

我现在很头痛,想安静地诊断一下这个问题

详细信息:
我有以下节点:

  • 配子层;主游戏层,也是一个半单打
  • 哈德勒;一个简单的HUD层(用于记分和暂停按钮),当然是和GameLayer一起添加到场景中的
  • 波塞莱尔;一个CCLayerColor子类,包含一个简单的菜单(恢复、重新启动和主菜单)
  • 每当按下暂停按钮时,PauseLayer将作为子对象添加到游戏层


    问题:
    通过在GameLayer本身中:[自重启游戏]重新启动游戏/场景,效果良好。 但是通过使用:[[GameLayer sharedGameLayer]restartGame]从PauseLayer调用相同的方法并不能用新实例完全替换GameLayer场景;旧场景仍然存在,没有孩子,相同的旧分数,等等,尽管游戏玩家的dealloc正在被调用(只有在没有使用转换的情况下)。

    代码:

    游戏玩家

    static GameLayer *sharedGameLayer;
    
    @implementation GameLayer
    
    - (id)init
    {
        // 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])
        {
            NSLog(@"%s", __PRETTY_FUNCTION__);
    
            sharedGameLayer = self;
            .
            .
    }
    
    
    + (GameLayer *)sharedGameLayer {
        @synchronized(self) {
            if (sharedGameLayer == nil) {
                sharedGameLayer = [[self alloc] init];
            }
        }
    
        return sharedGameLayer;
    }
    
    
    - (void)pauseGame
    {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    
        if (![[CCDirector sharedDirector] isPaused])
        {        
     // Disable the top menu.
            self.hud.topMenu.enabled = NO;
    
     // Pause game.
            [[CCDirector sharedDirector] pause];
    
     // Pause the background music.
            [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
    
     // Disable touch detection.
            [[CCDirector sharedDirector].touchDispatcher removeDelegate:self];
    
     // Add the Pause Layer.
            PauseLayer *pauseLayer = [[PauseLayer alloc] init];
            pauseLayer.tag = 2;
            pauseLayer.zOrder = 10;
            [self addChild:pauseLayer z:10 tag:2];
        }
    }
    
    
    - (void)restartGame
    {
        NSLog(@"%s", __PRETTY_FUNCTION__);
    
        [[NSNotificationCenter defaultCenter] removeObserver:self];
        [[CCDirector sharedDirector].touchDispatcher removeAllDelegates];
        [self stopAllActions];
        [self unscheduleAllSelectors];
        [self unscheduleUpdate];
    
        [self removeAllChildrenWithCleanup:YES];
    
        [[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
     //[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:1.0 scene:[GameLayer scene]]];
    }
    
    
    - (void)dealloc
    {
        NSLog(@"%s", __PRETTY_FUNCTION__);
        sharedGameLayer = nil;
    }
    
    @end
    

    波塞莱尔

    - (id)init
    {
        if (self = [super initWithColor:ccc4(0, 0, 0, 128) width:[CCDirector sharedDirector].winSize.width height:[CCDirector sharedDirector].winSize.height])
        {
     // Create a menu.
    
     // Resume button.
            CCLabelTTF *resumeLabel = [CCLabelTTF labelWithString:@"Resume" fontName:@"Marker Felt" fontSize:32];
            resumeLabel.color = ccc3(240, 240, 240);
            CCMenuItemLabel *resumeButton = [CCMenuItemLabel itemWithLabel:resumeLabel block:^(id sender) {
                [[GameLayer sharedGameLayer] resumeGame];
            }];
    
     // Restart Game button.
            CCLabelTTF *restartLabel = [CCLabelTTF labelWithString:@"Restart" fontName:@"Marker Felt" fontSize:32];
            restartLabel.color = ccc3(240, 240, 240);
            CCMenuItemLabel *restartButton = [CCMenuItemLabel itemWithLabel:restartLabel block:^(id sender) {
                [[GameLayer sharedGameLayer] restartGame];
            }];
    
     // Main Menu button.
            CCLabelTTF *mainMenuLabel = [CCLabelTTF labelWithString:@"Main Menu" fontName:@"Marker Felt" fontSize:32];
            mainMenuLabel.color = ccc3(240, 240, 240);
            CCMenuItemLabel *mainMenuButton = [CCMenuItemLabel itemWithLabel:mainMenuLabel block:^(id sender) {
                [[GameLayer sharedGameLayer] gotoMainMenu];
            }];
    
    
            CCMenu *menu = [CCMenu menuWithItems:resumeButton, restartButton, mainMenuButton, nil];
            [menu alignItemsVerticallyWithPadding:10.0];
            menu.position = ccp([CCDirector sharedDirector].winSize.width / 2, [CCDirector sharedDirector].winSize.height / 2);
            [self addChild:menu];
        }
    
        return self;
    }
    


    编辑: 如果我在GameLayer的init方法中添加暂停层(作为GameLayer的子对象,并且始终可见),那么一切都会完美地工作。。这有点奇怪。

    非常感谢您的任何意见。 提前谢谢

    从线路开始

    static GameLayer *sharedGameLayer;
    
    您需要在@implementation class line之前写这一行,使其不是类成员变量。在sharedGameLayer方法中,您应该将其更改为

    + (GameLayer *)sharedGameLayer {
        @synchronized(self) {
            if (sharedGameLayer == nil) {
                sharedGameLayer = [[self alloc] init];
            }
        }
    
        return sharedGameLayer;
    }
    

    而且,当您定义游戏层类时,您不调用init方法,但应该调用sharedGameLayer使游戏层类成为singleton。

    我不建议在CCLayers上使用singleton模式,但是您是否重写/编辑了CCScene包装器,使其不调用init

    比如说

    +(id)scene
    {
        CCScene* scene = [CCScene node];
        [scene addChild:[GameLayer sharedGameLayer]];
        return scene;
    }
    
    那么当你打电话的时候

    [[CCDirector sharedDirector] replaceScene:[GameLayer scene]];
    
    请记住在游戏结束后立即重新启动游戏

    [[GameLayer sharedInstance] restart];
    
    或者可以在场景包装器方法中执行此操作

    希望我明白你的意思


    至少这将使您不必一直为游戏层重新分配空间,呵呵。

    问题的罪魁祸首是在使用CCDirector的暂停方法暂停游戏后调用CCDirector的replaceSecene:method。

    我所做的是实现我自己的“暂停”功能,主要使用:[self pauseSchedulerAndActions];在我的例子中也是如此:[[self.spidersBatchNode children]makeObjectsPerformSelector:@selector(pauseSchedulerAndActions)];对于spriteBatchNode中的所有子节点。

    出现了另一个问题,我将提出另一个问题。

    感谢所有回复。

    静态游戏层*sharedGameLayer;确实已经超出了@Implementation指令的范围,我已经在代码中纠正了这一点。我还按照您的建议修改了+(GameLayer*)sharedGameLayer方法,但不幸的是,行为仍然是一样的。编辑:如果我在GameLayer的init方法中添加暂停层(作为GameLayer的子对象,并且始终可见),那么一切都会很好地工作。。这有点奇怪。[scene addChild:[GameLayer sharedGameLayer]];给出一个断言失败。另外,重新启动方法实际上是替换场景的方法。
    无论如何,我已经解决了一些出现的问题,因此我将首先编辑我的问题。这是新问题的URL,以防有人想跟进: