cocos2dx游戏开发学习——技能按钮(雏形)

此技能按钮主要有一下几个功能

  1. 技能冷却效果
  2. 技能蓄力

代码如下:

SkillButton.h

#ifndef SkillButton_h
#define SkillButton_h

#include <stdio.h>
#include "cocos2d.h"


USING_NS_CC;

class SkillButton:public Node
{
public:
    typedef std::function<void(float pressTime)> alSkillClickCallback;
    typedef std::function<void(float pressTime)> alSkillTouchCallback;
    typedef std::function<void(void)> alSkillCDEndCallback;



public:
    static SkillButton* create(const std::string normalImage,const std::string coolImage = "",float skillTime = 0);

    SkillButton();
    virtual ~SkillButton();

    /**
      技能是否处于冷却中
     */
    virtual const bool& isSkillCD() const { return _isSkillCD;}

    /**
     *  设置正常状态下的Image
     */
    virtual void setupNormalImage(const std::string normalImage);
    /**
     *  设置冷却状态下的Image
     */
    virtual void setupCoolImage(const std::string coolImage);



    /**
     技能的点击回调
     注意:如果不开启按压更新的话  按压时间一直为0
     */
    virtual void addClickCallback(const alSkillClickCallback& callback);

    /**
     技能按压开始的回调 按压时间为 0
     */
    virtual void addTouchBeginCallback(const alSkillTouchCallback& callback);


    /**
     技能按压结束的回调
     注意:如果不开启按压更新的话  按压时间一直为0
     */
    virtual void addTouchEndCallback(const alSkillTouchCallback& callback);

    /**
     技能按压更新回调 (每隔一段时间 进行更新)
     注意:如果不开启按压更新的话,此回调函数不会调用
     @param callback 回调函数
     @param interval 时间间隔应该大于等于0.1且是0.1的倍数  如果时间间隔为0 则表示不会启用更新函数
     */
    virtual void addTouchUpdateCallback(const alSkillTouchCallback& callback,float interval);

    /**
     添加技能CD结束后的回调
     */
    virtual void addSkillCDEndCallback(const alSkillCDEndCallback& callback);


protected:
    virtual bool init() override;
    virtual bool init(const std::string normalImage,const std::string coolImage,float skillTime);
    /**
     添加触摸事件
     */
    virtual void addTouchListener();

    /**
     执行技能按钮触摸开始操作
     */
    virtual bool doSkillTouchBegin(const Point& touchPoint);

    /**
     执行技能按钮触摸移动操作
     */
    virtual void doSkillTouchMoved(const Point& touchPoint);

    /**
     执行技能按钮触摸结束操作
     */
    virtual void doSkillTouchEnd(const Point& touchPoint);


    /**
      开始技能冷却
     */
    virtual void startSkillCDAction();

    /**
     重置技能冷却
     */
    virtual void resetSkillCDAction();

    /**
     减少冷却时间
     */
    virtual void reduceSkillCDTimeAction(float time);

protected:
    Sprite* _pSkill;
    ProgressTimer* _pProgressCD;


    //** 技能是否可用 *//
    CC_PROPERTY_PASS_BY_REF(bool, _skillEnable, SkillEnable);
    //** 技能是否处于冷却时间 *//
    bool _isSkillCD = false;
    //** 技能冷却时间 *//
    CC_SYNTHESIZE_PASS_BY_REF(float, _skillCoolTime, SkillCoolTime);
    //** 技能按压计时更新是否可用 *//
    CC_SYNTHESIZE_PASS_BY_REF(bool, _updateEnable, UpdateEnable);
    //** 按压时间 *//
    CC_SYNTHESIZE_READONLY_PASS_BY_REF(float, _pressTime, PressTime);
    //**  *//
    float _tUpdateInerval = 0;


    std::string _normalImageName;
    std::string _coolImageName;
    alSkillClickCallback _clickCallback;
    alSkillTouchCallback _touchBeginCallback;
    alSkillTouchCallback _touchEndCallback;
    alSkillClickCallback _touchUpdateCallback;
    alSkillCDEndCallback _skillCDEndCallback;


private:
    //** 是否技能触摸结束 *//
    bool _isSkillTouchEnd = true;
    //** 更新时间增量数,主要用于 *//
    float _deltaSum = 0;
};

#endif /* SkillButton_h */

SkillButton.cpp

#include "SkillButton.h"


#define SCHEDULE_SKILL_UPDATE_TIME "SCHEDULE_SKILL_UPDATE_TIME"
#define SKILL_UPDATE_INTERVAL 0.1

SkillButton::SkillButton()
{
    _pSkill = nullptr;
    _pProgressCD = nullptr;


    _skillEnable = true;
    _skillCoolTime = 0;
    _isSkillCD = false;
    _updateEnable = false;
    _pressTime = 0;
    _tUpdateInerval = 0;

    _normalImageName = "";
    _coolImageName ="";

    _clickCallback = nullptr;
    _touchBeginCallback = nullptr;
    _touchEndCallback = nullptr;
    _touchUpdateCallback = nullptr;
    _skillCDEndCallback = nullptr;


    _deltaSum = 0;
}


SkillButton::~SkillButton()
{

}

SkillButton* SkillButton::create(const std::string normalImage,const std::string coolImage,float skillTime)
{
    SkillButton* skillBtn = new (std::nothrow) SkillButton();
    if (skillBtn && skillBtn->init(normalImage, coolImage, skillTime)) {
        return skillBtn;
    }else{
        CC_SAFE_DELETE(skillBtn);
        return nullptr;
    }
}


bool SkillButton::init()
{
    if (Node::init()) {
        return true;
    }
    return false;
}

bool SkillButton::init(const std::string normalImage, const std::string coolImage, float skillTime)
{
    if (init()) {
        _skillCoolTime = skillTime;
        setupNormalImage(normalImage);
        setupCoolImage(coolImage);

        addTouchListener();
        return true;
    }
    return false;
}


void SkillButton::addTouchListener()
{
    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(false);
    listener->onTouchBegan = [this](Touch* touch, Event* evnt)->bool
    {
        return this->doSkillTouchBegin(touch->getLocation());
    };

    listener->onTouchMoved = [this](Touch* touch, Event* evnt)
    {

        this->doSkillTouchMoved(touch->getLocation());
    };

    auto touchEndedCallback = [this](Touch* touch, Event* evnt)
    {
        this->doSkillTouchEnd(touch->getLocation());
    };

    listener->onTouchCancelled = touchEndedCallback;

    listener->onTouchEnded = touchEndedCallback;

    Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, this);

}


bool SkillButton::doSkillTouchBegin(const Point& touchPoint)
{
    // 判断点击区域
    Size contentSize = _pSkill->getContentSize();
    Rect btnRect = Rect(this->getPositionX() - contentSize.width/2, this->getPositionY()- contentSize.height/2, contentSize.width, contentSize.height);
    if (btnRect.containsPoint(touchPoint)) {
        if (_skillEnable && !_isSkillCD) {
            // 开启计时器
            if (_updateEnable) {
                unschedule(SCHEDULE_SKILL_UPDATE_TIME);
                _pressTime = 0;
                _deltaSum = 0;
                schedule([this](float delta){
                    _pressTime += delta;
                    _pressTime = (float)((int)(_pressTime * 1000 + 0.5f))/1000;//保留小数点后三位
                    if (_tUpdateInerval>= delta && _touchUpdateCallback)
                    {
                        _deltaSum+= delta;
                        _deltaSum = (float)((int)(_deltaSum * 1000 + 0.5f))/1000;// 保留小数点后三位
                        if (_deltaSum >= _tUpdateInerval) {
                            _touchUpdateCallback(_pressTime);
                            _deltaSum = 0;
                        }
                    }

                }, SKILL_UPDATE_INTERVAL, SCHEDULE_SKILL_UPDATE_TIME);
            }
            // 调用开始回调
            if (_touchBeginCallback) {
                _touchBeginCallback(0);
            }
            _isSkillTouchEnd = false;
            return true;
        }
    }
    _isSkillTouchEnd = true;
    return false;
}


void SkillButton::doSkillTouchMoved(const cocos2d::Point &touchPoint)
{
    if (!_isSkillTouchEnd) {
        Size touchSize = Size(_pSkill->getContentSize().width*1.2, _pSkill->getContentSize().height*1.2);
        Rect touchRect = Rect(this->getPositionX() - touchSize.width/2, this->getPositionY()- touchSize.height/2, touchSize.width, touchSize.height);

        if (!touchRect.containsPoint(touchPoint)) {
            this->doSkillTouchEnd(touchPoint);
        }
    }
}


void SkillButton::doSkillTouchEnd(const Point& touchPoint)
{
    if (!_isSkillTouchEnd)
    {
        // 停止计时器
        unschedule(SCHEDULE_SKILL_UPDATE_TIME);

        float pressTime = _pressTime;
        _pressTime = 0;
        _deltaSum = 0;

        if (_touchEndCallback) {
            _touchEndCallback(pressTime);
        }
        if (_clickCallback) {
            _clickCallback(pressTime);
        }

        // 开始读冷却
        this->startSkillCDAction();
        _isSkillTouchEnd = true;
    }
}


void SkillButton::startSkillCDAction()
{
    if (_skillCoolTime > 0) {
        _isSkillCD = true;
        _pProgressCD->setPercentage(100);
        _pProgressCD->stopAllActions();
        _pProgressCD->runAction(Sequence::create(ProgressTo::create(_skillCoolTime, 0),CallFunc::create([this]{
            // 技能冷却结束
            _isSkillCD = false;
            // 技能冷却完成后的回调
            if (_skillCDEndCallback) {
                _skillCDEndCallback();
            }
        }), NULL));
    }else{
        _pProgressCD->stopAllActions();
        _pProgressCD->setPercentage(0);
        _isSkillCD = false;
        // 技能冷却完成后的回调
        if (_skillCDEndCallback) {
            _skillCDEndCallback();
        }
    }


}

void SkillButton::resetSkillCDAction()
{
    if (_isSkillCD) {
        _pProgressCD->stopAllActions();
        _pProgressCD->setPercentage(0);
        _isSkillCD = false;
        // 技能冷却完成后的回调
        if (_skillCDEndCallback) {
            _skillCDEndCallback();
        }
    }
}

void SkillButton::reduceSkillCDTimeAction(float time)
{
    if (_isSkillCD) {
        _pProgressCD->stopAllActions();
        float percent = _pProgressCD->getPercentage();
        float remainingTime = MIN(0, percent*_skillCoolTime - time);
        if (remainingTime > 0) {
            float nowPercent = 100.f / _skillCoolTime * remainingTime;
            _pProgressCD->setPercentage(nowPercent);
            _pProgressCD->runAction(Sequence::create(ProgressTo::create(remainingTime, 0),CallFunc::create([this]{
                // 技能冷却结束
                _isSkillCD = false;
                // 技能冷却完成后的回调
                if (_skillCDEndCallback) {
                    _skillCDEndCallback();
                }
            }), NULL));
        }else{
            resetSkillCDAction();
        }
    }
}




//============================
// !!!: public
//============================

void SkillButton::setSkillEnable(const bool &enable)
{
    if (_skillEnable != enable) {
        _skillEnable = enable;
        if (!_skillEnable) {
            _pProgressCD->stopAllActions();
            _pProgressCD->setPercentage(100);
            _isSkillCD = true;
        }
    }
}


const bool& SkillButton::getSkillEnable() const
{
    return _skillEnable;
}


void SkillButton::setupNormalImage(const std::string normalImage)
{
    _normalImageName = normalImage;
    CCASSERT(!normalImage.empty(), "SkillButton : normalImage is empty");
    auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(normalImage);
    if (_pSkill) {
        (frame ? _pSkill->setSpriteFrame(frame) : _pSkill->setSpriteFrame(normalImage));
    }else{
        _pSkill = frame ? Sprite::createWithSpriteFrame(frame) : Sprite::create(normalImage);
        this->addChild(_pSkill,0);
    }
    setContentSize(_pSkill->getContentSize());

    if (_coolImageName.empty()) {
        setupCoolImage("");
    }

}

void SkillButton::setupCoolImage(const std::string coolImage)
{
    _coolImageName = coolImage;
    Sprite* coolSprite = nullptr;
    if (coolImage.empty()) {
        auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(_normalImageName);
        coolSprite = frame ? Sprite::createWithSpriteFrame(frame) : Sprite::create(_normalImageName);
        coolSprite->setColor(Color3B(64, 64, 64));
    }else{
        auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(coolImage);
        coolSprite = frame ? Sprite::createWithSpriteFrame(frame) : Sprite::create(coolImage);
    }
    if (_pProgressCD) {
        _pProgressCD->setSprite(coolSprite);
    }else{
        _pProgressCD = ProgressTimer::create(coolSprite);
        _pProgressCD->setType(ProgressTimer::Type::RADIAL);
        _pProgressCD->setReverseProgress(true);
        _pProgressCD->setPercentage(0);
        this->addChild(_pProgressCD,1);
    }
}

void SkillButton::addClickCallback(const SkillButton::alSkillClickCallback &callback)
{
    _clickCallback = callback;
}

void SkillButton::addTouchBeginCallback(const SkillButton::alSkillTouchCallback &callback)
{
    _touchBeginCallback = callback;
}

void SkillButton::addTouchEndCallback(const SkillButton::alSkillTouchCallback &callback)
{
    _touchEndCallback = callback;
}

void SkillButton::addTouchUpdateCallback(const SkillButton::alSkillTouchCallback &callback, float interval)
{
    if (interval >= SKILL_UPDATE_INTERVAL) {
        _touchUpdateCallback = callback;
        _tUpdateInerval = interval;
    }
}

void SkillButton::addSkillCDEndCallback(const alSkillCDEndCallback& callback)
{
    _skillCDEndCallback = callback;
}

猜你喜欢

转载自blog.csdn.net/Allen_ww/article/details/81084124