cocos2d创建不规则按钮

本文介绍两种在Cocos2d-x中实现不规则形状按钮的方法:一是通过自定义按钮类来处理透明像素;二是修改Button类源码以支持透明度检测。文章提供完整代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在游戏中,有时候会遇到不规则的按钮,比如:三国类的地图上的按钮,根据国家的的大小,划分成不同大小的不规则按钮,我们知道,素材都是规则的矩形,只不过有些圆形,不规则等图形中,在Image中处理时的数据为0而已。具体的像素问题不是很了解,好了,直接上代码。

方法一:

IrregularButton.h

#ifndef __IRREGULAR_BUTTON_H__
#define __IRREGULAR_BUTTON_H__ 

#include "cocos2d.h"
#include "ui/CocosGUI.h"
USING_NS_CC;
using namespace ui;

class IrregularButton : public Button
{
public:
	IrregularButton();                                     
	virtual ~IrregularButton();                            
	static IrregularButton* create(const std::string& normalImage,const std::string& selectedImage = "",const std::string& disableImage = "",Widget::TextureResType texType = Widget::TextureResType::LOCAL);
	virtual bool init(const std::string& normalImage, const std::string& selectedImage = "", const std::string& disableImage = "", Widget::TextureResType texType = Widget::TextureResType::LOCAL) override;
	virtual bool hitTest(const cocos2d::Vec2 &pt) override;
	
	void loadNormalTransparentInfo(std::string normalImage);   //初始化按钮
	bool getIsTransparentAtPoint(cocos2d::Vec2 point);		   //获取点击到的像素数据

private:
	int normalImageWidth_;
	int normalImageHeight_;
	bool* normalTransparent_;

};


#endif

IrregularButton.cpp

#include "IrregularButton.h"
IrregularButton::IrregularButton() :
Button(),
normalTransparent_(nullptr)
{}

IrregularButton::~IrregularButton()
{
	delete[] normalTransparent_;
}

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;
}

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);
	return ret;
}


void IrregularButton::loadNormalTransparentInfo(std::string sName)
{
	Image* normalImage = new Image();
	normalImage->initWithImageFile(sName);
	normalImageWidth_ = normalImage->getWidth();
	normalImageHeight_ = normalImage->getHeight();
	this->setContentSize(Size(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;
}

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];
}

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

然后在HelloWorld中直接创建就可以了

	const std::string sNameN = "smile.png";
	const std::string sNameP = "angry.png";
	IrregularButton* alphaBtn = IrregularButton::create(sNameN, sNameP, sNameP);
	alphaBtn->setPosition(ccp(400, 400));
	this->addChild(alphaBtn);
	alphaBtn->addTouchEventListener(CC_CALLBACK_2(HelloWorld::IrregularButtonCallBack, this));

void HelloWorld::IrregularButtonCallBack(Ref* pSender, Widget::TouchEventType touchtype)
{
	switch (touchtype)
	{
	case Widget::TouchEventType::BEGAN:
		log("IrregularButtonCallBack--------TouchBegan");
		break;
	case Widget::TouchEventType::MOVED:
		log("IrregularButtonCallBack--------TouchMoved");
		break;
	case Widget::TouchEventType::ENDED:
		log("IrregularButtonCallBack--------TouchEnded");
		break;
	}
}

这样我们就能够跟普通的按钮一样使用了,源码下载地址:

https://pan.baidu.com/s/1dEYi6tF

方法二:

第一步,新建一个cocos项目,找到cocos的源代码中的Widget,它在ui 》base 》UIWidget.h文件中,在Widget类的public中添加三个函数:

virtual bool AlphaTouchCheck(const Vec2 &point);

virtual bool getAlphaTouchEnable();

virtual void setAlphaTouchEnable(bool isAlphaTouch);

然后再添加一个布尔型变量:

bool _isAlphaTouchEnable;

在UIWidget.cpp文件中实现:
bool Widget::AlphaTouchCheck(const Vec2 &point)

    {

        returntrue;

    }

bool Widget::getAlphaTouchEnable()

    {

        return_isAlphaTouchEnable;

    }

void Widget::setAlphaTouchEnable(bool isAlphaTouch)

    {

        _isAlphaTouchEnable = isAlphaTouch;  

    }



第二步,找到Button的源代码,在ui 》widgets 》UIButton.h中重载函数bool AlphaTouchCheck(constVec2& point); 在UIbutton.cpp中实现:
bool Button::AlphaTouchCheck(const Vec2& point)

    {

        if (getAlphaTouchEnable())

        {

            Image* normalImage =newImage();

            normalImage->initWithImageFile(_normalFileName);//_normalFileName是button默认的那张图片路径

            auto data = normalImage->getData();

            if (data ==NULL)

            {

                returntrue;

            }

            auto locationInNode =this->convertToNodeSpace(point);

            int pa =4 * ((normalImage->getHeight() - (int)(locationInNode.y) -1) * normalImage->getWidth() + (int)(locationInNode.x)) +3;

            unsignedint ap = data[pa];

            if (ap <20)//这里判断透明度,小于20就判断为点击无效,课根据自己的需要修改为0等等..

            {

                CC_SAFE_DELETE(normalImage);

                returnfalse;

            }

            else

            {

                CC_SAFE_DELETE(normalImage);

                returntrue;  

            }  

        }  

        returntrue;  

    }

第三步:比较重要,在在ui 》base 》UIWidget.cpp文件中找到boolWidget::onTouchBegan(Touch *touch,Event *unusedEvent),在

_touchBeganPosition = touch->getLocation();这一句代码后面添加

if(!AlphaTouchCheck(_touchBeganPosition))

        {

            return false;

        }

ok,完成。源代码修改到这里结束;

然后基本没什么,就是Button的正常使用,要注意一点的是,这个button的点击效果有个开关:setAlphaTouchEnable(bool ); 

测试在HelloWorld.cpp中添加一个Button,选一个不规则的图片作为默认按钮图,代码:

Button*s = Button::create("testbtn.png");//图片中间区域透明

s->addTouchEventListener(this,toucheventselector(HelloWorld::btnclick));

s->setPosition(Vec2(300,200));

addChild(s);

s->setAlphaTouchEnable(true);//false为关闭该功能,和普通button一样,点击中间区域按钮后执行btnclick;true为开启,点击中间区域后不进入btnclick函数;


voidHelloWorld::btnclick(Ref*r,cocos2d::ui::TouchEventType t)

{

    CCLog("Log:%s" ,"click!"); 

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值