cocos2dx-CCControlButton源码分析

CCControlButtton

CCMenu简介

CCControlButtton是按钮控件,由一个标签加背景图片构成。cocos的CCMenu以及提供了相应的控件功能,CCMenu同CCControlButtton一样派生于CCLayer,可以开启触摸。CCMenu的孩子CCMenuItem已经提供了简单的按钮功能了,可以由图片或者文字构建一个菜单项,CCMenu可以看成一个控件层,在上面布局子控件CCMenuItem。下面是CCMenu的应用代码:

CCLabelTTF *label = CCLabelTTF::create("CCSequence test", "Arial", 24);
CCMenuItemLabel *item = CCMenuItemLabel::create(label, this, menu_selector(ActionScene::menuAction1));
item->setPosition(ccp(320, 1100));
menu->addChild(item);

上面在创建的时候直接指定了目标与动作,其中动作部分是menu_selector(ActionScene::menuAction1),menu_selector的作用是取ActionScene::menuAction1函数指针并向上转型,这里ActionScene必须是CCObject子类。相关代码如下:

typedef void (CCObject::*SEL_MenuHandler)(CCObject*);
#define menu_selector(_SELECTOR) (SEL_MenuHandler)(&_SELECTOR)

SEL_MenuHandler是void CCObject::fun(CCObject*)类型函数指针。
这里指定菜单项是一个标签,可以使用CCMenuItemSprite、CCMenuItemImage创建带有图片的菜单项。

可以先创建好菜单项,然后再指定目标动作,代码如下:

CCMenuItemImage *img = CCMenuItemImage::create("reset.png", "reset.png");
img->setTarget(this, menu_selector(ActionScene::reset));
img->setPosition(ccp(50, 1000));
menu->addChild(img);

菜单项的触摸事件比较简单,只有touchdown这个事件,无法处理touchdown后的手指拖拽。CCMenu是cocos标准库中的内容,后来cocos引入了其他人对cocos的扩展,其中有一个是控件扩展,提供的控件挺多,其中有一个控件是CCControlButtton,它同CCMenuItem一样,可以有标签和图片,图片使用CCScale9Sprite,支持九宫格图片。除此之外,CControlButtton定义了更多的事件,这些事件如下:

事件 描述
CCControlEventTouchDown 开始触摸
CCControlEventTouchDragEnter 触摸后从控件外拖拽进来
CCControlEventTouchDragInside 触摸后在控件内拖拽
CCControlEventTouchDragExit 触摸后从控件里拖拽出来
CCControlEventTouchDragOutside 触摸后在控件外拖拽
CCControlEventTouchUpInside 触摸后在控件里触摸结束
CCControlEventTouchUpOutside 触摸后在控件外触摸结束

上面看出CCControlButtton对手势的事件支持挺多的,这里主要根据用户的手在不在控件里进行手势划分的。
接下来对CCControlButtton进行详细的分析,目的除了了解使用背后的原理,更是为了方便自定义一些控件,构造游戏中的控件库。

CCControlButtton代码分析

CCControlButtton的应用代码如下:

CCSpriteFrame *btnSf = CCSpriteFrame::create("ui.png", CCRectMake(760, 163, 64, 60));
CCScale9Sprite *btnS9 = CCScale9Sprite::createWithSpriteFrame(btnSf);
CCControlButton *btn = CCControlButton::create(btnS9);
btn->setPreferredSize(CCSizeMake(64, 64));
btn->setPosition(ccp(100, 50));
btn->addTargetWithActionForControlEvents(this, cccontrol_selector(TilemapTest::itemsBarClick), CCControlEventTouchDown);
this->addChild(btn);

上面的代码添加了一个CCControlButton,我使用了一张网上download下来的游戏资源图片创建了一个精灵帧(描述纹理以及纹理的使用范围),然后用此创建一个九宫格精灵,再用它创建CCControlButton,setPreferredSize目的是防止九宫格精灵被变形,这里只想保持纹理的默认大小。由于网上并没有提供图片中每个子图片的属性描述文件,所以只能手动测量子图片在大图片中的的纹理范围了,这里范围是CCRectMake(760, 163, 64, 60)。最终在场景中创建了一个物品按钮,图片如下:

上面是一个RPG小游戏,黑色区域是碰撞区,占时没有隐藏。图片左下角是加入的按钮
现在分析CCControlButton是如何创建的,以及如何响应用户触摸事件的。CCScale9Sprite::createWithSpriteFrame(btnSf)代码如下:

CCControlButton* CCControlButton::create(CCScale9Sprite* sprite)
{
    CCControlButton *pRet = new CCControlButton();  //创建CCControlButton
    pRet->initWithBackgroundSprite(sprite); //初始化
    pRet->autorelease();
    return pRet;
}

pRet->initWithBackgroundSprite(sprite);代码如下:

bool CCControlButton::initWithBackgroundSprite(CCScale9Sprite* sprite)
{
    CCLabelTTF *label = CCLabelTTF::create("", "Arial", 30); //创建标签
    return initWithLabelAndBackgroundSprite(label, sprite); //继续初始化
}

initWithLabelAndBackgroundSprite(label, sprite);代码如下:

bool CCControlButton::initWithLabelAndBackgroundSprite(CCNode* node, CCScale9Sprite* backgroundSprite)
{
    if (CCControl::init())
    {
        CCAssert(node != NULL, "Label must not be nil.");
        CCLabelProtocol* label = dynamic_cast<CCLabelProtocol*>(node);  //向上转型用于下面检查
        CCRGBAProtocol* rgbaLabel = dynamic_cast<CCRGBAProtocol*>(node); //向上转型用于下面检查
        CCAssert(backgroundSprite != NULL, "Background sprite must not be nil.");
        CCAssert(label != NULL || rgbaLabel!=NULL || backgroundSprite != NULL, "");

        m_bParentInited = true;

        // Initialize the button state tables
        this->setTitleDispatchTable(CCDictionary::create());  //用字典初始化4个表
        this->setTitleColorDispatchTable(CCDictionary::create());
        this->setTitleLabelDispatchTable(CCDictionary::create());
        this->setBackgroundSpriteDispatchTable(CCDictionary::create());

        setTouchEnabled(true); //开启触摸
        m_isPushed = false; //是否被按下
        m_zoomOnTouchDown = true; //按下时是否执行放大与缩小动作

        m_currentTitle=NULL; //标签内容为空

        // Adjust the background image by default
        setAdjustBackgroundImage(true); //调整背景图片
        setPreferredSize(CCSizeZero); //设置偏爱的大小
        // Zooming button by default
        m_zoomOnTouchDown = true;

        // Set the default anchor point
        ignoreAnchorPointForPosition(false);
        setAnchorPoint(ccp(0.5f, 0.5f));

        // Set the nodes
        setTitleLabel(node);
        setBackgroundSprite(backgroundSprite);

        // Set the default color and opacity
        setColor(ccc3(255.0f, 255.0f, 255.0f));
        setOpacity(255.0f);
        setOpacityModifyRGB(true);

        // Initialize the dispatch table

        CCString* tempString = CCString::create(label->getString());
        //tempString->autorelease();
        setTitleForState(tempString, CCControlStateNormal);
        setTitleColorForState(rgbaLabel->getColor(), CCControlStateNormal);
        setTitleLabelForState(node, CCControlStateNormal);
        setBackgroundSpriteForState(backgroundSprite, CCControlStateNormal);

        setLabelAnchorPoint(ccp(0.5f, 0.5f));

        // Layout update
        needsLayout();

        return true;
    }
    //couldn't init the CCControl
    else
    {
        return false;
    }
}

this->setTitleDispatchTable(CCDictionary::create()); 等四个函数就是设置4个表,分别对应标签文本、标签颜色、标签、背景图片。用户可以存储标签与图片的不同状态在这些表中,控件在每一个状态,就会使用此状态下的标签与图片。
setTouchEnabled(true); 开启触摸,这里将调用CCLayer的,因为CCControlButton是CCLayer子类,并且cocos2dx2.2.2也就CCLayer实现了向触摸事件分发器注册与移除触摸代理的功能,继承CCLayer就可以使用这些功能了。这里是cocos2dx的触摸机制的详细分析cocos2dx-2.2.2触摸详解
setAdjustBackgroundImage(true);代码如下:

void CCControlButton::setAdjustBackgroundImage(bool adjustBackgroundImage)
{
    m_doesAdjustBackgroundImage=adjustBackgroundImage;
   
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值