cocos3.x创建不规则按钮

1 主要思路

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

2 详细设计

2.1 成员变量

CC_SYNTHESIZE(int,m_iBtnID,iBtnID);
	int normalImageWidth_;
	int normalImageHeight_;
	bool* normalTransparent_;
 

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

2.2 Create函数

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

IrregularButton* IrregularButton::create(const std::string& normalImage,
	const std::string& selectedImage,
	const std::string& disableImage,
	TextureResType texType)
{
	IrregularButton* btn = new IrregularButton;
	if (btn && btn->init(normalImage, selectedImage, disableImage, texType)) {
		btn->autorelease();
		return btn;
	}
	CC_SAFE_DELETE(btn);
	return nullptr;
}
 

2.3 init函数

bool IrregularButton::init(const std::string &normalImage,
	const std::string& selectedImage,
	const std::string& disableImage,
	TextureResType texType)
{
	bool ret = true;
	do {
		if (!Button::init(normalImage, selectedImage, disableImage, texType)) {
			ret = false;
			break;
		}
	} while (0);
	loadNormalTransparentInfo(normalImage);

	auto listener1 = EventListenerTouchOneByOne::create();	listener1->setSwallowTouches(true); 
	listener1->onTouchBegan = [=](Touch* touch, Event* event){
		Point locationInNode = convertToWorldSpace(touch->getLocation());
		hitTest(locationInNode);
		return true;
	};
	listener1->onTouchMoved = [=](Touch* touch, Event* event){
	};
	listener1->onTouchEnded = [=](Touch* touch, Event* event){
	};
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, this);
	return ret;
}

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

2.4 loadNormalTransparentInfo函数

IrregularButton的loadNormalTransparentInfo函数,保存normalTransparent_的数组值。

void IrregularButton::loadNormalTransparentInfo(std::string sName)
{
	Image* normalImage = new Image();
	normalImage->initWithImageFile(sName);
	normalImageWidth_ = normalImage->getWidth();
	normalImageHeight_ = normalImage->getHeight();
	this->setContentSize(CCSizeMake(normalImageWidth_, normalImageHeight_));
	auto dataLen = normalImage->getDataLen();
	if (normalTransparent_ != nullptr) {
		delete[] normalTransparent_;
	}
	auto normalPixels = normalImage->getData();
	normalTransparent_ = new bool[dataLen / (sizeof(unsigned char)* 4)];
	for (auto i = 0; i < normalImageHeight_; i++) {
		for (auto j = 0; j < normalImageWidth_; j++) {
			normalTransparent_[i * normalImageWidth_ + j] = (normalPixels[(i * normalImageWidth_ + j) * 4] == 0);
		}
	}
	delete normalImage;
}
 

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

2.5 hitTest函数

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

bool IrregularButton::hitTest(const Vec2 &pt)
{
	Vec2 localLocation = _buttonNormalRenderer->convertToNodeSpace(pt);
	Rect validTouchedRect;
	validTouchedRect.size = _buttonNormalRenderer->getContentSize();
	if (validTouchedRect.containsPoint(localLocation) && getIsTransparentAtPoint(localLocation) == false)
	{
		CCLOG("IN");
		NotificationCenter::getInstance()->postNotification("NotifyIrregularBtn", (Ref*)m_iBtnID);
		return true;
	}
	return false;
}
 

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

2.6 getIsTransparentAtPoint函数

bool IrregularButton::getIsTransparentAtPoint(cocos2d::Vec2 point)
{
	point.y = _buttonNormalRenderer->getContentSize().height - point.y;
	int x = (int)point.x - 1;
	if (x < 0) {
		x = 0;
	}
	else if (x >= normalImageWidth_) {
		x = normalImageWidth_ - 1;
	}
	int y = (int)point.y - 1;
	if (y < 0) {
		y = 0;
	}
	else if (y >= normalImageHeight_) {
		y = normalImageHeight_ - 1;
	}
	return normalTransparent_[normalImageWidth_ * y + x];
}

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

2.7调用

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

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

void HelloWorld::onNotifyIrregularBtn(Ref* ref)
{
	int iBtnID = (int)ref;
}

实现效果

没点击时:

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

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

工程源码下载:
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

四夕立羽

你的鼓励将是我创作的最大动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值