【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

时间:2023-03-08 18:46:23

本系列学习教程使用的是cocos2d-x-2.1.4版本(截至目前为止最新稳定版) ,PC开发环境Windows7,C++开发环境VS2010

图层也是渲染框架中很重要的内容。场景类用来划分游戏的状态,图层就用来划分游戏画面。通常图层的尺寸

会与屏幕的尺寸一致。它将会覆盖整个显示名目。所以所图层几乎包含了所有游戏内容。相比场景类,它为玩家呈现

了丰富的游戏画面。每个游戏场景中可以有很多层,每一层负责各自的任务,如专门负责显示地图的背景、专门负责

显示敌人、专门负责机关和专门负责主角等;每一层上可以放置不同的元素,包括文本、精灵图片和菜单等。通过层

与层之间的组合关系就可以构成游戏显示的界面UI,游戏中等。当然为了看到每一层的东西,可把一些层设置为透明

或半透明的,这样就可以看到不同布景层加到一起的效果了。

一、布景层类CCLayer

布景层类CCLayer是CCNode类的子类,并且在此基础上实现触屏事件代理(TouchEventsDelegate)协议,可以

实现CCNode类的功能,并且可以处理输入,包括触屏和加速传感器。 CCLayer类包含了三个功能。

<1> 接受用户操作,比如触屏、重力加速度计的信息。

<2> 作为游戏内容元素的容器,用于显示游戏画面、承载精灵类、字体文本等对象。

<3> 填充背景游戏背景颜色。

CCLayer类的继承关系如下图所示。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

由图可以看出CCLayer类继承自CCNode类,并且CCLayer类还遵照触屏代理协议、加速度传感器代理协议、键

盘时间代理协议等协议。除此之外,CCLayer类还有子类,如下图所示。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

这些子类的功能如下图所示。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

首先来看看CCLayer类的使用,然后再来看主要的子类的使用。

1、CCLayer类的主要函数如下图所示。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

2、CCLayer类的使用

新建一个Cocos2D-X的项目,然后在新建项目的HelloWorldScene.cpp文件中,scene函数定义CCLayer类并把它

加入场景中,代码如下所示。

CCScene* HelloWorld::scene()
{
// 新建场景类实例
CCScene * scene = CCScene::create(); //定义布景层
HelloWorld *layer = HelloWorld::create(); // 将布景层加入场景中
scene->addChild(layer); // 返回场景类
return scene;
}

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); // 得到尺寸大小
CCSize size = CCDirector::sharedDirector()->getWinSize(); // 创建图片精灵
CCSprite* pSprite = CCSprite::create("HelloWorld.png"); // 设置图片精灵的位置
pSprite->setPosition(ccp(size.width/2, size.height/2)); // 把图片精灵放置在图层中
this->addChild(pSprite, 0); return true;
}

我们会在后面学习具体显示在层次上的对象,目前只需要了解在init函数中定义要显示的对象并把它作为子类加入

场景中。另外,关于触屏、键盘、加速度传感器等输入,我们也会在后面学习到。接下来,让我们一起学习CCLayer

类的子类。

二、颜色布景层类(CCLayerColor

颜色布景层类CCLayerColor是CCLayer类的子类,包含CCLayer类的特性,并且有两个扩展功能:可以为布景层

增添颜色,以及设置不透明度。

我们新建一个Coco2D-X的项目,然后在看CCLayerColor类的定义初始化,如下代码所示。这段代码在下

HelloWorldScene.cpp文件中HelloWorld的init函数。

bool HelloWorld::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init()); // Create a "close" menu item with close icon, it's an auto release object.
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
CC_BREAK_IF(! pCloseItem); // Place the menu item bottom-right conner.
pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20)); // Create a menu with the "close" menu item, it's an auto release object.
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
CC_BREAK_IF(! pMenu); // Add the menu to HelloWorld layer as a child layer.
this->addChild(pMenu, 1); // Get window size and place the label upper.
CCSize size = CCDirector::sharedDirector()->getWinSize(); CCLayerColor* layer = CCLayerColor::create(ccc4(0xFF,0x00,0x00,0x80),200,200);
layer->ignoreAnchorPointForPosition(false);
layer->setPosition(CCPointMake(size.width/2,size.height/2));
addChild(layer,1); bRet = true;
} while (0); return bRet;
}

我们主要看的是这几句代码:

CCLayerColor* layer = CCLayerColor::create(ccc4(0xFF,0x00,0x00,0x80),200,200);
layer->ignoreAnchorPointForPosition(false);
layer->setPosition(CCPointMake(size.width/2,size.height/2));
addChild(layer,1);

create函数的第一个参数是颜色的ARGB值,使用ccc4定义,其中第一个参数是颜色A值,第二个参数是R值,第

三个参数是G值,最后一个参数是B值。除此之外,create函数后两个参数是布景层的宽和高。
      另外,使用ignoreAnchorPointForPosition将忽略锚点置为false。由于默认设置是忽略锚点,也就是以左下角为锚

点,可以让布景层考虑锚点的影响(关于锚点在之前已经学习过),这时默认的锚点在中心。

运行效果图如下图所示。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

还有一个比较常用的函数setBlendFunc,可以让布景层的颜色产生渐变的效果。比如,需要在整屛添加全屏的一

些覆盖效果、全屏变黑或者全屏变暗时,都可以使用这个方法。下面让我们通过示例来学习这个函数的用法。

<1> 新建一个Coco2D-X的项目,我们取名为MyLayerBlend。首先在HelloWorldScene.h头文件中添加一个函数。

void newBlend(float dt);

<2> 然后在HelloWorldScene.cpp文件的init函数中修改如下所示代码。

bool HelloWorld::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init()); // Create a "close" menu item with close icon, it's an auto release object.
CCMenuItemImage *pCloseItem = CCMenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
this,
menu_selector(HelloWorld::menuCloseCallback));
CC_BREAK_IF(! pCloseItem); // Place the menu item bottom-right conner.
pCloseItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20)); // Create a menu with the "close" menu item, it's an auto release object.
CCMenu* pMenu = CCMenu::create(pCloseItem, NULL);
pMenu->setPosition(CCPointZero);
CC_BREAK_IF(! pMenu); // Add the menu to HelloWorld layer as a child layer.
this->addChild(pMenu); // Get window size and place the label upper.
CCSize size = CCDirector::sharedDirector()->getWinSize(); CCLayerColor* layer1 = CCLayerColor::create( ccc4(255, 255, 255, 80) ); CCSprite* sister1 = CCSprite::create("grossinis_sister1.png");
CCSprite* sister2 = CCSprite::create("grossinis_sister2.png"); addChild(sister1,1);
addChild(sister2,1);
addChild(layer1, 100,1); sister1->setPosition( ccp( size.width*1/3, size.height/2) );
sister2->setPosition( ccp( size.width*2/3, size.height/2) ); schedule( schedule_selector(HelloWorld::newBlend), 1.0f); bRet = true;
} while (0); return bRet;
}

这里用了一个定时器schedule来切换渐变的效果。

<3> 最后在newBlend函数中添加如下所示代码。

void HelloWorld::newBlend(float dt)
{
CCLayerColor *layer = (CCLayerColor*)getChildByTag(1); 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 );
}

传入的参数是一个有起始效果和结束效果的参数。

<4> 运行效果图。

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用

三、多层布景层类(CCLayerMultiplex

在游戏开发中,一般会把游戏分为两部分:一部分是游戏界面部分,也就是常说的UI部分;另一部分就是游戏本

身的部分。有时UI有很多页面,在页面中用的图也并不是很多,不需要使用切换场景,只需把不同页面做成不同的布

景层,然后切换布景层。那么这就需要一个“管理者”来管理这些界面,这时候就要使用CCLayerMultiplex类。

在很多游戏中都需要在不同的界面中使用相同的几个变量,如果不这样做,就需要做大量的保存工作。

在 tests项目中MenuTest.cpp的MenuTestScene类的runThisTest函数中有CCLayerMultiplex类的定义初始化方

法,如下代码所示。

void MenuTestScene::runThisTest()
{
CCLayer* pLayer1 = new MenuLayerMainMenu();
CCLayer* pLayer2 = new MenuLayer2();
CCLayer* pLayer3 = new MenuLayer3();
CCLayer* pLayer4 = new MenuLayer4();
CCLayer* pLayer5 = new MenuLayerPriorityTest();
CCLayer* pLayer6 = new BugsTest();
CCLayer* pLayer7 = new RemoveMenuItemWhenMove(); CCLayerMultiplex* layer = CCLayerMultiplex::create(pLayer1, pLayer2, pLayer3, pLayer4, pLayer5, pLayer6, pLayer7, NULL);
addChild(layer, 0); pLayer1->release();
pLayer2->release();
pLayer3->release();
pLayer4->release();
pLayer5->release();
pLayer6->release();
pLayer7->release(); CCDirector::sharedDirector()->replaceScene(this);
}

首先定义并初始化每个布景层类,然后将这些布景层实例以参数形式传给CCLayerMultiplex的create函数,最后以NULL(空)结束。

这里在传入参数之后将这些布景层实例的指针释放,是为了防止内存泄露。至于Cocos2D-X的内存管理,我们会

在后面学习到。

然后把CCLayerMultiplex实例作为子节点传入场景中,最后运行场景。如下代码所示是切换布景层的switchTo函数

使用方法。

void MenuLayerPriorityTest::menuCallback(CCObject* pSender)
{
((CCLayerMultiplex*)m_pParent)->switchTo(0);
// [[CCDirector sharedDirector] popScene];
}

由于这个函数被CCLayerMultiplex实例的子布景,即初始化CCLayerMultiplex传入的布景类实例调用,所以它的

m_pParent父节点就是CCLayerMultiplex实例本身。获得CCLayerMultiplex实例指针后,调用switchTo函数就可以转

换到相应的子布景中。

示例源码下载地址