《Cocos2D-x权威指南》——3.4 布景层类

简介: 本节书摘来自华章计算机《Cocos2D-x权威指南》一书中的第3章,第3.4节,作者:满硕泉著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.4 布景层类

布景层类CCLayer是CCNode类的子类,并且在此基础上实现触屏事件代理(TouchEventsDelegate)协议,可以实现CCNode类的功能,并且可以处理输入,包括触屏和加速度传感器。
每个游戏场景中可以有很多层,每一层负责各自的任务,如专门负责显示地图的背景、专门负责显示敌人、专门负责机关和专门负责主角等;每一层上可以放置不同的元素,包括文本、精灵图片和菜单等。通过层与层之间的组合关系,就可以构成游戏显示的界面UI,游戏中等。当然为了看到每一层的东西,可把一些层设置为透明或半透明的,这样就可以看到不同布景层叠加到一起的效果了。CCLayer类的继承关系如图3-12所示。

image

由图3-12可以看出CCLayer类继承自CCNode类,并且CCLayer类还遵照触屏代理协议、加速度传感器代理协议、键盘时间代理协议等协议。除此之外,CCLayer类还有子类,如图3-13所示。

image

这些子类的功能如表3-8所示。
image

首先来看CCLayer类的使用,然后再来看主要的子类使用。
3.4.1 CCLayer类的函数
CCLayer类的主要函数如表3-9所示。
image

来看Cocos2D-x的HelloWorld项目中的HelloWorldScene.cpp文件,scene函数定义CCLayer类并把它加入场景中,如代码清单3-16所示。
代码清单3-16 scene函数定义CCLayer类并把它加入场景中

CCScene* HelloWorld::scene()
{
    //新建场景类实例
    CCScene *scene = CCScene::create();
    
    //定义布景层
    HelloWorld *layer = HelloWorld::create();

    //将布景层加入场景
    scene->addChild(layer);

    //返回场景类
    return scene;
}

CCLayer类的init函数在创建布景层时被调用,如代码清单3-17所示。
代码清单3-17 CCLayer类的init函数

bool HelloWorld::init()
{
    if ( !CCLayer::init() )
    {
        return false;
    }
    CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
                                        "CloseNormal.png",
                                        "CloseSelected.png",
                                        this,
    menu_selector(HelloWorld::menuCloseCallback) );
    pCloseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) );
    CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
    pMenu->setPosition( CCPointZero );
    this->addChild(pMenu, 1);
    CCLabelTTF* pLabel = CCLabelTTF::create("Hello World", "Arial", 24);
    CCSize size = CCDirector::sharedDirector()->getWinSize(); 
    pLabel->setPosition( ccp(size.width / 2, size.height - 50) );   
    this->addChild(pLabel, 1); 
    CCSprite* pSprite = CCSprite::create("HelloWorld.png"); 
    pSprite->setPosition( ccp(size.width/2, size.height/2) ); 
    this->addChild(pSprite, 0);
    
    return true;
}

本书将在后面介绍具体显示在层次上的对象,目前只需要了解在init函数中定义要显示的对象并把它作为子类加入场景中。另外,关于触屏、键盘、加速度传感器等输入,将在后面的章节介绍。本节后面将介绍CCLayer类的子类。
3.4.2 颜色布景层类CCLayerColor
颜色布景层类CCLayerColor是CCLayer类的子类,包含CCLayer类的特性,并且有两个拓展功能:可以为布景层增添颜色,以及设置不透明度。
首先看CCLayerColor类的定义初始化,如代码清单3-18所示。这段代码是tests项目下LayerTest.cpp文件中LayerTest1的onEnter函数。

代码清单3-18 CCLayerColor类的定义初始化

void LayerTest1::onEnter()
{
    LayerTest::onEnter();

    setTouchEnabled(true);
    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLayerColor* layer = CCLayerColor::create( ccc4(0xFF, 0x00, 0x00, 0x80), 200, 200); 
    
    layer->ignoreAnchorPointForPosition(false);
    layer->setPosition( CCPointMake(s.width/2, s.height/2) );
    addChild(layer, 1, kTagLayer);
}

create函数的第一个参数是颜色的ARGB值,使用ccc4定义,其中第一个参数是颜色a值,第二个参数是R值,第三个参数是G值,最后一个参数是B值。除此之外,create函数的后两个参数是布景层的宽和高。
另外,使用ignoreAnchorPointForPosition将忽略锚点置为false。由于默认设置是忽略锚点,也就是以左下角为锚点,可以让布景层考虑锚点的影响(关于锚点在之前已经介绍过),这时默认的锚点在中心。运行效果如图3-14所示。

image


另外,LayerTest.cpp文件中的LayerTest1的updateSize函数中,可以修改颜色布景层的大小,如代码清单3-19所示。
代码清单3-19 修改颜色布景层的大小
void LayerTest1::updateSize(CCPoint &touchLocation)
{    
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    
    CCSize newSize = CCSizeMake( fabs(touchLocation.x - s.width/2)*2, fabs(touchLocation.y - s.height/2)*2);
    
    CCLayerColor* l = (CCLayerColor*) getChildByTag(kTagLayer);

    l->setContentSize( newSize );
}

通过setContentSize可以设置颜色布景层的大小。对于CCLayerColor类来说,还有一个比较常用的函数setBlendFunc,可以让布景层的颜色产生渐变效果。比如,需要在整屏添加全屏的一些覆盖效果、全屏变黑或者全屏变暗时,都可以使用这个方法。代码清单3-20所示是tests项目LayerTestBlend类中的newBlend函数,也就是使用setBlendFunc的示例。
代码清单3-20 使用setBlendFunc的示例

void LayerTestBlend::newBlend(float dt)
{
     CCLayerColor *layer = (CCLayerColor*)getChildByTag(kTagLayer);

    GLenum src;
    GLenum dst;

    if( layer->getBlendFunc().dst == GL_ZERO )
    {
        src = GL_SRC_ALPHA;
        dst = GL_ONE_MINUS_SRC_ALPHA;
    }
    else
    {
        src = GL_ONE_MINUS_DST_COLOR;
        dst = GL_ZERO;
    }

    ccBlendFunc bf = {src, dst};
    layer->setBlendFunc( bf );
}

传入的参数是一个有起始效果和结束效果的参数,运行之后的效果如图3-15和图3-16所示。
image

CCLayerColor类作为一个带颜色的布景层,在开发中可以给我们做特效带来方便。下一节介绍多层布景层类。
3.4.3 多层布景层类CCLayerMultiplex
在游戏开发中,一般会把游戏分为两部分:一部分是游戏界面部分,也就是常说的UI部分(User Interface,用户界面);另一部分就是游戏本身部分。有时UI有很多页面,在页面中用的图也并不是很多,不需要使用切换场景,只需把不同页面做成不同的布景层,然后切换布景层。那么这就需要一个“管理者”来管理这些界面,这时候就要使用CCLayerMultiplex类。
在很多游戏中都需要在不同的界面中使用相同的几个变量,如果不这样做,就需要做大量的保存工作。
tests项目中MenuTest.cpp的MenuTestScene类的runThisTest函数中有CCLayerMultiplex类的定义初始化方法,如代码清单3-21所示。
代码清单3-21 CCLayerMultiplex类的定义初始化

void MenuTestScene::runThisTest()
{
    CCLayer* pLayer1 = new MenuLayerMainMenu();
    CCLayer* pLayer2 = new MenuLayer2();
    CCLayer* pLayer3 = new MenuLayer3();
    CCLayer* pLayer4 = new MenuLayer4();
    CCLayer* pLayer5 = new MenuLayerPriorityTest();

    CCLayerMultiplex* layer = CCLayerMultiplex::create(pLayer1, pLayer2, pLayer3, pLayer4, pLayer5, NULL);
    addChild(layer, 0); 

    pLayer1->release();
    pLayer2->release();
    pLayer3->release();
    pLayer4->release();
    pLayer5->release();

    CCDirector::sharedDirector()->replaceScene(this);
}

首先定义并初始化每个布景层类,然后将这些布景层实例以参数形式传给CCLayerMultiplex的create函数,最后以NULL(空)结束。
这里在传入参数之后将这些布景层实例的指针释放,是为了防止内存泄露。至于Cocos2D-x的内存管理,本书将会在后面的章节介绍。
然后把CCLayerMultiplex实例作为子节点传入场景中,最后运行场景。代码清单3-22所示是切换布景层的switchTo函数使用方法。
代码清单3-22 switchTo函数使用方法

void MenuLayerPriorityTest::menuCallback(CCObject* pSender)
{
    ((CCLayerMultiplex*)m_pParent)->switchTo(0);
}

由于这个函数被CCLayerMultiplex实例的子布景,即初始化CCLayerMultiplex传入的布景类实例调用,所以它的m_pParent父节点就是CCLayerMultiplex实例本身。获得CCLayerMultiplex实例指针后,调用switchTo函数就可以转换到相应的子布景中。关于子布景中显示的菜单,下一节将会介绍。
3.4.4 菜单类CCMenu
游戏中常用的菜单如图3-17所示,其中菜单项可以是图片、系统字,或者自定义的字体。

image

CCMenu是一个菜单项的容器,用来装载各种菜单项。代码清单3-23就是一个定义CCMenu类实例的过程,是tests项目中MenuTest.cpp的MenuLayer2的构造函数。
代码清单3-23 定义CCMenu类实例

MenuLayer2::MenuLayer2()
{
    for( int i=0;i < 2;i++ ) 
    {
        CCMenuItemImage* item1 = CCMenuItemImage::create(s_PlayNormal, s_PlaySelect, this, menu_selector(MenuLayer2::menuCallback));
        CCMenuItemImage* item2 = CCMenuItemImage::create(s_HighNormal, s_HighSelect, this, menu_selector(MenuLayer2::menuCallbackOpacity) );
        CCMenuItemImage* item3 = CCMenuItemImage::create(s_AboutNormal, s_AboutSelect, this, menu_selector(MenuLayer2::menuCallbackAlign) );
        
        item1->setScaleX( 1.5f );
        item2->setScaleX( 0.5f );
        item3->setScaleX( 0.5f );
        
        CCMenu* menu = CCMenu::create(item1, item2, item3, NULL);
        
        CCSize s = CCDirector::sharedDirector()->getWinSize();
        menu->setPosition(ccp(s.width/2, s.height/2));
        menu->setTag( kTagMenu );
        
        addChild(menu, 0, 100+i);

        m_centeredMenu = menu->getPosition();
    }

    m_alignedH = true;
    alignMenusH();
}

首先定义菜单项(关于菜单项,本书会在后面的章节中做讲解),然后用它们定义初始化菜单CCMenu实例,最后将CCMenu实例加入CCLayer中显示出来,效果如图3-18所示。
菜单类还提供了alignItemsVertically和align-ItemsHorizontally等函数。如代码清单3-24所示,tests项目中MenuTest.cpp的MenuLayer2的构造函数alignMenusH就是alignItems-Horizontally水平对齐两种方法对比,一种是alignItems-Horizontally水平对齐,底下是alignItemsHorizontallyWithPadding留空间水平对齐,效果对比请见之前的图3-18。
代码清单3-24 对齐方法对比函数

void MenuLayer2::alignMenusH()
{
    for(int i=0;i<2;i++) 
    {
        CCMenu *menu = (CCMenu*)getChildByTag(100+i);
        menu->setPosition( m_centeredMenu );
        if(i==0) 
        {
            // TIP: if no padding, padding = 5
            menu->alignItemsHorizontally();            
            CCPoint p = menu->getPosition();
            menu->setPosition( ccpAdd(p, CCPointMake(0,30)) );
            
        } 
        else 
        {
            // TIP: but padding is configurable
            menu->alignItemsHorizontallyWithPadding(40);
            CCPoint p = menu->getPosition();
            menu->setPosition( ccpSub(p, CCPointMake(0,30)) );
        }        
    }
}

使用方法比较简单,直接调用就可以。下一节介绍Cocos2D-x中的UI控件。
3.4.5 控件类及其子类
在应用的开发中,无论是Android操作系统还是iOS操作系统,其开发框架都提供了控件,包括按键、拖动滑块等,这样提高了开发效率。对于游戏的开发,UI的开发同样需要控件来提高开发效率。对Cocos2D-x来说,从2.0版本开始提供了很多控件类来帮助我们更好地开发UI。
1 . 拖动滑块的控件类CCControlSlider
首先来看拖动滑块的控件类CCControlSlider。tests项目中ControlExtensionTestCCControl-SliderTest目录下CCControlSliderTest.cpp中的代码如代码清单3-25所示。
代码清单3-25 定义并初始化CCControlSliderTest类实例

bool CCControlSliderTest::init()
{
    if (CCControlScene::init())
    {
        CCSize screenSize = CCDirector::sharedDirector()->getWinSize();
        //定义标签的代码,考虑到篇幅而被省略
       ...
        //定义CCControlSlider
        CCControlSlider *slider = CCControlSlider::create("extensions/sliderTrack.png","extensions/sliderProgress.png" ,"extensions/sliderThumb.png");
        slider->setAnchorPoint(ccp(0.5f, 1.0f));
        slider->setMinimumValue(0.0f); // 设置范围最小值
        slider->setMaximumValue(5.0f); // 设置范围最大值
        slider->setPosition(ccp(screenSize.width / 2.0f, screenSize.height / 2.0f));
        //添加回调函数,当滑块被拖动时被调用
        slider->addTargetWithActionForControlEvents(this, cccontrol_selector(CCControlSliderTest::valueChanged), CCControlEventValueChanged);
        addChild(slider);    
        return true;
    }
    return false;
}
void CCControlSliderTest::valueChanged(CCObject *sender, CCControlEvent controlEvent)
{
    CCControlSlider* pSlider = (CCControlSlider*)sender;
m_pDisplayValueLabel->setString(CCString::createWithFormat("Slider value = %.02f", pSlider->getValue())->getCString());    
}

要定义拖动滑块对象,首先调用create函数,参数为图片路径,分别是滑块滑道图片路径、滑块滑动后覆盖滑道图片路径和滑块图片路径;之后设置锚点,并设置范围最小值和设置范围最大值,设置位置后给拖动注册拖动事件接受函数。在拖动事件中,可以通过pSlider->getValue())->getCString()来获取目前所在位置的值,运行效果如图3-19所示。

image


2 . 颜色选择盘类CCControlColourPicker
颜色选择盘类CCControlColourPicker的定义和初始化如代码清单3-26所示。代码在tests项目中ControlExtensionTest CCControl-ColourPickerTest目录下的CCControlColourPicker-Test.cpp文件中。
代码清单3-26 CCControlColourPicker类的定义和初始化
bool CCControlColourPickerTest::init()
{
    if (CCControlScene::init())
    {
        CCSize screenSize = CCDirector::sharedDirector()->getWinSize();

        CCNode *layer  = CCNode::create();
        layer->setPosition(ccp (screenSize.width / 2, screenSize.height / 2));
        addChild(layer, 1);

        double layer_width = 0;

        //定义并初始化颜色选择盘
        CCControlColourPicker *colourPicker = CCControlColourPicker::create();
        colourPicker->setColor(ccc3(37, 46, 252));
        colourPicker->setPosition(ccp (colourPicker->getContentSize().width / 2, 0));
        //添加到层次中
        layer->addChild(colourPicker);
        //注册事件
        colourPicker->addTargetWithActionForControlEvents(this, cccontrol_selector(CCControlColourPickerTest::colourValueChanged), CCControlEventValueChanged);
        //以下定义其他控件的代码省略
       ...
        return true;
    }
    return false;

}
void CCControlColourPickerTest::colourValueChanged(CCObject *sender, CCControlEvent controlEvent)
{
    CCControlColourPicker* pPicker = (CCControlColourPicker*)sender;
    m_pColorLabel->setString(CCString::createWithFormat("#%02X%02X%02X",pPicker->getColorValue().r, pPicker->getColorValue().g, pPicker->getColorValue().b)->getCString());
}

首先定义CCControlColourPicker,直接调用create函数就可以。这里需要把testsResourcesextensions目录下和CCControlColour-Picker相关的文件复制到Resourcesextensions目录,然后定义初始颜色,加入父节点中,并注册回调函数。回调函数通过pPicker->getColorValue().g, pPicker->getColorValue().b)->getCString()获得相应的颜色值字符串。运行效果如图3-20所示。

image


3 . 开关按钮类CCControlSwitch
开关按钮类CCControlSwitch的定义和初始化如代码清单3-27所示。代码在tests项目中的ControlExtensionTest CCControlSwitchTest目录下的CCControlSwitchTest.cpp中。
代码清单3-27 CCControlSwitch的定义和初始化
bool CCControlSwitchTest::init()
{
    if (CCControlScene::init())
    {
        //定义其他控件,代码省略
       ...
        // 定义开关控件
        CCControlSwitch *switchControl = CCControlSwitch::create
            (
                CCSprite::create("extensions/switch-mask.png"),
                CCSprite::create("extensions/switch-on.png"),
                CCSprite::create("extensions/switch-off.png"),
                CCSprite::create("extensions/switch-thumb.png"),
                CCLabelTTF::create("On", "Arial-BoldMT", 16),
                CCLabelTTF::create("Off", "Arial-BoldMT", 16)
            );
        switchControl->setPosition(ccp (layer_width + 10 + switchControl->getContentSize().width / 2, 0));
        layer->addChild(switchControl);
        switchControl->addTargetWithActionForControlEvents(this, cccontrol_selector(CCControlSwitchTest::valueChanged), CCControlEventValueChanged);
        //定义其他控件,代码省略
        ...
        return true;
    }
    return false;
}

要定义开关对象,首先调用create函数,参数为图片路径和上面的文字标签。图片路径分别是背景图片路径、开状态背景图片路径、关状态背景图片路径和开关背景图片路径,文字标签是开文字标签、关文字标签。设置位置加入布景层后定义回调函数。运行效果如图3-21所示。

image


4 . 按钮类CCControlButton
按钮类CCControlButton的定义和初始化如代码清单3-28所示。代码是tests项目中ControlExtensionTest CCControlButtonTest目录下CCControlButtonTest.cpp中的CCControlButtonTest_Event的init函数。
代码清单3-28 CCControlButton的定义和初始化
bool CCControlButtonTest_Event::init()
{
    if (CCControlScene::init())
    {
       //定义其他控件,代码省略
       ...
        //定义并初始化按钮
        CCControlButton *controlButton = CCControlButton::create(titleButton, backgroundButton);
        controlButton->setBackgroundSpriteForState(backgroundHighlightedButton, CCControlStateHighlighted);
        controlButton->setTitleColorForState(ccWHITE, CCControlStateHighlighted);
        
        controlButton->setAnchorPoint(ccp(0.5f, 1));
        controlButton->setPosition(ccp(screenSize.width / 2.0f, screenSize.height / 2.0f));
        addChild(controlButton, 1);
        //定义其他控件,代码省略
        ...
        //加入回调函数
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchDownAction), CCControlEventTouchDown);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchDragInsideAction), CCControlEventTouchDragInside);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchDragOutsideAction), CCControlEventTouchDragOutside);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchDragEnterAction), CCControlEventTouchDragEnter);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchDragExitAction), CCControlEventTouchDragExit);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchUpInsideAction), CCControlEventTouchUpInside);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchUpOutsideAction), CCControlEventTouchUpOutside);
        controlButton->addTargetWithActionForControlEvent(this, cccontrol_selector(CCControlButtonTest_Event::touchCancelAction), CCControlEventTouchCancel);
        return true;
    }
    return false;
}

要定义按钮对象,首先调用create函数。该函数传入的参数可以是图片的路径,也可以是精灵对象。两个参数代表的分别是按钮标题字和背景。之后可以设置按钮的参数,包括设置按钮位置和加入定义的回调函数等。这里的回调函数可以有多个,根据需要的操作定义,包括按下、拖动和抬起等。运行效果如图3-22所示。

image

本节介绍了Cocos2D-x的布景层类和它的子类,下节开始介绍精灵类及其子类。

相关文章
|
容器
《Cocos2D-x权威指南》——3.11 本章小结
本节书摘来自华章计算机《Cocos2D-x权威指南》一书中的第3章,第3.11节,作者:满硕泉著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
916 0
|
Android开发 C++ iOS开发
《Cocos2D-x权威指南》——2.5 本章小结
本节书摘来自华章计算机《Cocos2D-x权威指南》一书中的第2章,第2.5节,作者:满硕泉著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1165 0
《Cocos2D权威指南》——3.9 本章小结
本节书摘来自华章计算机《Cocos2D权威指南》一书中的第3章,第3.9节,作者:王寒,屈光辉,周雪彬著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1121 0
|
JavaScript 前端开发
《Cocos2D权威指南》——3.4 CCLayer层类
本节书摘来自华章计算机《Cocos2D权威指南》一书中的第3章,第3.4节,作者:王寒,屈光辉,周雪彬著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1356 0
|
JavaScript 前端开发
《Cocos2D权威指南》——2.6 最后的点缀
本节书摘来自华章计算机《Cocos2D权威指南》一书中的第2章,第2.6节,作者:王寒,屈光辉,周雪彬著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1083 0
|
iOS开发 开发者
《Cocos2D权威指南》——导读
从1976年在父母的车库中创业开始,乔布斯参与、开创并改变了几个行业—PC、电脑动画、数字音乐、移动互联网。他创办了苹果公司,中途又因某些原因被苹果驱逐。然而在苹果挣扎于濒死的边缘时,他又挺身而出将苹果救活,并把它推到无人可以企及的高度。
1031 0
|
移动开发 程序员 Android开发
《Cocos2D-x权威指南》——导读
现在,开始的好奇心和兴趣成就了我引以为豪的事业。在大四的时候,我到了天津猛犸实习,从J2ME平台到Android平台,从Android平台到iOS平台,我不仅接触了不同平台的开发,更学会了游戏开发的技巧和思想。如果说编程是一门艺术,那么游戏开发就是艺术中的艺术。
1396 0
《Cocos2D-x权威指南》——1.4 本章小结
本节书摘来自华章计算机《Cocos2D-x权威指南》一书中的第1章,第1.4节,作者:满硕泉著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1175 0
《Cocos2D权威指南》——2.7 本章小结
本节书摘来自华章计算机《Cocos2D权威指南》一书中的第2章,第2.7节,作者:王寒,屈光辉,周雪彬著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
912 0
|
测试技术
《Cocos2D权威指南》——1.6 本章小结
本节书摘来自华章计算机《Cocos2D权威指南》一书中的第1章,第1.6节,作者:王寒,屈光辉,周雪彬著, 更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1030 0