Event of the Slider doesn't work correctly

I need to create a controller of the BGM volume and I select to use the slider bar.

What I want is to play a sound effect when the value changed.

Here is my code:

auto bgm = Slider::create();
bgm->loadBarTexture("data/menu/config/MaterBlack.png");
bgm->loadProgressBarTexture("data/menu/config/Mater.png");
bgm->setPosition(Vec2(400, 297.7));
bgm->setMaxPercent(20);
bgm->setPercent(20);
bgm->addEventListener([&](Ref* sender, Slider::EventType type) {
    if (type == Slider::EventType::ON_PERCENTAGE_CHANGED) {
        CocosDenshion::SimpleAudioEngine::getInstance()->playEffect("data/se/039.wav");
    }
});

Confusingly, every time when I moved my finger on the slider bar(I didn’t change the value), it would always play the SE.

Then I added a log function to the event to display the value of EventType.

I found that the value of EventType is always among 0, 1, 2, as touch_move, touch_down, touch_up.

Is this a bug of cocos2dx? So how can I modify the source code to fix this problem?

I’m using the cocos2dx v3.10 and Xcode to develop my game.I debugged on iOS emulator.

I’ve found the resolution.

I think it’s a bug of cocos2dx.

In my opinion, percentage changing doesn’t mean that your finger has moved.

So I modified the code in UISlider.cpp and UISlider.h

I added a new item in enum EventType called ON_TOUCH_MOVE at UISlider.h

enum class EventType
{
    ON_PERCENTAGE_CHANGED,
    //@since v3.7
    ON_SLIDEBALL_DOWN,
    ON_SLIDEBALL_UP,
    ON_SLIDEBALL_CANCEL,
    ON_TOUCH_MOVE
};

And I changed the way the callback functions work.

bool Slider::onTouchBegan(Touch *touch, Event *unusedEvent)
{
    bool pass = Widget::onTouchBegan(touch, unusedEvent);
    if (_hitted)
    {
        int percent_old = getPercent();
        int percent_new = getPercentWithBallPos(_touchBeganPosition);
        if (percent_old != percent_new && percent_new >= 0 && percent_new <= getMaxPercent()) {
            setPercent(percent_new);
            percentChangedEvent(EventType::ON_SLIDEBALL_DOWN);
            percentChangedEvent(EventType::ON_PERCENTAGE_CHANGED);
        } else {
            setPercent(percent_new);
            percentChangedEvent(EventType::ON_SLIDEBALL_DOWN);
        }
    }
    return pass;
}

void Slider::onTouchMoved(Touch *touch, Event *unusedEvent)
{
    _touchMovePosition = touch->getLocation();
    int percent_old = getPercent();
    int percent_new = getPercentWithBallPos(_touchMovePosition);
    if (percent_old != percent_new && percent_new >= 0 && percent_new <= getMaxPercent()) {
        setPercent(percent_new);
        percentChangedEvent(EventType::ON_PERCENTAGE_CHANGED);
    } else {
        setPercent(percent_new);
        percentChangedEvent(EventType::ON_TOUCH_MOVE);
    }
}

void Slider::onTouchEnded(Touch *touch, Event *unusedEvent)
{
    Widget::onTouchEnded(touch, unusedEvent);
    percentChangedEvent(EventType::ON_TOUCH_MOVE);
    percentChangedEvent(EventType::ON_SLIDEBALL_UP);
}

Then it works as I wish.

1 Like