【Cocos2d-X开发学习笔记】第05期:渲染框架之布景层类(CCLayer)的使用
本系列学习教程使用的是cocos2d-x-2.1.4版本(截至目前为止最新稳定版) ,PC开发环境Windows7,C++开发环境VS2010
图层也是渲染框架中很重要的内容。场景类用来划分游戏的状态,图层就用来划分游戏画面。通常图层的尺寸
会与屏幕的尺寸一致。它将会覆盖整个显示名目。所以所图层几乎包含了所有游戏内容。相比场景类,它为玩家呈现
了丰富的游戏画面。每个游戏场景中可以有很多层,每一层负责各自的任务,如专门负责显示地图的背景、专门负责
显示敌人、专门负责机关和专门负责主角等;每一层上可以放置不同的元素,包括文本、精灵图片和菜单等。通过层
与层之间的组合关系就可以构成游戏显示的界面UI,游戏中等。当然为了看到每一层的东西,可把一些层设置为透明
或半透明的,这样就可以看到不同布景层加到一起的效果了。
一、布景层类(CCLayer)
布景层类CCLayer是CCNode类的子类,并且在此基础上实现触屏事件代理(TouchEventsDelegate)协议,可以
实现CCNode类的功能,并且可以处理输入,包括触屏和加速传感器。 CCLayer类包含了三个功能。
<1> 接受用户操作,比如触屏、重力加速度计的信息。
<2> 作为游戏内容元素的容器,用于显示游戏画面、承载精灵类、字体文本等对象。
<3> 填充背景游戏背景颜色。
CCLayer类的继承关系如下图所示。
由图可以看出CCLayer类继承自CCNode类,并且CCLayer类还遵照触屏代理协议、加速度传感器代理协议、键
盘时间代理协议等协议。除此之外,CCLayer类还有子类,如下图所示。
这些子类的功能如下图所示。
首先来看看CCLayer类的使用,然后再来看主要的子类的使用。
1、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。由于默认设置是忽略锚点,也就是以左下角为锚
点,可以让布景层考虑锚点的影响(关于锚点在之前已经学习过),这时默认的锚点在中心。
运行效果图如下图所示。
还有一个比较常用的函数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> 运行效果图。
三、多层布景层类(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函数就可以转
换到相应的子布景中。