cocos2d-3.x实现擦图效果

//
//  Eraser.h
//  Eraser
//
//  Created by students on 16/1/12.
//
//

#ifndef __Eraser__Eraser__
#define __Eraser__Eraser__

#include <stdio.h>
#include <cocos2d.h>
USING_NS_CC;
//pszFileName--精灵文件名, eraserImmediately---是否可以立即擦除 true---可以, false---不能
//drawType---擦除形状, 0---正方形,1---圆形, 2---自定义形状(可用一张图片代替)
class Eraser : public Sprite
{
public:
    Eraser();
    ~Eraser();
    
    static Eraser* create(std::string pszFileName,const bool& eraserImmediately = true,const unsigned int& drawType = 0);
    virtual bool init(std::string pszFileName,const bool& eraserImmediately = true,const unsigned int& drawType = 0);
    
    virtual void onEnter();
    virtual void onExit();
    
public:
    CC_PROPERTY(bool, isEraser, Eraser);//设置是否可以擦除
    CC_PROPERTY(float, drawWidth, DrawWidth);//擦除大小,默认10.F
    CC_PROPERTY(bool, isEraserOK, EraserOK);//是否擦除完毕
    
    void setDrawStencil(std::string pszFileName);
    
private:
    void eraserByBlend(Point& point);
    void eraserByBlend(const Point& point);
    void eraserByColorMask();
    
private:
    void initData(std::string pszFileName,const bool& eraserImmediately = true,const unsigned int& zdrawType = 0);
    Size spriteSize;//精灵大小
    unsigned int drawType;//擦除形状
    
    Point touchPoint;//触摸点
    Texture2D* drawTextture;//自定义图片时,设置的擦除图片
    
    RenderTexture* Rtex;//渲染纹理
    DrawNode* pEraser;//渲染节点
};

#endif /* defined(__Eraser__Eraser__) */
//
//  Eraser.cpp
//  Eraser
//
//  Created by students on 16/1/12.
//
//

#include "Eraser.h"
Eraser::Eraser()
{
    
}
Eraser::~Eraser()
{
    pEraser->release();
}

Eraser* Eraser::create(std::string pszFileName,const bool& eraserImmediately,const unsigned int& drawType)
{//创建对象
    Eraser* pRet = new Eraser();
    if (pRet && pRet->init(pszFileName,eraserImmediately,drawType)) {
        pRet->autorelease();
        return pRet;
    }else
    {
        delete pRet;
        pRet = NULL;
        return NULL;
    }
}
bool Eraser::init(std::string pszFileName,const bool& eraserImmediately,const unsigned int& drawType)
{
    if (!Sprite::init()) {
        return false;
    }
    initData(pszFileName,eraserImmediately,drawType);
    
    auto dis = Director::getInstance()->getEventDispatcher();
    auto lis = EventListenerTouchOneByOne::create();
    lis->onTouchBegan = [this](Touch* touch,Event* event)
    {
        if (isEraser)
        {
            Point point = touch->getLocation();
            eraserByBlend(-this->getPosition() + point + spriteSize/2.f);
            touchPoint = point;
            
            return true;
        }
        
        return false;
    };
    lis->onTouchMoved = [this](Touch* touch,Event* event)
    {
        if (isEraser)
        {
            Point point = touch->getLocation();
            Point normal = (point-touchPoint).getNormalized();
            
            
            while(1)
            {
                if (point.distance(touchPoint) < 1.f)
                {
                    eraserByBlend(-this->getPosition() + point + spriteSize/2.f);
                    break;
                }
                touchPoint = touchPoint + normal*1.f;
                eraserByBlend(-this->getPosition() + touchPoint + spriteSize/2.f);
            }
            
            touchPoint = point;
        }
    };
    dis->addEventListenerWithSceneGraphPriority(lis, this);
    
    return true;
}
void Eraser::initData(std::string pszFileName,const bool& eraserImmediately,const unsigned int& zdrawType)
{
    isEraser = eraserImmediately;
    drawType = zdrawType;
    drawWidth = 10.0f;
    
    auto size = Director::getInstance()->getWinSize();
    //设置图片
    auto sprite = Sprite::create(pszFileName);
    auto scalex = size.width/sprite->getContentSize().width;
    auto scaley = size.height/sprite->getContentSize().height;
    sprite->setScaleX(scalex);
    sprite->setScaleY(scaley);
    
    spriteSize = size;
    
    sprite->setAnchorPoint(Vec2::ZERO);
    
    //渲染纹理
    Rtex = RenderTexture::create(spriteSize.width, spriteSize.height);
    Rtex->setPosition(Point::ZERO);
    this->addChild(Rtex);
    
    //????
    Rtex->begin();
    sprite->visit();//??
    Rtex->end();
    
    //渲染节点
    pEraser = DrawNode::create();
    setDrawWidth(10.0f);
    pEraser->retain();///???
    //自定义擦除的图片
    drawTextture = new Texture2D;
    drawTextture->retain();
}
void Eraser::setDrawStencil(std::string pszFileName)
{
    drawTextture = Director::getInstance()->getTextureCache()->addImage(pszFileName);
}

void Eraser::eraserByBlend(Point& point)
{
    
}
void Eraser::eraserByBlend(const Point& point)
{
    switch (drawType) {
        case 2:
        {
            auto drawSprite = Sprite::createWithTexture(drawTextture);
            drawSprite->setPosition(point);
            BlendFunc blendFunc = {GL_ONE_MINUS_SRC_ALPHA,GL_SRC_ALPHA};
            drawSprite->setBlendFunc(blendFunc);
            Rtex->begin();
            drawSprite->visit();
            Rtex->end();
        }
            break;
            
        default:
        {
            pEraser->setPosition(point);
            BlendFunc blendFunc = {GL_ONE,GL_ZERO};
            pEraser->setBlendFunc(blendFunc);
            Rtex->begin();
            pEraser->visit();
            Rtex->end();
        }
            break;
    }
}
void Eraser::eraserByColorMask()
{
    Rtex->begin();
    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
    pEraser->visit();
    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
    Rtex->end();
}

void Eraser::setEraser(bool var)
{
    this->isEraser = var;
}
bool Eraser::getEraser()
{
    return isEraser;
}
bool Eraser::getEraserOK()
{
    isEraserOK = false;
    
    auto image = new Image();
    image = Rtex->newImage();
    
    int m = 3;
    if (image->hasAlpha()) {
        m = 4;
    }
    
    unsigned char* data_ = image->getData();
    int x = 0,y = 0;
    for (x = 0; x<spriteSize.width; ++x) {
        for (y = 0; y<spriteSize.height; ++y) {
            unsigned char* pixel = data_+(x+y*image->getWidth())*m;
            
            unsigned int r = (unsigned int)*pixel;
            unsigned int g = (unsigned int)*(pixel + 1);
            unsigned int b = (unsigned int)*(pixel + 2);
            unsigned int a = (unsigned int)*(pixel + 3);
            
            if (r != 0 && g!=0 && b!=0 && a!=0) {
                isEraserOK = false;
                break;
            }
        }
        if (spriteSize.height != y) {
            break;
        }
    }
    if (x == spriteSize.width && y == spriteSize.height) {
        isEraserOK = true;
    }
    delete image;
    
    return this->isEraserOK;
}
void Eraser::setEraserOK(bool var)
{
    this->isEraser = var;
}
float Eraser::getDrawWidth()
{
    return this->drawWidth;
}
void Eraser::setDrawWidth(float var)
{
    this->drawWidth = var;
    switch (drawType) {
        case 0:
        {
            pEraser->drawDot(Vec2::ZERO, drawWidth, Color4F(0, 0, 0, 0));
        }
            break;
        case 1:
        {
            float fRadius = drawWidth;
            const int nCount = 100;
            const float coef = 2.0f*(float)M_PI/nCount;
            static Vec2 circle[nCount];
            for (unsigned int i=0; i<nCount; i++) {
                float rads = i*coef;
                circle[i].x = fRadius*cosf(rads);
                circle[i].y = fRadius*sinf(rads);
            }
            pEraser->drawPolygon(circle, nCount, Color4F(0, 0, 0, 0), 0, Color4F(0, 0, 0, 0));
        }
            break;
        case 2:
        {
            
        }
            break;
            
        default:
            break;
    }
}
void Eraser::onEnter()
{
    Sprite::onEnter();//单点触摸
    
}
void Eraser::onExit()
{
    Sprite::onExit();
}

 

posted @ 2016-01-13 20:59  离时樱  阅读(536)  评论(0编辑  收藏  举报