.h头文件
/*!
-
@brief GuideLayer
-
@author elvis cui
-
@date 2020-08-28
-
@ingroup Scenes/GuideLayer
-
新手引导层
2.3、分析总结
通过ClippingNode进行裁剪遮罩,其实是这样的:
将模板(Stencil)上所有元素的形状集合作为“形状模板”,其元素本身不渲染。
使用“形状模板”对底板进行裁剪。
显示从底板上裁剪下来的图片区域。
总的来说:
模板(Stencil)相当于是一个样板,上面有很多不同形状的"洞洞"。
然后根据样板,对底板进行裁剪,“挖洞”。
然后将剪下来的那些碎片,按照原来的位置进行摆放。
其中:模板(Stencil)只是一个“形状模板”,本身的图片是不进行绘制的。
模板节点是Node的子类,一般常常使用DrawNode,因为它可以绘制不同形状的图形。当然也可以直接使用Node节点作为作为模板。
*/
#pragma once
#include “cocos2d.h”
#include “cocostudio.h”
#include “cocos-ext.h”
#include “MobileKit.h”
USING_NS_CC;
USING_NS_CC_EXT;
typedef enum GuideType
{
Type_None = -1,
Type_Circle = 1, //圆形遮罩
Type_Rect = 2, //矩形遮罩
Type_ImageOrBtn = 3, //图片或按钮遮罩
}GuideType;
class GuideLayer : public Layer, public MKNodeBinder, public MKObserver
{
public:
GuideLayer();
virtual ~GuideLayer();
public:
static GuideLayer* create();
static std::string LayerName;
//开始圆形引导 世界坐标下的圆中心和半径
void startCircleGuide(cocos2d::Vec2 circle_center_worldPos, float radius);
//开始矩形引导 世界坐标下的矩形
void startRectGuide(Rect worldSpaceRect);
//开始图片或者按钮形状的新手引导 图片路径和时间坐标的位置
void startImageOrBtnGuide(std::string filePath, cocos2d::Vec2 worldSpacePos);
private:
/*!
* @brief 初始化GuideLayer
* @param
*/
virtual bool init();
virtual bool onTouchBegan(Touch *touch, Event *unused_event) override;
virtual void onTouchMoved(Touch *touch, Event *unused_event) override;
virtual void onTouchEnded(Touch *touch, Event *unused_event) override;
protected:
/*!
* @brief 绑定变量
* @param node 节点
/
virtual void onBindVariable(Node node) override;
/**
* @brief 绑定触摸事件的回调方法
* @param node 节点
*/
virtual void onBindCallback(Node* node) override;
/**
* @brief 绑定变量完成
*/
virtual void onFinishBinding() override;
/**
* @brief 设备按键
*/
void onKeyReleased(EventKeyboard::KeyCode keyCode, cocos2d::Event *event);
/*!
* @brief 响应通知
* @param 通知数据
*/
virtual void onNotify(MKNotice* notify) override;
private:
/*!
* @brief 关闭界面
*/
void close();
private:
//创建灰色的bg
EventListenerTouchOneByOne* m_touchListener = nullptr; //触摸监听器
LayerColor* createGrayBg();
bool touchInRectArea(Touch* touch); //是否点中了扣洞的矩形区域
bool touchInCircleArea(Touch *touch); //是否点中了扣洞的圆形区域
bool touchInImageOrBtnArea(Touch* touch); //是否点中了扣洞的图片或按钮区域
GuideType m_guideType = GuideType::Type_None;
cocos2d::Vec2 m_circle_center_pos = cocos2d::Vec2::ZERO; //原点位置
float m_circle_radius = 1.0f; //圆的半径
// 触摸事件如果在这个矩形区域内,则可以穿透 继续传递下去
cocos2d::Rect m_rectArea = Rect::ZERO;
//图片或按钮的新手引导
cocos2d::Sprite* m_sprite_imageOrBtn_guide = nullptr;
};
.cpp文件
#include “GuideLayer.h”
#include “GameUtils.h”
#include “SoundManager.h”
#include “GameNotify.h”
std::string GuideLayer::LayerName = “GuideLayer”;
GuideLayer::GuideLayer()
{
auto listener = EventListenerKeyboard::create();
listener->onKeyReleased = CC_CALLBACK_2(GuideLayer::onKeyReleased, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
registerAllNotice();
}
GuideLayer::~GuideLayer()
{
}
GuideLayer* GuideLayer::create()
{
GuideLayer* layer = new GuideLayer();
if (layer && layer->init())
{
layer->autorelease();
return layer;
}
else
{
delete layer;
layer = nullptr;
}
return nullptr;
}
bool GuideLayer::init()
{
if (!Layer::init())
{
return false;
}
Node* node = MKUIHelper::readNode("Guide/GuideLayer.csb", this);
addChild(node);
MKUIHelper::bindNodes(node, this, true);
//auto action = CSLoader::createTimeline("Guide/GuideLayer.csb");
//node->runAction(action);
//action->gotoFrameAndPlay(0, false);
return true;
}
bool GuideLayer::onTouchBegan(Touch* touch, Event *event)
{
bool result = false; //isTouch
if (this->m_guideType == GuideType::Type_Rect)
{
result = this->touchInRectArea(touch);
}
else if (this->m_guideType == GuideType::Type_Circle)
{
result = this->touchInCircleArea(touch);
}
else if (this->m_guideType == GuideType::Type_ImageOrBtn)
{
result = this->touchInImageOrBtnArea(touch);
}
//根据是否点中设置是否吞噬触摸
if (result)
{ //点击到了遮罩位置
LogD("1111111111111111");
this->m_touchListener->setSwallowTouches(false);
}
else
{ //点击的背景
LogD("2222222222222222");
this->m_touchListener->setSwallowTouches(true);
}
return true;
}
void GuideLayer::onTouchMoved(Touch* touch, Event *event)
{
}
void GuideLayer::onTouchEnded(Touch* touch, Event *event)
{
Point point = touch->getLocation();
Point startPoint = touch->getStartLocation();
//Point pannelPoint = m_imgBg->getParent()->convertToNodeSpace(point);//->getParent()
//if (!m_imgBg->getBoundingBox().containsPoint(pannelPoint))
//{
// close();
//}
}
void GuideLayer::onKeyReleased(EventKeyboard::KeyCode keyCode, cocos2d::Event *event)
{
if (keyCode == EventKeyboard::KeyCode::KEY_BACK)
{
//MKEventSystem::sendNotice(kOnClickKeyBackNtf);
}
else if (keyCode == EventKeyboard::KeyCode::KEY_ESCAPE)
{ //esc键
//MKEventSystem::sendNotice(kOnClickKeyBackNtf);
}
event->stopPropagation();
}
void GuideLayer::onBindVariable(Node * node)
{
}
void GuideLayer::onBindCallback(Node* node)
{
}
void GuideLayer::onFinishBinding()
{
//test code elviscui todo
//this->startCircleGuide(cocos2d::Vec2(200, 200), 100);
//this->startRectGuide(Rect(300, 300, 300, 300)); //x, y, width, height
this->startImageOrBtnGuide("textures/game/StartLayer/btn_signIn.png", Vec2(Director::getInstance()->getWinSize().width / 2, Director::getInstance()->getWinSize().height / 2));
}
void GuideLayer::onNotify(MKNotice* notify)
{
const std::string& type = notify->getType();
}
void GuideLayer::close()
{
this->removeFromParentAndCleanup(true);
}
bool GuideLayer::touchInCircleArea(Touch *touch)
{
bool result = false;
auto touchPos = touch->getLocation();
//Vec2 nodeSpace = this->convertToNodeSpace(touchPos);
if (touchPos.getDistance(this->m_circle_center_pos) <= this->m_circle_radius)
{
return true;
}
return false;
}
bool GuideLayer::touchInRectArea(Touch* touch)
{
bool result = false;
auto touchPos = touch->getLocation();
//Vec2 nodeSpace = this->convertToNodeSpace(touchPos);
if (this->m_rectArea.containsPoint(touchPos))
{
result = true;
}
return result;
}
bool GuideLayer::touchInImageOrBtnArea(Touch* touch)
{
bool result = false;
auto touchPos = touch->getLocation();
if (this->m_sprite_imageOrBtn_guide != nullptr)
{
Vec2 nodeSpace = this->m_sprite_imageOrBtn_guide->getParent()->convertToNodeSpace(touchPos);
Rect boundBox = this->m_sprite_imageOrBtn_guide->getBoundingBox();
if (boundBox.containsPoint(nodeSpace))
{
result = true;
}
}
return result;
}
LayerColor* GuideLayer::createGrayBg()
{
cocos2d::Size winSize = Director::getInstance()->getWinSize();
LayerColor* layerColor = LayerColor::create(Color4B(0, 0, 0, 255 * 0.7f), winSize.width, winSize.height); //黑色底板
if (m_touchListener == nullptr)
{
m_touchListener = EventListenerTouchOneByOne::create();
m_touchListener->onTouchBegan = CC_CALLBACK_2(GuideLayer::onTouchBegan, this);
m_touchListener->onTouchMoved = CC_CALLBACK_2(GuideLayer::onTouchMoved, this);
m_touchListener->onTouchEnded = CC_CALLBACK_2(GuideLayer::onTouchEnded, this);
m_touchListener->setSwallowTouches(true);
_eventDispatcher->addEventListenerWithSceneGraphPriority(m_touchListener, layerColor);
}
return layerColor;
}
//------------------------------public method begin-------------------------------
void GuideLayer::startCircleGuide(cocos2d::Vec2 circle_center_worldPos, float radius)
{
this->m_guideType = GuideType::Type_Circle; //设置引导类型
this->m_circle_center_pos = circle_center_worldPos;
this->m_circle_radius = radius;
ClippingNode* clippingNode = ClippingNode::create(); //创建裁剪节点
//设置模板
DrawNode* drawNode = DrawNode::create();
drawNode->drawSolidCircle(circle_center_worldPos, radius, 360, 9999, Color4F(1, 0, 0, 1));
clippingNode->setStencil(drawNode);
//设置底板
LayerColor* diban = this->createGrayBg();
clippingNode->addChild(diban);
clippingNode->setInverted(true); //反向显示
clippingNode->setAlphaThreshold(0.05f);
this->addChild(clippingNode);
}
void GuideLayer::startRectGuide(cocos2d::Rect worldSpaceRect)
{
this->m_guideType = GuideType::Type_Rect; //设置引导类型
this->m_rectArea = worldSpaceRect;
ClippingNode* clippingNode = ClippingNode::create(); //创建裁剪节点
//设置模板
DrawNode* drawNode = DrawNode::create();
drawNode->drawSolidRect(cocos2d::Vec2(worldSpaceRect.getMinX(), worldSpaceRect.getMinY()),
cocos2d::Vec2(worldSpaceRect.getMaxX(), worldSpaceRect.getMaxY()), Color4F(1, 0, 0, 1)); //矩形的起点, 矩形的终点 左下角为 0,0 点
clippingNode->setStencil(drawNode);
//设置底板
LayerColor* diban = this->createGrayBg();
clippingNode->addChild(diban);
clippingNode->setInverted(true); //反向显示
clippingNode->setAlphaThreshold(0.05f);
this->addChild(clippingNode);
}
void GuideLayer::startImageOrBtnGuide(std::string filePath, cocos2d::Vec2 worldSpacePos)
{
this->m_guideType = GuideType::Type_ImageOrBtn; //设置引导类型
ClippingNode* clippingNode = ClippingNode::create(); //创建裁剪节点
//设置模板
Node* stencil_node = Node::create();
this->m_sprite_imageOrBtn_guide = cocos2d::Sprite::create(filePath);
m_sprite_imageOrBtn_guide->setPosition(worldSpacePos);
m_sprite_imageOrBtn_guide->getTexture()->setAntiAliasTexParameters(); //抗锯齿
//m_sprite_imageOrBtn_guide->getTexture()->setAliasTexParameters(); //不抗锯齿
stencil_node->addChild(m_sprite_imageOrBtn_guide);
clippingNode->setStencil(stencil_node);
//设置底板
LayerColor* diban = this->createGrayBg();
clippingNode->addChild(diban);
clippingNode->setInverted(true); //反向显示
clippingNode->setAlphaThreshold(0.05f);
this->addChild(clippingNode);
}
//------------------------------public method end-------------------------------