Cocos2d-x 3.0菜单教程
2014.10.31 by cocos
教程
今天,将带大家一起征服Cocos2d-x的菜单。你不可能会做一个游戏而缺少菜单功能吧?cocos2d使得制作菜单变得非常简单。但是,在我们开始之前,需要确保构建一个系统,它非常容易扩展,以后制作任何游戏都可以用到,它就是我们即将创建的“场景管理器”(Scene Manager)。 你可以去Cocos2d-x官网上下载最新版本:http://www.cocos2d-x.org/download/version#Cocos2d-x。目前最新版本是3.0 beta2。 下载完最新版本后,解压,然后从终端(win下就是命令控制台)用cd命令进入Cocos2d-x目录下的tools/project-creator/,然后运行create_project.py,就会有一个简单的图形界面出现,填好工程命和包名就可以创建了。这里说以下,目前很多老的教程都是教的用模版创建工程,但是Cocos2d-x2.1.4以后就不能支持用模板方式新建工程,而新的创建方式具有跨平台方便,一个脚本生成所有平台的项目文件的优点。3.0版本的支持工程放在任意路径(2.x的默认放在Cocos2d-x目录下的projects文件夹下)。 一旦编译运行之后,你将看到下面的屏幕: 注意:如果条件允许的话,你应该把你的程序在老设备和新设备上都测试一下。我以前做游戏的时候,会在游戏的加载画面里面显示一些“提示”,这些信息可以帮助玩家更好地了解游戏的玩法。同时,这样也可以使得加载画面看起来更快,因为玩家注意力被分散了,所以感觉上“慢”了。然后,那种在1代的设备上要花费10秒来加载的画面,在iphone4上面可能一眨眼就没了。为了解决这个问题,我会在加载完成之后,显示一个“Continue”按钮,这样玩家就有时间读“提示信息”了,同时也不会感觉很奇怪。只是一个小技巧而已:) 我们将在一个背景层上面创建一个简单的菜单。在我们继续这个教程之前,我需要带领大家从头开始制作,这样的话能帮助大家更好地理解。首先最重要的事情,我们并不需要自动生成的HelloWorldScene.h和HelloWorldScene.m文件,所以让我们删了它们吧!    现在,我们将创建一个简单的场景管理器----我们这样做的目的是,今后可以对层与层之间的切换有更多的控制权。直接在“Classes”分组上面点击右键,然后是“New File”。 我们将添加一个新的“C++ Class”文件,Save As为“SceneManager”。    那么,这个文件里的代码看起来是什么样子呢?
#include "cocos2d.h"
#include "MenuLayer.h"

class SceneManager : public cocos2d::Object
{
public:
    SceneManager() {};
    ~SceneManager() {};

    static void goMenu();
private:
    static void go(cocos2d::Layer* layer);
    static cocos2d::Scene* wrap(cocos2d::Layer *layer);
};
然后,往.cpp文件里添加下列内容:
#include "SceneManager.h"
USING_NS_CC;

void SceneManager::goMenu()
{
    Layer *layer = MenuLayer::create();
    SceneManager::go(layer);
}

void SceneManager::go(Layer* layer)
{
    Director *director = Director::getInstance();
    Scene *newScene = SceneManager::wrap(layer);
    if ( director->getRunningScene() )
    {
        director->replaceScene(newScene);
    }
    else
    {
        director->runWithScene(newScene);
    }
}

Scene* SceneManager::wrap(Layer *layer)
{
    Scene *newScene = Scene::create();
    newScene->addChild(layer);
    return newScene;
}
你可能已经注意到了,我们包含了“MenuLayer.h”文件,然后在“goMenu”方法中使用了MenuLayer。所以,让我们再创建一个类,叫MenuLayer.h,如下所示: MenuLayer.h文件:
#include "cocos2d.h"

class MenuLayer : public cocos2d::Layer
{
public:
    bool init();

    void onNewGame(Object* pSender);
    void onCredits(Object* pSender);


    CREATE_FUNC(MenuLayer);
};
MenuLayer.cpp文件:
#include "MenuLayer.h"
#include "SceneManager.h"
USING_NS_CC;

bool MenuLayer::init()
{
    if ( !Layer::init() )
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();

    TTFConfig config_font96("Marker Felt.ttf", 96);
    TTFConfig config_font52("Marker Felt.ttf", 52);

    Label *titleLeft = Label::createWithTTF(config_font96, "Menu ");
    Label *titleRight = Label::createWithTTF(config_font96, " System");
    Label *titleQuotes = Label::createWithTTF(config_font96, "\"                        \"");
    Label *titleCenterTop = Label::createWithTTF(config_font52, "How to build a...");
    Label *titleCenterBottom = Label::createWithTTF(config_font96, "Part 1");

    MenuItemFont *startNew = MenuItemFont::create("New Game", CC_CALLBACK_1(MenuLayer::onNewGame, this));
    MenuItemFont *credits = MenuItemFont::create("Credits", CC_CALLBACK_1(MenuLayer::onCredits, this));

    Menu *menu = Menu::create(startNew, credits, NULL);

    titleCenterTop->setPosition(
                   Point( (visibleSize.width - titleCenterTop->getContentSize().width)/2,
                           visibleSize.height - 100) );
    this->addChild(titleCenterTop);

    titleQuotes->setPosition(
          Point((visibleSize.width - titleQuotes->getContentSize().width)/2,
          titleCenterTop->getPosition().y - titleQuotes->getContentSize().height - 40) );
    this->addChild(titleQuotes);

    int tileWidth = titleLeft->getContentSize().width + titleRight->getContentSize().width + 50;
    titleLeft->setPosition(
        Point( (visibleSize.width - tileWidth)/2,
            titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40) );
    this->addChild(titleLeft);

    titleRight->setPosition(
       Point( (visibleSize.width - tileWidth)/2 + titleLeft->getContentSize().width + 50,
           titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40) );
    this->addChild(titleRight);

    titleCenterBottom->setPosition(
        Point( (visibleSize.width - titleCenterBottom->getContentSize().width)/2,
        titleRight->getPosition().y - titleCenterBottom->getContentSize().height - 40) );
    this->addChild(titleCenterBottom);

    menu->setPosition(
            Point( visibleSize.width / 2,
                  titleCenterBottom->getPosition().y-150 ) );
    menu->alignItemsVerticallyWithPadding(80.0f);
    this->addChild(menu, 2);

    return true;
}

void MenuLayer::onNewGame(Object* pSender)
{
    SceneManager::goMenu();
}

void MenuLayer::onCredits(Object* pSender)
{
    SceneManager::goMenu();
}
最后,修改app delegate(MenuTutorialAppDelegate.m),包含SceneManager.h头文件:
#include "SceneManager.h"
并且删除:
#include "HelloWorldScene.h"
当然,我们还需要修改一些内容。因为所有的“runWithScene”逻辑,现在都被SceneManager类所替代,因此,把下面的语句:
auto scene = HelloWorld::createScene();
director->runWithScene(scene);
替换成:
SceneManager::goMenu();
我们也将会让我们的例子在Portrait模式运行(竖版)---因为屏幕方向跟各个平台有关系,专为跨平台设计的cocos2d-x没有提供相关api,针对xcode开发可以通过下列方式设置屏幕方向,其他平台的需求请自行搜索:
//IOS目录中RootViewController.mm
//显示竖屏
- (BOOL) shouldAutorotate {
    return NO;
}
//显示横屏
- (BOOL) shouldAutorotate { 
return YES;
}
这里有本教程的完整源代码 当你编译并运行工程之后,你就能看到上面的截屏啦!祝贺你完成了第一部分教程的学习,接下来,我们将在第二部分教程中学到更多有意思的内容。 原文链接:http://www.iphonegametutorials.com/2010/09/07/cocos2d-menu-tutorial/   如果你还没有阅读过第一篇教程的话,那么我建议你在继续之前,回过头去完成第一部分教程再回来。 今天,我们将在上一篇教程之上添加一些东西,同时,我们会用到动画和layer之间的切换效果(transition)。 这里有本教程的完整源代码。 好了,正式出发吧!第一步,就是整理一下我们将要实现些什么东西。如果在编码之前,你不做任何的计划的话,那么你什么也做不成!下面是我们这篇教程将要实现的功能特性列表:
  • 为credit场景和play场景添加一个新的层
  • 当从一个场景切换到另一个场景的时候,做一些transition。
  • 用文本构建菜单系统。
我保证接下来的内容很直白,而且很容易。 让我们先创建两个新类“PlayLayer”和“CreditLayer”--为什么要有Credit Layer?好吧,其实就是让别人知道这个游戏是你做的。我真的希望“PlayLayer”很清晰明了,其实就是我们游戏的GameScene或者MainScene,就是你实际玩游戏的场景。 因此,像之前添加“SceneManger”类一样,右键点击“Classes”分组,再选择“New Files”,选择IOS -> C and C++ -> C++ Class,如下所示:    同样的方法创建CreditLayer: 现在,我们有四个文件,但是里面啥也没有。。。别担心,我们马上会讲到如何添加里面的内容--首先是PlayLayer.h文件:
#include "cocos2d.h"
#include "SceneManager.h"

class PlayLayer : public cocos2d::Layer
{
public:
    PlayLayer();
    ~PlayLayer();
    bool init();
    void back(Object* pSender);

    CREATE_FUNC(PlayLayer);
};
现在是PlayerLayer.cpp文件:
#include "PlayLayer.h"
USING_NS_CC;

PlayLayer::PlayLayer()
{
}

PlayLayer::~PlayLayer()
{
}

bool PlayLayer::init()
{
    if(!Layer::init())
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();

    MenuItemFont *back = MenuItemFont::create("back", CC_CALLBACK_1(PlayLayer::back, this));
    Menu *menu = Menu::create(back, NULL);
    menu->setPosition(visibleSize.width/2, visibleSize.height/2);

    this->addChild(menu);

    return true;
}


void PlayLayer::back(Object* pSender)
{
    SceneManager::goMenu();
}

现在,CreditLayer和PlayLayer几乎差不多,除了名字不同以外。但是,为了教学的需要,我还是要展示出来--首先是CreditLayer.h文件:
#include "cocos2d.h"
#include "SceneManager.h"

class CreditLayer : public cocos2d::Layer
{
public:
    CreditLayer();
    ~CreditLayer();
    bool init();
    void back(Object* pSender);

    CREATE_FUNC(CreditLayer);
};
然后是CreditLayer.cpp文件:
#include "CreditLayer.h"
USING_NS_CC;

CreditLayer::CreditLayer()
{
}

CreditLayer::~CreditLayer()
{
}

bool CreditLayer::init()
{
    if(!Layer::init())
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();

    MenuItemFont *back = MenuItemFont::create("back", CC_CALLBACK_1(CreditLayer::back, this));
    Menu *menu = Menu::create(back, NULL);
    menu->setPosition(visibleSize.width/2, visibleSize.height/2);
    this->addChild(menu);

    return true;
}


void CreditLayer::back(Object* pSender)
{
    SceneManager::goMenu();
}
这些文件现在都只干一件事情----有一个“back”菜单按钮,当用户点击的时候,就通过SceneManager调转到MenuLayer。然后,如果你现在编译运行的话,也不会有任何问题,但是,你点back的时候,并不会跳转到任何场景去。。。我们马上就会来解决这个问题! 现在,我们回到SceneManager并作一些修改----添加两个方法“goPlay”和“goCredits”:
static void goPlay();
static void goCredit();
同时,我们要向SceneManager.cpp里面添加两个方法的实现,它让我们能够跳转到PlayerLayer和CreditsLayer中去。
//添加头文件
#include "PlayLayer.h"
#include "CreditLayer.h"

void SceneManager::goPlay()
{
    Layer *layer = PlayLayer::create();
    SceneManager::go(layer);
}

void SceneManager::goCredit()
{
    Layer *layer = CreditLayer::create();
    SceneManager::go(layer);
}
因此,现在完整的SceneManager.cpp文件,看起来如下所示:
#include "SceneManager.h"
#include "PlayLayer.h"
#include "CreditLayer.h"
USING_NS_CC;

void SceneManager::goMenu()
{
    Layer *layer = MenuLayer::create();
    SceneManager::go(layer);
}

void SceneManager::goPlay()
{
    Layer *layer = PlayLayer::create();
    SceneManager::go(layer);
}

void SceneManager::goCredit()
{
    Layer *layer = CreditLayer::create();
    SceneManager::go(layer);
}

void SceneManager::go(Layer* layer)
{
    Director *director = Director::getInstance();
    Scene *newScene = SceneManager::wrap(layer);
    if ( director->getRunningScene() )
    {
        director->replaceScene(newScene);
    }
    else
    {
        director->runWithScene(newScene);
    }
}

Scene* SceneManager::wrap(Layer *layer)
{
    Scene *newScene = Scene::create();
    newScene->addChild(layer);
    return newScene;
}
现在,我们只需要在MenuLayer中添加一些调用就可以了! 因为,我们创建了“onNewGame”和“onCredits”两个函数,在第一部分里,我们并没有在MenuLayer.h里添加任何方法声明。当然,不要忘了#include PlayLayer.h和CreditLayer.h两个头文件。 最后,我们需要在MenuLayer.cpp文件里使用SceneManager来实现“onNewGame”和“onCredits”两个方法:
void MenuLayer::onNewGame(Object* pSender)
{
    SceneManager::goPlay();
}

void MenuLayer::onCredits(Object* pSender)
{
    SceneManager::goCredit();
}
哇!就这么多代码!现在编译并运行,你现在有一个菜单,可以从“Play”到“Menu”,以及“Credits”之间相互切换了。 但是,看起来有点生硬,不够生动---接下来,让我们做一些更有趣的事情吧---来玩一玩transitons怎么样?:) 那么,我们怎么做呢?我们可以让SceneManager来完成所有的工作。好,我们先在“go”方法里面使用CCFadeTransition来replaceScene,如下所示:
director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
从下载下来的Cocos2d-x工程里的TestCpp测试代码中,找到TransitionsTest.h/.cpp,那里面有所有的transition的用法,后面我们用到的是从TransitionsTest切出来的一小部分。 为了从场景的字符串名字返回场景类,我们所要下面的宏定义和结构体:
#define STRINGIFY(x) #x

#define TRANS(__className__) {                                      \
    [](float t, Scene* s){ return __className__::create(t,s);},     \
        STRINGIFY(__className__),                                   \
}

struct _transitions {
    std::function<TransitionScene*(float t, Scene* s)> function;
    const char * name;
} transitions[] = {
    TRANS(PageTransitionForward),
    TRANS(PageTransitionBackward),
    TRANS(FadeWhiteTransition),
    TRANS(ZoomFlipXLeftOver),
    TRANS(FlipXRightOver),
    TRANS(FlipYUpOver)
};
这个结构体保存从场景的字符串名字返回的场景类和该字符串。顺便定义了一个保存该结构体的数组transitions,存储了6个我们要用到的场景跳转效果。 整个SceneManager类看起来如下所示:
#define TRANSITION_DURATION (1.2f)

class FadeWhiteTransition : public TransitionFade
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        return TransitionFade::create(t, s, Color3B::WHITE);
    }
};

class FlipXRightOver : public TransitionFlipX
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        return TransitionFlipX::create(t, s, TransitionScene::Orientation::RIGHT_OVER);
    }
};

class FlipYUpOver : public TransitionFlipY
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        return TransitionFlipY::create(t, s, TransitionScene::Orientation::UP_OVER);
    }
};

class ZoomFlipXLeftOver : public TransitionZoomFlipX
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        return TransitionZoomFlipX::create(t, s, TransitionScene::Orientation::LEFT_OVER);
    }
};

class PageTransitionForward : public TransitionPageTurn
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        Director::getInstance()->setDepthTest(true);
        return TransitionPageTurn::create(t, s, false);
    }
};

class PageTransitionBackward : public TransitionPageTurn
{
public:
    static TransitionScene* create(float t, Scene* s)
    {
        Director::getInstance()->setDepthTest(true);
        return TransitionPageTurn::create(t, s, true);
    }
};

#define STRINGIFY(x) #x

#define TRANS(__className__) {                                      \
    [](float t, Scene* s){ return __className__::create(t,s);},     \
        STRINGIFY(__className__),                                   \
}
struct _transitions {
    std::function<TransitionScene*(float t, Scene* s)> function;
    const char * name;
} transitions[] = {
    TRANS(PageTransitionForward),
    TRANS(PageTransitionBackward),
    TRANS(FadeWhiteTransition),
    TRANS(ZoomFlipXLeftOver),
    TRANS(FlipXRightOver),
    TRANS(FlipYUpOver)
};


#define MAX_LAYER (sizeof(transitions) / sizeof(transitions[0]))


static int s_nSceneIdx = 0;

TransitionScene* createTransition(int index, float t, Scene* s)
{

    Director::getInstance()->setDepthTest(false);

    return transitions[index].function(t,s);
}
因此,最后修改一下“go”函数,首先,我们下面的语句:
director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
替换成:
//director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
s_nSceneIdx++;
s_nSceneIdx = s_nSceneIdx % MAX_LAYER;
Director::getInstance()->replaceScene(
                    createTransition(s_nSceneIdx, TRANSITION_DURATION, newScene));
最终SceneManger的go函数看起来如下所示:
void SceneManager::go(Layer* layer)
{
    Director *director = Director::getInstance();
    Scene *newScene = SceneManager::wrap(layer);

    if ( director->getRunningScene() )
    {
        //director->replaceScene(TransitionFade::create(1.2f, newScene, Color3B::WHITE));
        s_nSceneIdx++;
        s_nSceneIdx = s_nSceneIdx % MAX_LAYER;
        Director::getInstance()->replaceScene(
                           createTransition(s_nSceneIdx, TRANSITION_DURATION, newScene));
    }
    else
    {
        director->runWithScene(newScene);
    }
}
很酷,对吧? 好像这个教程还不够,我们还可以调加更多的效果。。。最后,我还想在菜单文本上面添加一些效果。为了实现这个,我们需要修改MenuLayer.cpp文件。   首先,我们先把titleLeft和titleRight Label从下面的代码:
titleLeft->setPosition(
    Point( (visibleSize.width - tileWidth)/2,
            titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40) );
this->addChild(titleLeft);

titleRight->setPosition(
    Point( (visibleSize.width - tileWidth)/2 + titleLeft->getContentSize().width + 50,
        titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40) );
this->addChild(titleRight);
改成下面的代码:
auto titleLeftPosBegin = Point((visibleSize.width - tileWidth)/2,
    titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40 - 400);
auto titleLeftPosEnd = Point((visibleSize.width - tileWidth)/2,
    titleCenterTop->getPosition().y - titleLeft->getContentSize().height - 40 );
auto titleRightPosBegin = Point(
    (visibleSize.width - tileWidth)/2 + titleLeft->getContentSize().width + 50,
    titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40 + 400);
auto titleRightPosEnd = Point(
    (visibleSize.width - tileWidth)/2+titleLeft->getContentSize().width + 50,
    titleCenterTop->getPosition().y - titleRight->getContentSize().height - 40);

titleLeft->setPosition(titleLeftPos);
this->addChild(titleLeft);

titleRight->setPosition(titleRightPos);
this->addChild(titleRight);
注意:原教程直接写的坐标数字,但是由于我改编时使用的分辨率跟原教程不同,所以之前的坐标没法用。于是我自己使用的相对坐标定位,这样造成代码有点长,于是在这里把需要的坐标特地用titleRightPosEnd,titleRightPosBegin等提取出来。这里由于title初始坐标改变了,依赖title初始坐标的菜单错位,如titleCenterBottom就应该变成依赖title的目的地坐标。titleCenterBottom的设置Position代码变为:
titleCenterBottom->setPosition(
    Point( (visibleSize.width - titleCenterBottom->getContentSize().width)/2,
    titleRightPosEnd.y - titleCenterBottom->getContentSize().height - 40) );
接着,在init函数开始时声明float delayTime = 0.3f,然后在菜单项设定Position之后的位置为菜单项添加一个动画:
Action *titleLeftAction = Sequence::create(
    DelayTime::create(delayTime),
    EaseBackOut::create(MoveTo::create(1.0, titleLeftPosEnd)),
    NULL);
oh!我的天,这在干嘛啊! 创建一个Action对象,它由于系列的事件组成。 这个事件序列首先等待0.3秒,然后移动到 titleLeftPosEnd 的位置,时间间隔为1秒,同时用EaseBackOut修饰了,所以是先快后慢。 一旦我们创建了这个动作序列之后,我们运行这个action。
titleLeft->runAction(titleLeftAction);
我们同时要为titleRight添加类似的行为。 最后的动画就是Menu本身:
for (Node *each : menu->getChildren())
{
    each->setScale(0.0f, 0.0f);
    Action *action = Sequence::create(DelayTime::create(delayTime),
                                        ScaleTo::create(0.5f, 1.0f),
                                        NULL);
    delayTime += 0.2f;
    each->runAction(action);
}
你可以讲讲上面的代码是干嘛用的吗?我们又创建了一个“Action”变量,先停0.3秒,然后0.5秒缩放到1.0。因为我们开始之前把scale设置为0,这样就可以在0.5秒的时间内,慢慢放大到100%的尺寸。让我们运行一下代码,体验一下吧! 原文链接:http://www.iphonegametutorials.com/2010/09/07/cocos2d-menu-tutorial-part-2/ 现在,我们已经在菜单上面做了大量文章了。可能你会问,我们还能干嘛?耐心点,我的朋友!今天我们将接触menu item的图片。很期待吧?呵呵 老实说,如果你没有图片资源,你啥事也做不好。你真的需要一些教程来教你如果为菜单定制图片,这也是这篇教程的来由。 这里有本教程的完整源代码。 好了,我们这次要完成哪些内容呢---下面是今天的日程表:
  1. 为所有已经存在的Layer添加一个BaseLayer作为背景。
  2. 给“Start Game”和“Credits”按钮添加“on”和“off”状态。也就是normal状态和selected状态。
好,让我们开始吧! 我们将在上一篇教程的基础上完成工作,所以确保你有上一个教程的工程。首先,创建一个“BaseLayer”.h和.cpp文件,现在这个对你来说是小菜一碟了。但是,可别太得意哈,记住在“Classes”分组上面右击,选择”New Fild“。 一旦加好之后,首先打开BaseLayer.h:
#include "cocos2d.h"

class BaseLayer : public cocos2d::Layer
{
public:
    BaseLayer();
    ~BaseLayer();
    bool init();

    CREATE_FUNC(BaseLayer);
};
然后修改BaseLayer.cpp文件:
#include "BaseLayer.h"
USING_NS_CC;

BaseLayer::BaseLayer()
{
}

BaseLayer::~BaseLayer()
{
}

bool BaseLayer::init()
{
    if (!Layer::init())
    {
        return false;
    }

    Size visibleSize = Director::getInstance()->getVisibleSize();

    Sprite *bg = Sprite::create("backgroud.png");
    bg->setPosition(Point(visibleSize.width/2, visibleSize.height/2));
    this->addChild(bg, 0);

    return true;
}
你可能看到了,这里用了“background.png”来创建精灵,所以,为了保证代码能够工作,你需要把这个背景图片添加到工程里面来。右击“Resources”分组,然后选择“Add File To...”如下图所示: 然后从弹出的对话框里选择你需要的png文件,同时复选上“Copy items into destination group‘s folder (if needed)”选项,确保那个文件不在Resources目录下面时会被拷贝过来。 然后,我们在每个Layer中导入BaseLayer。 MenuLayer.h:
#include "BaseLayer.h"
class MenuLayer : public BaseLayer
PlayLayer.h:
#include "BaseLayer.h"
class PlayLayer : public BaseLayer
CreditLayer.h:
#include "BaseLayer.h"
class CreditLayer : public BaseLayer
同时修改这三个Layer的init函数里的返回false的那里,把Layer
if ( !BaseLayer::init() )
{
    return false;
}
在你完成之后,你将会看到每一层的背景显示下面的图片:(Credits,Menu和Play屏幕) 好,现在我们有背景了,那么菜单按钮呢? 我们首先需要创建它们,你可以使用Photoshop或者Fireworks去完成,但是,今天来说,这种方式有点过时了。今天,我将向大家介绍一个在线创建按钮图片的工具: Button Generator 我使用上面的站点创建了四个图片了。每个菜单项对应两张图片:(对应两种状态) newGameBtn.png newGameBtn_over.png creditsBtn.png creditsBtn_over.png 一种状态是按钮空闲时候显示的图片,另一种状态是用户按住菜单项的状态。我们会把这4张图片全部添加到Resource文件夹中,和之间添加background.png图片一样。 因此,我们项目中有图片了,接下来呢? 首先,找到MenuLayer.cpp文件,把startNew从文本形式,改成图片形式:
//MenuItemFont *startNew = MenuItemFont::create("New Game",                                     CC_CALLBACK_1(MenuLayer::onNewGame, this));
MenuItemImage *startNew = MenuItemImage::create("newGameBtn.png", 
                                                "newGameBtn_over.png",                                              "newGameBtn.png", 
                                    CC_CALLBACK_1(MenuLayer::onNewGame, this));
//MenuItemFont *credits = MenuItemFont::create("Credits",                                   CC_CALLBACK_1(MenuLayer::onCredits, this));
MenuItemImage *credits = MenuItemImage::create("creditsBtn.png", 
                                                "creditsBtn_over.png", 
                                                "creditsBtn.png",
                                    CC_CALLBACK_1(MenuLayer::onCredits, this));
disabledImage是可选的,如果你有一个disabled图片就更好了,但是这里为了教学展示,姑且这样使用。 现在,编译并运行代码,玩一玩吧!:) 原文链接:http://www.iphonegametutorials.com/2010/09/07/cocos2d-menu-tutorial-part-3/