• Cocos2d-x 点击菜单按键居中放大(无需修改底层代码)


    建议转至该处阅读 https://www.zybuluo.com/tangyikejun/note/21953

    配置环境:win7+Cocos2d-x.2.0.3+VS2012
    目标读者:已经了解Cocos2d-x中的坐标系统,精灵和图片的关系。并知道OOP中类和对象的关系。

     

    目标

    实现一个按键效果,按下去之前显示normal.png的图,按下去之后显示selected.png的图。selected.png尺寸大于normal.png。效果图如下:

    效果图

     

    正文

     

    1、原始效果

    笔者在这个问题上纠结了一天半,尝试了各种方法,一直以为是自己错误使用菜单类导致不能居中放大。之后查看了源码,源码用两个精灵保存前后两张图片,并设置其锚点为(0,0),因此按键前后的图片都是以左下角点为原点绘制,无法到达居中放大的效果。

    默认绘制效果图

     

    2、类间关系

    我们先罗列出绘制一个按键所涉及的类,CCMenu、CCMenuItemSprite、CCSprite。它们在结点树上依次是爷爷、父亲、儿子的关系,当然你也可以认为是外婆、母亲、女儿的关系,随便。上述三个类中,CCMenu和CCSprite的锚点坐标都是(0,0),CCMenuItemSprite的锚点为(0.5,0.5),不建议更改这一默认设置。默认设定CCMenuItemSprite的大小和CCSprite的大小一致。当你没有抚摸屏幕的时候界面是这样的:

    无按键时类间布局关系;

    在这个图中,只对CCMenuItemSprite的位置进行了设置,其他对象的位置都是默认值。可以看到CCMenu对象的默认位置(position)为(0,0)。CCSprite的位置与CCMenuItemSprite的位置一致,即CCSprite的位置默认也是(0,0)。

     

    3、解决方案

    接下来我们通过实际的例子来讨论,本例中一些类和对象的关系如下表:

    对象对应图片
    CCSprite pNormalSprite normal.png
    CCSprite pSelectedSprite selected.png
    CCMenuItemSprite pCloseItem

    现在我们只把注意力放在CCMenuItemSprite和CCSprite这两个类上。对于本例,pNormalSprite和pSelectedSprite两个对象的默认锚点和位置均为(0,0),也就是说均以pCloseItem的左下角点作为原点。为了达到中心放大的目的,只需要重新设置pSelectedSprite的位置即可,见下图伪代码:

    第二张精灵位置计算

     

    4、实现

    具体的代码如下,直接在HelloWorld工程中的HelloWorld::init()函数中修改即可查看效果(当然要先把图放进去!)。

     
    //start//////////////////下面这些代码都是通用的///////////////
    
    /*新建按键前后两个精灵*/
    CCSprite *pNormalSprite = CCSprite::create("normal.png");
    CC_BREAK_IF(!pNormalSprite);
    
    CCSprite *pSelectedSprite = CCSprite::create("selected.png");
    CC_BREAK_IF(!pSelectedSprite);
    
    
    /*计算两张图片的dW,dH*/
    float dW = pNormalSprite->getContentSize().width
            - pSelectedSprite->getContentSize().width;
    float dH = pNormalSprite->getContentSize().height
            - pSelectedSprite->getContentSize().height;
            
            
    /*设置pSelectedSprite的位置*/        
    pSelectedSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));
    
    
    /*把精灵添加到菜单项pCloseItem中*/
    CCMenuItemSprite *pCloseItem = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(HelloWorld::menuCloseCallback));
    CC_BREAK_IF(!pCloseItem);
    //end////////////////////////////////////////////////////////
    
    /*设置菜单项的位置。*/
    pCloseItem->setPosition(ccp(100,100));
    
    /*添加菜单项到菜单*/
    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);

    5、更进一步

    上述代码虽然解决了中心放大的问题,但是仍存在一些缺陷。Cocos2d-x引擎处理后,pCloseItem对象的尺寸(content size)与pNormalSprite的尺寸是一样大的。即pSelected的尺寸 大于 pCloseItem对象的尺寸。当我们需要根据菜单项的大小来确定位置的时候,上面这种设置就会出现问题,比如我想把菜单项放在屏幕的左下角,如果直接将位置设置为

    pCloseItem->setPosition(ccp(w/2,h/2));//w,h分别是从pCloseItem获得的宽和高

    那么菜单项被按下后selected图片会超出屏幕。
    要解决这个问题需要两个步骤:
    1、pSelectedSprite保持默认位置,而对pNormalSprite的位置进行设置。
    2、将pCloseItem对象的尺寸设置为pSelectedSprite的尺寸。

    例子:

    CCSprite *pNormalSprite = CCSprite::create(path);       //path为图片路径
    CCSprite *pSelectedSprite = CCSprite::create(path);
    
    //得到dW和dH
    float dW = pSelectedSprite->getContentSize().width - pNormalSprite->getContentSize().width; 
    float dH = pSelectedSprite->getContentSize().height - pNormalSprite->getContentSize().height;
    
    //更改位置
    pNormalSprite->setPosition(ccp(dW / 2.0f,dH / 2.0f));
    
    //将菜单项的contentSize设置为selectedSprite对象的大小
    CCMenuItemSprite *pItemSprite = CCMenuItemSprite::create(pNormalSprite,pSelectedSprite,this,menu_selector(MainScene::onMenuEnd));
    
    CCSize size = pSelectedSprite->getContentSize();
    pItemSprite->setContentSize(size);

    本文疏漏错误之处,欢迎大家指正!从而对博文不断改进,更好地为大家服务!

    转载请注明出处:

    http://www.cnblogs.com/tangyikejun/p/3842000.html 

    https://www.zybuluo.com/tangyikejun/note/21953




    知识共享许可协议
    作者:tangyikejun
    本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

  • 相关阅读:
    2022商汤科技Java面试题、面试经验汇总
    2022拼多多Java面试题汇总
    程序员HR面,最常问的问题有哪些、汇总含答案
    Windows 下安装ES 和 Kibana ,以及配置Kibana 和ES的链接(最新版本:8.1.2)
    博图VBS连接SQLServer
    ping某个范围的IP地址
    C# 多点最小二乘法拟合平面算法
    博图VBS修改SQLServer数据
    Python|Mac——依据摄像头检测的方式去实现“防窥屏”
    连接MySQL失败,errorNo=2002,Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)
  • 原文地址:https://www.cnblogs.com/tangyikejun/p/3842000.html
Copyright © 2020-2023  润新知