抄袭从游戏的第一个界面开始,如上图。
本文的代码已经提交 Github ,ccocos2d-x 的基础版本 fork 自其 2013.6.11 下午的版本。本项目直接做在 HelloCpp 的工程上,目前在 Windows 上开发,但我不会加系统 API ,保证跨平台性,当前分辨率设置为 320*480 ,以后适时再做到 iOS 上。
开始我完全不了解 cocos2d-x ,所以把 HelloCpp 和 TestCpp 工程跟了下,了解了它的运行流程,以及如何设置分辨率、组织场景、创建对象等等。
根据我看的这两个工程, cocos2d 的程序组织大致会是这样。
由于 c++ 的 cocos2d-x 是从 objective-c 的 cocos2d 移植来的,所以很多类名、函数名都来自于 Cocoa ,比如 AppDelegate, applicationDidFinishLaunching 等。
CCApplication 是最外层的一个对象,需要是全局唯一的。我们要继承它( AppDelegate )并在 main 函数中手动创建,以后使用 CCApplication::sharedApplication 获取到,也算是一个 Singleton 的实现。cocos2d 中有很多类似的全局唯一对象,比如 CCDirector, CCEGLView 等。有了 App 对象后,调用其 run 函数,程序就会进入消息循环。
在进入消息循环之前,程序会进入到 CCApplication::applicationDidFinishLaunching 函数进行应用程序的初始化,所以在子类 AppDelegate 中,我们重载这个函数,初始化我们自己的程序。在这个函数中,我们需要做的事情首先是为 GLView 设置分辨率,然后组织游戏场景。
CCDirector 负责对场景的管理,同时只能有一个 CCScene 在跑,如果插入一个新的 Scene,原来的 Scene 就会被挂起。Scene 可以看作是游戏的多个流程模块,比如主界面、游戏界面、剧情界面等。TestCpp 工程就是通过 Scene 来组织多个 Demo 程序,点击主界面里的 Menu 来切换。
Scene 下面可以有多个 CCLayer ,Layer 被用来组织多个 CCSprite , Sprite 就是游戏里的那些基本的元素,比如一个图片,一个 Label 。
下面来组织我们的第一个场景,主界面。
我复制了 HelloWorldScene.h/cpp 建了一个新的类 MainMenuScene ,修改它的 init 函数创建我们的主界面场景,包含一个背景图,一个 Logo 和底部的 Menu 。
// on "init" you need to initialize your instance
bool MainMenuScene::init()
{
//
// 1. super init first
if ( !CCLayer::init() )
{
return false ;
}
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
// add background
CCSprite* pSprite = CCSprite::create( "background@2x.png");
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
// add the sprite as a child to this layer
this->addChild(pSprite, 0);
// add dots' logo
CCSprite* pLogo = CCSprite::create( "dots_logo@2x.png");
pLogo->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height + origin.y + pLogo->getContentSize().height));
this->addChild(pLogo, 0);
// logo's action
CCPoint ptLogoFinal = ccp(visibleSize.width/2 + origin.x, visibleSize.height * 3 / 4 + origin.y);
CCPoint ptLogoMiddle = ccp(visibleSize.width/2 + origin.x, visibleSize.height * 2 / 3 + origin.y);
CCActionInterval* action1 = CCMoveTo::create(0.5f, ptLogoMiddle);
CCActionInterval* action2 = CCMoveBy::create(0.2f, ccp(0, 50));
CCActionInterval* action3 = CCMoveBy::create(0.2f, ccp(0, -25));
CCActionInterval* action4 = CCMoveBy::create(0.2f, ccp(0, 12));
CCActionInterval* action5 = CCMoveBy::create(0.2f, ccp(0, -7));
// run logo's action
pLogo->runAction( CCSequence::create(action1, action2, action3, action4, action5, NULL));
// dots menu
m_pItemMenu = CCMenu::create();
for (int i = 0; i < MENU_COUNT; ++i)
{
CCLabelTTF* label = CCLabelTTF::create(g_aMenuNames[i].c_str(), "fonts/Josefin Sans Bold.ttf", 12);
label->setColor(ccBLACK);
aaMenuItemLabel* pMenuItem = new aaMenuItemLabel();
pMenuItem->initWithLabel(label, this, menu_selector(MainMenuScene::menuCallback));
pMenuItem->autorelease();
m_pItemMenu->addChild(pMenuItem, i + 10000);
pMenuItem->setPosition( ccp( 0, (- i * LINE_SPACE) ));
}
m_pItemMenu->setPosition(ccp(visibleSize.width/2 + origin.x, origin.y+50));
this->addChild(m_pItemMenu, 0);
return true ;
}
Action 部分是动画,留待下一篇专门来讲。背景和 Logo 就是一个图片 Sprite ,Menu 本身是一个 Layer,里面由多个菜单项组成。由于 CCMenuItemLabel 提供的点击动画(文字放大)不是我们想要的(Dots 的会变成青绿色),所以我做了一个 aaMenuItemLabel 继承于它,重新实现它的 selected 和 unselected 函数。
场景创建完后,把 AppDelegate::applicationDidFinishLaunching 里调用 HelloWorldScene 的地方改成 MainMenuScene 就能显示出主场景了。因为上面加了 Action ,所以你会看到 Dots 中 Logo 掉下来弹跳的样子。当然不如原版的动画好,我们后面再来想办法调。
初涉 cocos2d-x 我遇到的最大的麻烦其实是分辨率和坐标的问题。要把这个说清楚可是个大工程,我先偷个懒,后面再写。如果你也遇到这样的问题,推荐看看这篇文章《Cocos2d-x 屏幕适配新解》