【Cocos2d-x】可擦除的Layer:ErasableLayer

本文介绍了Cocos2d-x中创建可擦除Layer的方法,通过ErasableLayer类实现交互式的擦除功能,允许用户在游戏或应用中动态清除特定内容。

说明


ErasableLayer是一个可擦除的Layer,可实现类似橡皮擦、刮奖等效果。原理是通过颜色混合实现的。关于颜色混合可查看这篇文章 >>点击查看<<

测试环境:cocos2d-x3.3、cocos2d-x3.5


源码


#ifndef __ERASABLELAYER_H__
#define __ERASABLELAYER_H__

#include "cocos2d.h"

USING_NS_CC;

// http://blog.youkuaiyun.com/linchaolong
// 可擦除的Layer
class ErasableLayer :public Layer
{
public:
	// 创建ErasableLayer
	//1.遮罩层
	//2.橡皮擦(可以是Sprite或者纹理的路径)
	static ErasableLayer* create(const char* layerPath, const char* erasaPath);
	static ErasableLayer* create(Node *layer, Sprite* erasa);
	static ErasableLayer* create(Node *layer, const char* erasaPath);
	static ErasableLayer* create(const char* layerPath, Sprite* erasa);

	// 还原
	void clear();
	// 是否可擦除
	void setErasable(bool);

	bool onTouchBegan(Touch* touch, Event  *event);
	void onTouchesMoved(Touch* touch, Event *event);
	void onTouchEnded(Touch* touch, Event  *event);
protected:
	ErasableLayer();
	~ErasableLayer();

	bool init(Node *layer, Sprite* erasa);
	void tick(float);
private:
	Node* layer_;
	Sprite* erasa_;
	bool isErasable_;
	RenderTexture* rt_;
};

#endif

#include "ErasableLayer.h"

ErasableLayer::ErasableLayer() :isErasable_(true)
{
}

ErasableLayer::~ErasableLayer()
{
	CC_SAFE_RELEASE(layer_);
	CC_SAFE_RELEASE(erasa_);
}
 
ErasableLayer* ErasableLayer::create(const char* layerPath, const char* erasaPath){
	CCSprite* layer = CCSprite::create(layerPath);
	CCSprite* erasa = CCSprite::create(erasaPath);

	ErasableLayer* ret = new ErasableLayer;
	if (ret->init(layer, erasa))
	{
		ret->autorelease();
		return ret;
	}
	delete ret;
	return nullptr;
}

ErasableLayer* ErasableLayer::create(Node* layer, Sprite* erasa){

	ErasableLayer* ret = new ErasableLayer;
	if (ret->init(layer, erasa))
	{
		ret->autorelease();
		return ret;
	}
	delete ret;
	return nullptr;
}

ErasableLayer* ErasableLayer::create(Node* layer, const char* erasaPath){
	CCSprite* erasa = CCSprite::create(erasaPath);
	ErasableLayer* ret = new ErasableLayer;
	if (ret->init(layer, erasa))
	{
		ret->autorelease();
		return ret;
	}
	delete ret;
	return nullptr;
}

ErasableLayer* ErasableLayer::create(const char* layerPath, Sprite* erasa){
	CCSprite* layer = CCSprite::create(layerPath);

	ErasableLayer* ret = new ErasableLayer;
	if (ret->init(layer, erasa))
	{
		ret->autorelease();
		return ret;
	}
	delete ret;
	return nullptr;
}

bool ErasableLayer::init(Node *layer, Sprite* erasa){

	if (!Layer::init())
	{
		return false;
	}

	layer_ = layer;
	erasa_ = erasa;

	layer_->retain();
	erasa_->retain();

	this->setContentSize(layer_->getContentSize());

	// 设置颜色混合模式
	BlendFunc erasaBf = { GL_ZERO, GL_ONE_MINUS_SRC_ALPHA }; //源因子:值为0,橡皮擦颜色为透明;目标因子:目标颜色透明度减去源颜色的透明度
	erasa_->setBlendFunc(erasaBf);

	auto size = layer_->getContentSize();
	rt_ = RenderTexture::create(size.width, size.height);
	rt_->setAnchorPoint(Vec2(0, 0));
	rt_->setPosition(Vec2(size.width/2, size.height/2));
	this->addChild(rt_);

	clear();

	schedule(CC_SCHEDULE_SELECTOR(ErasableLayer::tick));

	// 触摸事件
	auto listener = EventListenerTouchOneByOne::create();
	listener->onTouchBegan = CC_CALLBACK_2(ErasableLayer::onTouchBegan, this);
	listener->onTouchMoved = CC_CALLBACK_2(ErasableLayer::onTouchesMoved, this);
	listener->onTouchEnded = CC_CALLBACK_2(ErasableLayer::onTouchEnded, this);
	_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
	listener->setSwallowTouches(false);

	return true;
}


void ErasableLayer::tick(float){
	if (!isErasable_)
	{
		return;
	}
	
	// 设置源颜色alpha值为最大值,目标颜色alpha值减去源颜色alpha值后就为0了,混合出来的效果就变透明了,这样就实现了橡皮擦效果了。
	erasa_->setOpacity(255);

	// 更新RenderTexture
	rt_->begin();
	
	// 绘制
	erasa_->visit();

	rt_->end();
}

void ErasableLayer::clear(){
	layer_->setAnchorPoint(Vec2(0, 0));
	layer_->setPosition(Vec2(0, 0));

	rt_->begin();
	layer_->visit();
	rt_->end();
}

void ErasableLayer::setErasable(bool flag){
	isErasable_ = flag;
}

bool ErasableLayer::onTouchBegan(Touch* touch, Event  *event)
{
	erasa_->setPosition(this->convertToNodeSpace(touch->getLocation()));
	return true;
}
void ErasableLayer::onTouchesMoved(Touch* touch, Event  *event){
	erasa_->setPosition(this->convertToNodeSpace(touch->getLocation()));
}
void ErasableLayer::onTouchEnded(Touch* touch, Event  *event)
{
	erasa_->setPosition(this->convertToNodeSpace(touch->getLocation()));
}


// 调用示例

	// 遮罩层
	auto maskLayer = LayerColor::create(Color4B(0,0,255,200));
	maskLayer->setContentSize(sprite->getContentSize());

	// 创建可擦除的Layer
	auto layer = ErasableLayer::create(maskLayer, "eraser.png");
	layer->setPosition(Vec2(visibleSize.width / 4, visibleSize.height / 4));
	this->addChild(layer);

这里创建了一个蓝色的LayerColor,并擦除该Layer。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值