cocos3.x创建不规则按钮

前端之家收集整理的这篇文章主要介绍了cocos3.x创建不规则按钮前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

1主要思路

Image类的initWithImageFile()方法去初始化Image对象,在一开始时创建一次,用一个bool数组保存每个像素点是否透明度为0的信息。每次触发点击事件时,就根据这个数组的值来判断点击是否有效。IrregularButton类继承自Button类。

2详细设计

2.1成员变量

  1. CC_SYNTHESIZE(int,m_iBtnID,iBtnID);
  2. int normalImageWidth_;
  3. int normalImageHeight_;
  4. bool* normalTransparent_;

m_iBtnID:按钮IDnormalImageWidth_图片的宽度。normalImageHeight_图片的高度。normalTransparent_:实际上是一个bool型的数组,用于存放每个像素点是否透明度为0,为0值为true

2.2Create函数

IrregularButton的静态创建函数create,覆盖父类create函数

  1. IrregularButton* IrregularButton::create(const std::string& normalImage,const std::string& selectedImage,const std::string& disableImage,TextureResType texType)
  2. {
  3. IrregularButton* btn = new IrregularButton;
  4. if (btn && btn->init(normalImage,selectedImage,disableImage,texType)) {
  5. btn->autorelease();
  6. return btn;
  7. }
  8. CC_SAFE_DELETE(btn);
  9. return nullptr;
  10. }

2.3init函数

  1. bool IrregularButton::init(const std::string &normalImage,TextureResType texType)
  2. {
  3. bool ret = true;
  4. do {
  5. if (!Button::init(normalImage,texType)) {
  6. ret = false;
  7. break;
  8. }
  9. } while (0);
  10. loadNormalTransparentInfo(normalImage);
  11.  
  12. auto listener1 = EventListenerTouchOneByOne::create(); listener1->setSwallowTouches(true);
  13. listener1->onTouchBegan = [=](Touch* touch,Event* event){
  14. Point locationInNode = convertToWorldSpace(touch->getLocation());
  15. hitTest(locationInNode);
  16. return true;
  17. };
  18. listener1->onTouchMoved = [=](Touch* touch,Event* event){
  19. };
  20. listener1->onTouchEnded = [=](Touch* touch,Event* event){
  21. };
  22. _eventDispatcher->addEventListenerWithSceneGraPHPriority(listener1,this);
  23. return ret;
  24. }

这里做以下几件事:1.调用父类init函数,使得的_buttonNormalRenderer确定,即确定按钮的大小;2.调用loadNormalTransparentInfo函数,确定normalTransparent_的数组值,即得到了精灵的每一点的是否透明。3.绑定触摸响应,并进行判断点击的那一点是否点击在精灵的透明区域。

2.4loadNormalTransparentInfo函数

IrregularButtonloadNormalTransparentInfo函数,保存normalTransparent_的数组值。

  1. void IrregularButton::loadNormalTransparentInfo(std::string sName)
  2. {
  3. Image* normalImage = new Image();
  4. normalImage->initWithImageFile(sName);
  5. normalImageWidth_ = normalImage->getWidth();
  6. normalImageHeight_ = normalImage->getHeight();
  7. this->setContentSize(CCSizeMake(normalImageWidth_,normalImageHeight_));
  8. auto dataLen = normalImage->getDataLen();
  9. if (normalTransparent_ != nullptr) {
  10. delete[] normalTransparent_;
  11. }
  12. auto normalPixels = normalImage->getData();
  13. normalTransparent_ = new bool[dataLen / (sizeof(unsigned char)* 4)];
  14. for (auto i = 0; i < normalImageHeight_; i++) {
  15. for (auto j = 0; j < normalImageWidth_; j++) {
  16. normalTransparent_[i * normalImageWidth_ + j] = (normalPixels[(i * normalImageWidth_ + j) * 4] == 0);
  17. }
  18. }
  19. delete normalImage;
  20. }

initWithImageFile得到精灵的RGBA信息。扫描精灵的每一点,当前点透明时为true放入normalTransparent中,否则为false放入normalTransparent中。

2.5hitTest函数

IrregularButtonhitTest函数,用来确定点击的是否透明区域。

  1. bool IrregularButton::hitTest(const Vec2 &pt)
  2. {
  3. Vec2 localLocation = _buttonNormalRenderer->convertToNodeSpace(pt);
  4. Rect validTouchedRect;
  5. validTouchedRect.size = _buttonNormalRenderer->getContentSize();
  6. if (validTouchedRect.containsPoint(localLocation) && getIsTransparentAtPoint(localLocation) == false)
  7. {
  8. CCLOG("IN");
  9. NotificationCenter::getInstance()->postNotification("NotifyIrregularBtn",(Ref*)m_iBtnID);
  10. return true;
  11. }
  12. return false;
  13. }

首先点击坐标转化为世界坐标,再转化为相对精灵坐标,当点击点包含在精灵的范围内并且点击的是非透明区域,说明点中了这个不规则按钮,向外发送通知通知传递自身的m_iBtnID号。

2.6getIsTransparentAtPoint函数

  1. bool IrregularButton::getIsTransparentAtPoint(cocos2d::Vec2 point)
  2. {
  3. point.y = _buttonNormalRenderer->getContentSize().height - point.y;
  4. int x = (int)point.x - 1;
  5. if (x < 0) {
  6. x = 0;
  7. }
  8. else if (x >= normalImageWidth_) {
  9. x = normalImageWidth_ - 1;
  10. }
  11. int y = (int)point.y - 1;
  12. if (y < 0) {
  13. y = 0;
  14. }
  15. else if (y >= normalImageHeight_) {
  16. y = normalImageHeight_ - 1;
  17. }
  18. return normalTransparent_[normalImageWidth_ * y + x];
  19. }

这里值得注意的是相对精灵坐标的是从精灵的左下角为原点,这里要转化为以左上角为原点的坐标。

2.7调用

  1. const string sNameN = "smile.png";
  2. const string sNameP = "angry.png";
  3. IrregularButton* alphaBtn = IrregularButton::create(sNameN,sNameP,sNameP);
  4. alphaBtn->setiBtnID(0);
  5. alphaBtn->setPosition(ccp(400,400));
  6. this->addChild(alphaBtn);
  7. NotificationCenter::getInstance()->addObserver(this,callfuncO_selector(HelloWorld::onNotifyIrregularBtn),"NotifyIrregularBtn",NULL);

调用的类中绑定通知,把转换的传入参数转为BtnID即可知道是哪个不规则按钮的通知

  1. void HelloWorld::onNotifyIrregularBtn(Ref* ref)
  2. {
  3. int iBtnID = (int)ref;
  4. }

实现效果

没点击时:

当点击到笑脸的圆形区域(即非透明区域)时:

点击精灵其他区域(透明区域)是不会响应的。IrregularButton类继承自Button类,这样按钮就可以通过传入三张精灵,实现正常,按压,禁止的按钮三种状态

工程源码下载:

猜你在找的Cocos2d-x相关文章