使用ARC的Cocos2d:当具有多个级别时,GameScene的单例模式的最佳实现是什么?

Cocos2d with ARC: what is the best implementation of singleton pattern for GameScene when having multiple levels?

编辑:我正在使用ARC

在我的代码中(基于本书中的ShootemUp示例,我高度推荐,这里提供第8章中的源代码),我经常使用通过以下方式访问游戏场景的技巧:

+(游戏场景*)sharedgamesecene;

它返回对gamesecene静态实例的引用,并由gamesecene的所有子代(例如shipEntity、inputlier..等)与游戏场景对话(编辑:即游戏场景的单例实例)。

为了创建多个级别,我考虑实现一个名为dscenewithid:(int)方法的方法,每次加载不同级别的数据。

编辑:init方法的代码段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-(id) initWithId:(int)sceneId
{
    CCLOG(@"scene With id");
    if ((self = [super init]))
    {
     //All common initialization happens here..
     switch (sceneId) {
        case 1:
            [self loadFirstLevelData];
            break;
        case 2:
            [self loadSecondLevelData];
            break;
        default:
            [self loadSecondLevelData];
            break;
    }
    //Other common stuff..
    [self setUpCounters];
    [self setUpWeaponsMenu];
    [self scheduleUpdate];
    [self schedule:@selector(timerUpdate:) interval:1];
    InputLayerButtons* inputLayer = [InputLayerButtons node];
    [self addChild:inputLayer z:1 tag:GameSceneLayerTagInput];
}

编辑:初始化方法可以吗?我找到了这篇文章,它使用了一次分派。我也应该这样做吗?

或者我应该先创建一个游戏场景类,然后再将其子类化?

1
E.g. FirstGameScene : GameScene

编辑:我按照@learncocos2d的建议使用了清理方法,并使用它来停止要播放的单件对象音乐层(Musiclayer对象在AppDelegate中初始化,我打算使用它来"管理"所有场景中的音乐-问题是,如果不在DealLoc中停止它,它将继续播放t是在初始化时加载的)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-(void) loadFirstLevelData{
//HERE WILL LOAD ALL SPECIFIC ELEMENTS: ENEMIES, BONUSES etc..

//AS WELL AS THE MUSIC FOR THE LEVEL
[[MusicLayer sharedMusicLayer] _loadMusic:@"1.mp3"];
[[MusicLayer sharedMusicLayer] playBackgroundMusicFile: @"1.mp3"];
}

-(void) cleanup
{
    //Should I remove all child loaded in LoadLevelData??
    CCLOG(@"cleanup GameScene");
    [[MusicLayer sharedMusicLayer] stopAllMusic];
    //MusicLayer is not a child of GameScene but of AppDelegate - the idea is to keep loading and unloading music files - sometimes I need to keep playing the file between scenes and hence I used the singleton pattern for this as well..
    [super cleanup];    
}

但我仍然有一些疑问:

  • 游戏场景类中有几个loadLevelData方法可以吗?每个方法可以有200行长!我试图放弃游戏场景,但有点混乱。我解释得更好。我在子类的头文件中导入了"gamesecene.h",通过这样做,我期望如果我只有ovverriden,那么只有某些方法(例如init),我就能够看到在gamesecene中导入的各种类(例如inputlayerbuttons)。事实并非如此。所以我可能不明白进口是如何在目标C中起作用的。

  • 是否可以在清理方法中删除特定的子项?我想我会删除loadlevelxxxdata方法中添加的所有子级,以减少内存使用。

  • 我已经为这个问题设置了一个赏金,但我可能需要测试答案并重新编辑,因为我对这个问题没有足够清晰的理解,无法在这个问题上做到非常精确。希望没问题。

    PS:如果有人想共享一个Cocos2d射击游戏的UML样式图,在该图中,各个级别和游戏场景都使用单例模式:),那就太好了。


    我将集中讨论下面的问题:

  • Is it ok to have several loadLevelData methods in GameScene class? Each method can be 200 lines long! I tried to sublcass GameScene but
    is a bit messy. I explain better. I imported"GameScene.h" in the
    header file of the subclass and by doing so I expected that if I had
    ovverriden only certain methods (e.g. init) I would have been able to
    see the various classes imported in GameScene (e.g.
    InputLayerButtons). It is not the case. So I probably don't understand
    how imports work in Objective-C
  • 长方法没什么错。不过,我怀疑您的加载方法执行非常相似的例程,所以您应该检查是否可以将这些例程归纳为子例程。一个好的指标是,如果有几行代码完全相同,除了参数或变量名。最佳实践是只写一次相同的代码,并用不同的参数多次执行它。

    #import语句用于允许编译器"查看"其他类。如果不导入其他头文件,就无法在没有编译器的抱怨的情况下使用该类的方法和属性。

    2 . Is it ok to remove specifc children in the cleanup method? I thought that I would remove all child that are added in the
    LoadLevelXXXData method to reduce the memory usage.

    在清理过程中移除孩子是没有意义的。cocos2d在清理过程中自动删除所有子项。

    如果您不这么认为,那么您在某个地方有一个保留循环,可以防止子节点解除分配。


    很抱歉回答这个问题,但我一直在尝试并决定:

    • 在游戏场景中不使用单件模式
    • 使用,代替singleton对象保留所有共享数据

    我的游戏场景(现在称为shooterscene)的实施草案如下(我在一篇Cocos2d iPhone论坛帖子以及另一篇文章中听取了一些建议):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    #import"ShooterScene.h"
    #import"LevelData.h"
    #import"HudLayer.h"


    @interface ShooterScene (PrivateMethods)
    -(void) loadGameArtFile;
    @end

    @implementation ShooterScene

    + (id) sceneWithId:(int)sceneId
    {
        CCScene *scene = [CCScene node];

        ShooterScene * shooterLayer = [ShooterScene node];
        [scene addChild:shooterLayer];
        [shooterLayer loadGameArtFile];

        LevelData * levelData = [LevelData node];
        [shooterLayer addChild:levelData];

        switch (sceneId) {
            case 1:
                [levelData loadLevelDataOne];
                break;
            case 2:
                [levelData loadLevelDataOne];
                break;            
            default:
                break;
        }

        HudLayer * hud = [HudLayer node];
        [hud setUpPauseMenu];
        [shooterLayer addChild:hud];

        return scene;    
    }

    我使用shooterscene的更新方法来管理所有游戏事件(例如,生成、检查碰撞、移动背景层)。我还没有将完整的实现放在这里,因为仍在进行中,但只是想知道我发现有用的答案类型。