导航

cocos2d下的游戏菜单代码分析

Posted on 2011-11-22 23:25  吼吼睡  阅读(403)  评论(0编辑  收藏  举报

不管是多么华丽,多么耐玩的游戏,与用户第一次交互的往往却是菜单.在cocos2d里,提供了专门的CCMenu和CCMenuItem帮助开发这快捷 的实现游戏菜单.并且,借助各种动画效果,可以把游戏菜单做得很酷.
这次,我们依然是从学习cocos2d的官方例子入手.官方的MenuTest例子,提供了4个层来展示各种菜单效果和用户交互的实现.
我们逐个来分析一下关键代码.已经学习cocos2d好几天了,所以有些重复出现的代码,在学习笔记里会省略掉,只分析关键代码.

@implementation AppController
- (void) applicationDidFinishLaunching:(UIApplication*)application
{
    // 以上省略了大量初始化代码
    CCScene *scene = [CCScene node];
    // 这里是关键要学习的部分.
    // 既往我理解,放在同一个Scene里的多个Layer,同时按不同的z-order显示
    // 存在先后显示顺序的Layer,应该放入不同的Scene里显示.
    // 而这个问题,在发现CCMultiplexLayer的使用后,才得以真正理解.
    // 利用switchTo方法,可以改变激活显示的Layer,在Scene里改变显示的Layer
    CCMultiplexLayer *layer = [CCMultiplexLayer layerWithLayers: [Layer1 node][Layer2 node][Layer3 node],[Layer4 node]nil];
    [scene addChild: layer z:0];
    [window makeKeyAndVisible];
    [[CCDirector sharedDirector] runWithScene: scene];
}
//以下省略了大量代码
@end

@implementation Layer1
-(id) init
{
    if( (self=[super init])) {
   
        //设置默认的菜单项字体属性
        [CCMenuItemFont setFontSize:30];
        [CCMenuItemFont setFontName: @"Courier New"];

        //创建一个菜单项
        //这个菜单项完全使用精灵完成.
        //与其说是菜单项,不如说是个按钮,它像按钮一样,提供普通状态,点中状态和禁用状态三种不同状 态下需要显示的Sprite
        //并且,与UIButton类似的,点击事件通过对target的回调方法来实现.
        CCSprite *spriteNormal = [CCSprite spriteWithFile:@"menuitemsprite.png" rect:CGRectMake(0,23*2,115,23)];
        CCSprite *spriteSelected = [CCSprite spriteWithFile:@"menuitemsprite.png" rect:CGRectMake(0,23*1,115,23)];
        CCSprite *spriteDisabled = [CCSprite spriteWithFile:@"menuitemsprite.png" rect:CGRectMake(0,23*0,115,23)];
        CCMenuItemSprite *item1 = [CCMenuItemSprite itemFromNormalSprite:spriteNormal selectedSprite:spriteSelected disabledSprite:spriteDisabled target:self selector:@selector(menuCallback:)];
       
        //创建第二个菜单项.
        //这个菜单项与第一个类似,不同之处是直接使用图片完称,比精灵更简洁.
        CCMenuItem *item2 = [CCMenuItemImage itemFromNormalImage:@"SendScoreButton.png"selectedImage:@"SendScoreButtonPressed.png" target:self selector:@selector(menuCallback2:)];

        //创建第三个菜单项
        //这个菜单项使用的是文本Label方式
        //值得一提的是,cocos2d提供了超级方便的自定义字库调用方法.
        //如下方法中,设置好字库文件,并且以ascii字符排序顺序定义好字库的初始字符,就可以使用 字库创建文本Label.
        //以label方式创建的菜单项,会自动以点击放大作为菜单的操作效果来处理.
        //如果要求护理特别特殊的点中效果,也可以继承CCMenuItem之后复写selected方 法来实现
        CCLabelAtlas *labelAtlas = [CCLabelAtlas labelAtlasWithString:@"0123456789"charMapFile:@"fps_images.png" itemWidth:16 itemHeight:24 startCharMap:'.'];
        CCMenuItemLabel *item3 = [CCMenuItemLabel itemWithLabel:labelAtlas target:self selector:@selector(menuCallbackDisabled:)];
        item3.disabledColor = ccc3(32,32,64);
        item3.color = ccc3(200,200,255);
       

        // 创建第四个菜单项,这是一个纯文本的菜单项.
        CCMenuItem *item4 = [CCMenuItemFont itemFromString: @"I toggle enable items" target: self selector:@selector(menuCallbackEnable:)];
       
        // 创建第五个菜单项.
        // 这也是一个使用文本配合字库文件创建的菜单项.
        // 不同的是,这里使用了fnt格式的字库描述文件.关于fnt格式的字库描述文件,我们今后再做详细研究.
        CCBitmapFontAtlas *label = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"configuration"fntFile:@"bitmapFontTest3.fnt"];
        CCMenuItemLabel *item5 = [CCMenuItemLabel itemWithLabel:label target:self selector:@selector(menuCallbackConfig:)];
       
        // 创建第六个菜单项
        // 这是一个最普通的文本菜单项,但是它搭配了一个动画效果.文本颜色,会一直变化
        CCMenuItemFont *item6 = [CCMenuItemFont itemFromString: @"Quit" target:self selector:@selector(onQuit:)];
       
        id color_action = [CCTintBy actionWithDuration:0.5f red:0 green:-255 blue:-255];
        id color_back = [color_action reverse];
        id seq = [CCSequence actions:color_action, color_back, nil];
        [item6 runAction:[CCRepeatForever actionWithAction:seq]];

        // 使用上述所有菜单项,构造菜单.
        CCMenu *menu = [CCMenu menuWithItems: item1, item2, item3, item4, item5, item6, nil];
        // 将菜单居中对齐
        [menu alignItemsVertically];
       
       
        // 给菜单制作一个展现效果.
        // 以下的算法,实现了菜单项交叉从左右飞入的效果,还是很酷滴.
        // 关于cocos2d各种动画效果的使用,我觉得有必要单独开一篇学习笔记来学习,今天就先略过吧.
        CGSize s = [[CCDirector sharedDirector] winSize];
        int i=0;
        for( CCNode *child in [menu children] ) {
            CGPoint dstPoint = child.position;
            int offset = s.width/2 + 50;
            if( i % 2 == 0)
                offset = -offset;
            child.position = ccp( dstPoint.x + offset, dstPoint.y);
            [child runAction:
             [CCEaseElasticOut actionWithAction:
              [CCMoveBy actionWithDuration:2 position:ccp(dstPoint.x - offset,0)]
                                       period: 0.35f]
            ];
            i++;
        }

        //将第三个菜单项设为禁用,用于演示toggle菜单项的功能
        disabledItem = [item3 retain];
        disabledItem.isEnabled = NO;

        [self addChild: menu];
    }

    return self;
}

-(void) menuCallback: (id) sender
{
    //点击菜单项时,将激活Layer切换为另外一个,相当于进入2级菜单
    [(CCMultiplexLayer*)parent_ switchTo:1];
}

-(void) menuCallbackEnable:(id) sender {
    //点击菜单项时,将某个菜单项禁用
    disabledItem.isEnabled = ~disabledItem.isEnabled;
}

-(void) onQuit: (id) sender
{
    //点击退出按钮的处理
    //在SDK 3.0以上,苹果不允许应用程序自己执行退出.所以,应用程序其实不应该有自己的Quit菜单项.
    // http://developer.apple.com/iphone/library/qa/qa2008/qa1561.html
    [[CCDirector sharedDirector] end]
   
    if( [[UIApplication sharedApplication] respondsToSelector:@selector(terminate)] )
        [[UIApplication sharedApplication] performSelector:@selector(terminate)];
    else
        NSLog(@"YOU CAN'T TERMINATE YOUR APPLICATION PROGRAMATICALLY in SDK 3.0+");
}


//省略了其他代码.
@end


/第四个层演示了比较经典的设置界面.主要通过CCMenuItemToggle来实现
@implementation Layer4
-(id) init
{
    [super init];

    //创建一组开关菜单项,简单地说,就是on/of
    //这组菜单项由两部分组成
    //title是显示用的文字,不可以接受用户点击
    [CCMenuItemFont setFontName: @"American Typewriter"];
    [CCMenuItemFont setFontSize:18];
    CCMenuItemFont *title1 = [CCMenuItemFont itemFromString: @"Sound"];
    [title1 setIsEnabled:NO];
    //接下来的是可以接受用户点击的菜单项
    //这个菜单项提供了两个item,在call时,可以根据选中的index切换显示
    [CCMenuItemFont setFontName: @"Marker Felt"];
    [CCMenuItemFont setFontSize:34];
    CCMenuItemToggle *item1 = [CCMenuItemToggle itemWithTarget:self selector:@selector(menuCallback:) items:
                             [CCMenuItemFont itemFromString: @"On"],
                             [CCMenuItemFont itemFromString: @"Off"],
                             nil];
   
    //与上一个菜单项项相同,省略了两组共四个菜单项的代码

    //这个菜单项与上面的基本相同
    [CCMenuItemFont setFontName: @"American Typewriter"];
    [CCMenuItemFont setFontSize:18];
    CCMenuItemFont *title4 = [CCMenuItemFont itemFromString: @"Orientation"];
    [title4 setIsEnabled:NO];
    [CCMenuItemFont setFontName: @"Marker Felt"];
    [CCMenuItemFont setFontSize:34];
    CCMenuItemToggle *item4 = [CCMenuItemToggle itemWithTarget:self selector:@selector(menuCallback:) items:
                             [CCMenuItemFont itemFromString: @"Off"]nil];
    //不同的是,这个菜单项使用了subItems的addObjectsFromArray方法来设置更多 的可选项.
    NSArray *more_items = [NSArray arrayWithObjects:
                             [CCMenuItemFont itemFromString: @"33%"],
                             [CCMenuItemFont itemFromString: @"66%"],
                             [CCMenuItemFont itemFromString: @"100%"],
                             nil];
    [item4.subItems addObjectsFromArray: more_items];
        item4.selectedIndex = 2;//设置一个初选中的项目

    // 设置第五组菜单项
    [CCMenuItemFont setFontName: @"Marker Felt"];
    [CCMenuItemFont setFontSize:34];
   
    CCBitmapFontAtlas *label = [CCBitmapFontAtlas bitmapFontAtlasWithString:@"go back"fntFile:@"bitmapFontTest3.fnt"];
    CCMenuItemLabel *back = [CCMenuItemLabel itemWithLabel:label target:self selector:@selector(backCallback:)];

    //构建菜单
    CCMenu *menu = [CCMenu menuWithItems:
                  title1, title2,
                  item1, item2,
                  title3, title4,
                  item3, item4,
                  back, nil]//共五组九个菜单项.
    //对齐菜单项
    //这是一个比较独特的对齐方法,即让菜单项目以分列方式居中对齐.
    //第一组两列,会让前两个菜单项,将屏幕分为两列,在每列内居中.
    //最后设置为了列,使一个菜单项单独占据一行
    [menu alignItemsInColumns:
    [NSNumber numberWithUnsignedInt:2],
    [NSNumber numberWithUnsignedInt:2],
    [NSNumber numberWithUnsignedInt:2],
    [NSNumber numberWithUnsignedInt:2],
    [NSNumber numberWithUnsignedInt:1],
    nil
    ]// 2 + 2 + 2 + 2 + 1 = 共9个.
   
    [self addChild: menu]
    return self;
}

-(void) menuCallback: (id) sender
{
    //选中菜单项的回调,切换显示选中项目
    NSLog(@"selected item: %@ index:%d"[sender selectedItem][sender selectedIndex] );
}
//省略部分代码
@end