cpp-tests Node::Layer及Node::Menu

来源:互联网 发布:淘宝产品怎么排名靠前 编辑:程序博客网 时间:2024/05/17 04:47

~~~~我的生活,我的点点滴滴!!



1、Layer层


Layer 游戏中的背景容器,Layer类是Node类的一个子类,它实现了触屏事件代理(TouchEventsDelegate)协议。

LayerColor是Layer的一个子类,它实现了RGBAProtocol协议。

LayerGradient是LayerColor的一个子类,它在背景上画渐变效果。 

LayerMultiplex类是一个能够使它的子类进行复用的布景层类。

Sprite精灵不能直接放入舞台中,它需要作为Layer的子节点,通过Layer加入舞台场景中显示。

cpp-tests例子中Node::Layer测试了很多Layer及其子类的作用与用法,比如递归设置Cascading与opacity来让在Layer层上面的精灵具有及相应的属

性等等,LayerMultiple类在MenuTest里面讲解,下面讲解一下渐变Layer即LayerGradient。

LayerGradient它实现了LayerColor类的所有功能,还添加了以下这些新功能:

1、渐变方向

2、渐变最终颜色

3、插值模式

颜色沿着给定的向量插在起始颜色和终止颜色之间(从起点开始,到终点结束)。如果没有提供向量,则默认到(0,-1)点一个从顶部到底部的淡入

淡出。

如果“compressedInterpolation”不可用,你将看不到非基本向量的起始颜色和终止颜色;不过无论如何,一个平滑的渐变  (包括终点)最终还是会

现出来。

 
如果“compressedInterpolation”是可用的(默认模式),你将看到渐变的起始颜色和终止颜色。


看下面代码:

LayerGradientTest::LayerGradientTest(){//渐变,第一个参数是起始颜色,第二个参数是终止颜色,第三个参数是渐变方向是通过与原点减来求矢量的;//这里(0.9f,0.9f)与(0,0)计算后的夹角是45度往x轴正方向,也就是向右;//如果没有第三个参数,则默认到(0,-1)一个从顶部到底部的淡入淡出;    auto layer1 = LayerGradient::create(Color4B(255,0,0,255), Color4B(0,255,0,255), Vec2(0.9f, 0.9f));    addChild(layer1, 0, kTagLayer);    auto listener = EventListenerTouchAllAtOnce::create();    listener->onTouchesMoved = CC_CALLBACK_2(LayerGradientTest::onTouchesMoved, this);    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);    auto label1 = Label::createWithTTF("Compressed Interpolation: Enabled", "fonts/Marker Felt.ttf", 26);    auto label2 = Label::createWithTTF("Compressed Interpolation: Disabled", "fonts/Marker Felt.ttf", 26);    auto item1 = MenuItemLabel::create(label1);    auto item2 = MenuItemLabel::create(label2);//设置一个toggle开关,来演示Compressed,本人目测效果不明显;    auto item = MenuItemToggle::createWithCallback( CC_CALLBACK_1(LayerGradientTest::toggleItem, this), item1, item2, nullptr);    auto menu = Menu::create(item, nullptr);    addChild(menu);    auto s = Director::getInstance()->getWinSize();    menu->setPosition(Vec2(s.width / 2, 100));}void LayerGradientTest::toggleItem(Ref *sender){    auto gradient = static_cast<LayerGradient*>( getChildByTag(kTagLayer) );    gradient->setCompressedInterpolation(! gradient->isCompressedInterpolation());}void LayerGradientTest::onTouchesMoved(const std::vector<Touch*>& touches, Event *event){    auto s = Director::getInstance()->getWinSize();    auto touch = touches[0];    auto start = touch->getLocation();        auto diff =  Vec2(s.width/2,s.height/2) - start;    diff = diff.getNormalized();    auto gradient = static_cast<LayerGradient*>( getChildByTag(1) );//设置一个移动矢量方向    gradient->setVector(diff);}

上面代码会产生一个从左下角红色慢慢变到右上角绿色的Layer层,当鼠标点击移动后,根顺着鼠标移动方向切换渐变颜色位置。


效果图:




2、Menu菜单


菜单按钮有好多了,像MenuItemSprite、MenuItemFont、MenuItemLabel、MenuItemImage、MenuItemToggle等等,都是大同小异,直接看后缀也大概

知道分别代表什么意思,怎么使用了。

下面代码列出了上面的使用方法:


MenuLayerMainMenu::MenuLayerMainMenu(){    _touchListener = EventListenerTouchOneByOne::create();    _touchListener->setSwallowTouches(true);    _touchListener->onTouchBegan = CC_CALLBACK_2(MenuLayerMainMenu::onTouchBegan, this);    _touchListener->onTouchMoved = CC_CALLBACK_2(MenuLayerMainMenu::onTouchMoved, this);    _touchListener->onTouchEnded = CC_CALLBACK_2(MenuLayerMainMenu::onTouchEnded, this);    _touchListener->onTouchCancelled = CC_CALLBACK_2(MenuLayerMainMenu::onTouchCancelled, this);    //注意这里使用的是FixedPriority而不是SceneGraphPriority;//FixedPriority会依据手动设置的值的顺序来决定触摸的优先级,但是不能为0;//0已经留给scene了    _eventDispatcher->addEventListenerWithFixedPriority(_touchListener, 1);    // Font Item    // 这里其实是一张图片有三个等分小图片,通过计算其位置来获得图片,plist文件里面其实也是这样的;// 这里的Rect值算的有问题,x,y坐标要缩小一倍,width与height也要缩小一倍;// 要不然显示出来的就是一个空白黄色立方形;    auto spriteNormal = Sprite::create(s_MenuItem, Rect(0,23*0.5*2,115*0.5,23*0.5));    auto spriteSelected = Sprite::create(s_MenuItem, Rect(0,23*0.5*1,115*0.5,23*0.5));    auto spriteDisabled = Sprite::create(s_MenuItem, Rect(0,23*0.5*0,115*0.5,23*0.5));    auto item1 = MenuItemSprite::create(spriteNormal, spriteSelected, spriteDisabled  , CC_CALLBACK_1(MenuLayerMainMenu::menuCallback, this) );    // Image Item    auto item2 = MenuItemImage::create(s_SendScore, s_PressSendScore, CC_CALLBACK_1(MenuLayerMainMenu::menuCallback2, this) );    // Label Item (LabelAtlas)    auto labelAtlas = LabelAtlas::create("0123456789", "fonts/labelatlas.png", 16, 24, '.');    auto item3 = MenuItemLabel::create(labelAtlas, CC_CALLBACK_1(MenuLayerMainMenu::menuCallbackDisabled, this) );    /*设置一层覆盖颜色,上一行代码给item3设置了一个触摸回调函数,后面代码;_disabledItem = item3; item3->retain();    _disabledItem->setEnabled( false );把_disabledItem指向item3并且设置setEnabled为false让其不可用状态;这样相当于在item3上面覆盖一层,这样触摸就可控制了;为什么不直接使用item3????;;;;*/item3->setDisabledColor( Color3B(232,0,0) );//设置字体颜色;    item3->setColor( Color3B(200,200,255) );        // Font Item    auto item4 = MenuItemFont::create("I toggle enable items", [&](Ref *sender) {    //设置是否可用;_disabledItem->setEnabled(! _disabledItem->isEnabled() );//此处能不能直接用item3了????????;//当然可以呀,但是需要把item3设置为成员变量,这样在lambda表达式中就能捕获到;//item3->setEnabled( !item3->isEnabled() );});    item4->setFontSizeObj(20);    item4->setFontName("fonts/Marker Felt.ttf");        // Label Item (LabelBMFont)    auto label = Label::createWithBMFont("fonts/bitmapFontTest3.fnt", "configuration");    auto item5 = MenuItemLabel::create(label, CC_CALLBACK_1(MenuLayerMainMenu::menuCallbackConfig, this));    // Testing issue #500    item5->setScale( 0.8f );    // Events    MenuItemFont::setFontName("fonts/Marker Felt.ttf");    // Bugs Item    auto item6 = MenuItemFont::create("Bugs", CC_CALLBACK_1(MenuLayerMainMenu::menuCallbackBugsTest, this));    // Font Item    auto item7= MenuItemFont::create("Quit", CC_CALLBACK_1(MenuLayerMainMenu::onQuit, this));        auto item8 = MenuItemFont::create("Remove menu item when moving", CC_CALLBACK_1(MenuLayerMainMenu::menuMovingCallback, this));    //设置item7 "Quit"一闪一闪效果;    auto color_action = TintBy::create(0.5f, 0, -255, -255);    auto color_back = color_action->reverse();    auto seq = Sequence::create(color_action, color_back, nullptr);    item7->runAction(RepeatForever::create(seq));    auto menu = Menu::create( item1, item2, item3, item4, item5, item6, item7, item8,  nullptr);    menu->alignItemsVertically();        //设置出场时动态效果;    // elastic effect    auto s = Director::getInstance()->getWinSize();        int i=0;    for(const auto &child : menu->getChildren()) {//这里得到的是相应Menu的位置,其值是很小的,x轴基本上都是0,y轴从正到负(竖直排列从上往下);        auto dstPoint = child->getPosition();        int offset = (int) (s.width/2 + 50);        if( i % 2 == 0)            offset = -offset;                child->setPosition( Vec2( dstPoint.x + offset, dstPoint.y) );//EaseElasticOut效果        child->runAction(                         EaseElasticOut::create(MoveBy::create(2, Vec2(dstPoint.x - offset,0)), 0.35f)                         );        i++;    }    _disabledItem = item3; item3->retain();    _disabledItem->setEnabled( false );    addChild(menu);    menu->setPosition(Vec2(s.width/2, s.height/2));    menu->setScale(0);//效果图从右上角出来时特别小,然后慢慢变大,通过ScaleTo实现这样就造成了从远到近的效果;    menu->runAction(ScaleTo::create(1,1));}bool MenuLayerMainMenu::onTouchBegan(Touch *touch, Event * event){    return true;}void MenuLayerMainMenu::onTouchEnded(Touch *touch, Event * event){}void MenuLayerMainMenu::onTouchCancelled(Touch *touch, Event * event){}void MenuLayerMainMenu::onTouchMoved(Touch *touch, Event * event){}MenuLayerMainMenu::~MenuLayerMainMenu(){//FixedPriority需要手动释放监听    _eventDispatcher->removeEventListener(_touchListener);    _disabledItem->release();}void MenuLayerMainMenu::menuCallback(Ref* sender){//LayerMultiplex是一个能够使它的子类进行复用的布景层类;//它支持一个或多个子类,但是一次仅能激活一个孩子;//下标从0开始;    static_cast<LayerMultiplex*>(_parent)->switchTo(1);}void MenuLayerMainMenu::menuCallbackConfig(Ref* sender){    static_cast<LayerMultiplex*>(_parent)->switchTo(3);}void MenuLayerMainMenu::allowTouches(float dt){//还原;    _eventDispatcher->setPriority(_touchListener, 1);//取消了所有定时器,不过对Actions的动作特效没有影响;//这里其实只要取消那个5s的定时器就好了;    unscheduleAllSelectors();    log("TOUCHES ALLOWED AGAIN");}void MenuLayerMainMenu::menuCallbackDisabled(Ref* sender) {    // hijack all touch events for 5 seconds//当前的zorder是0,这里设置成-1,他的优先级高;//所以这个时候_touchListener的四个函数touchBegan、touchMoved、TouchEnded、TouchCancelled优先被触发;//而这四个函数里面什么也没有干,只是把touchBegan返回true(一定要返回true不然就会往下传递了,因为我们设置了setSwallowTouches(true));//这样就形成了一个天然的触摸屏蔽了;    _eventDispatcher->setPriority(_touchListener, -1);//5秒过后,在allowTouches()回调里面在设置回来了;    schedule(schedule_selector(MenuLayerMainMenu::allowTouches), 5.0f);    log("TOUCHES DISABLED FOR 5 SECONDS");}

看上面的注释,我们能知道怎么屏蔽触摸穿透,怎么又能恢复触摸事件,并且也展示了MenuItem的各种使用方法,大家在用的时候去看下源码接口就知

道怎么使用了,里面那个屏蔽触摸是5s内任务触摸无效,5s后就一切正常,场景出来的画面也很有意思。

效果图:




前面在讲Layer时我们说过LayerMultiplex 会在这里讲解,老实说这个类方法在切换layer时没有任何过渡效果,感觉有点鸡肋,但总还是有他的用处,喜

欢的就用,不喜欢的就不用,他是一个把多个layer层添加在一起的一个容器,他里面是互斥的一次只能激活(显示)一个layer,但是其他的layer里面设置

依然保存,也就是上一次是什么样子的,下一次切换回来时依然是那个样子。


下面看简单的代码:

void MenuTestScene::runThisTest(){    MenuItemFont::setFontSize(20);    //产生了各种layer层,然后在下面全添加到LayerMultiplex中存放。    auto layer1 = new MenuLayerMainMenu();    auto layer2 = new MenuLayer2();    auto layer3 = new MenuLayer3();    auto layer4 = new MenuLayer4();    auto layer5 = new BugsTest();    auto layer6 = new RemoveMenuItemWhenMove();/*在这里创建的LayerMultiplex;一个能够使它的子类进行复用的布景层类。 功能: 它支持一个或多个子类;一次仅能激活一个孩子;    */       auto layer = LayerMultiplex::create(layer1, layer2, layer3, layer4, layer5, layer6, nullptr);    addChild(layer, 0); //?????为什么要手动release    layer1->release();    layer2->release();    layer3->release();    layer4->release();    layer5->release();    layer6->release();    Director::getInstance()->replaceScene(this);}


这样加完后,中间很多代码像Lyaer2、Layer3、Layer4等代码这里都省略了,大家想看直接去cpp-tests例子下面MenuTest里面去看

效果图如下:




========================================================

当没有切换Layer层的时候,刚开始出来的Layer上"Quit"菜单是有动态效果的,一闪一闪的,但是只要切换一次,在切回来就不会闪了,

也就是说使用LayerMultiplex时会使用运动的actions停止,这只适合于静态layer层,感觉太鸡肋了吧。


========================================================



0 0