功夫小子实践开发-游戏设置功能的实现

时间:2021-02-19 20:08:47

设置功能场景的ui效果图: 

功夫小子实践开发-游戏设置功能的实现
可以看出这个功能场景的控件就三种类型,一个是菜单按钮——关闭按钮和保存按钮以及音乐和音效的开关按钮。而是精灵图片——背景图片等,三是滑动条的控件。因此此处我们需要学习的两个全新的控件就是滑动条的控件和开关按钮的控件,他们对应的Cocos2d-x的控件是:滑动条:ControlSlider,开关按钮MenuItemToggle。

0ControlSlider的用法

滑动条控件的组成分为三部分——互动的背景图,滑块,划过区域的图。看下他的关键源码:

ControlSlider.cpp
/*
继承自Control控件类,这个类有三个子类——ControlSlider(滑动条),ControlButton(按钮类,这个在后面会用到),ControlSwitch(开关类)。Control类为它的子类提供了一系列的触摸响应绑定的函数。具体参考Control的源码。
*/

class ControlSlider: public Control
{
public:
/** 通过一个背景图片,划过区域,滑块图片名称创建一个滑动条。
* Creates slider with a background filename, a progress filename and a
* thumb image filename.
*/

static ControlSlider* create(const char* bgFile, const char* progressFile, const char* thumbFile);

/** 通过一个背景图片精灵,划过区域精灵,滑块图片精灵创建一个滑动条
* Creates a slider with a given background sprite and a progress bar and a
* thumb item.
*
* @see initWithSprites
*/

static ControlSlider* create(Sprite * backgroundSprite, Sprite* pogressSprite, Sprite* thumbSprite);
// 以上两个方法仅仅是参数不同,但是第一个其实在方法内部也是使用的精灵实现的

/**
* Creates slider with a background filename, a progress filename, a thumb
* and a selected thumb image filename.
*/

static ControlSlider* create(const char* bgFile, const char* progressFile, const char* thumbFile,
const char* selectedThumbSpriteFile);

/** 多了一个选中的滑块的图片,下面方法一样
* Creates a slider with a given background sprite and a progress bar, a thumb
* and a selected thumb .
*
* @see initWithSprites
*/

static ControlSlider* create(Sprite * backgroundSprite, Sprite* pogressSprite, Sprite* thumbSprite,
Sprite* selectedThumbSprite);
/**
* @js ctor
*/

ControlSlider();
/**
* @js NA
* @lua NA
*/

virtual ~ControlSlider();

/** 初始化一个Slider使用参数中的精灵,各个参数的意义见下面的注释
* Initializes a slider with a background sprite, a progress bar and a thumb
* item.
*
* @param backgroundSprite Sprite, that is used as a background.
* @param progressSprite Sprite, that is used as a progress bar.
* @param thumbSprite Sprite, that is used as a thumb.
*/

virtual bool initWithSprites(Sprite * backgroundSprite, Sprite* progressSprite, Sprite* thumbSprite);

/**
* Initializes a slider with a background sprite, a progress bar and a thumb
* item.
*
* @param backgroundSprite Sprite, that is used as a background.
* @param progressSprite Sprite, that is used as a progress bar.
* @param thumbSprite Sprite, that is used as a thumb.
* @param selectedThumbSprite Sprite, that is used as a selected thumb.
*/

virtual bool initWithSprites(Sprite * backgroundSprite, Sprite* progressSprite, Sprite* thumbSprite,
Sprite* selectedThumbSprite);

virtual void needsLayout();
// 常用的API
virtual void setMaximumValue(float val); // 设置滑动的最大值
virtual void setEnabled(bool enabled); // 设置能否响应
virtual bool isTouchInside(Touch * touch);
Point locationFromTouch(Touch* touch);
virtual void setValue(float val); // 手动设置滑动条的值
virtual void setMinimumValue(float val); // 设置最小值
``````
// 更多方法请自查文档和源码
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

他的父类Control提供了一个绑定事件的函数如下:

/**
* Adds a target and action for a particular event to an internal dispatch
* table.
* The action message may optionnaly include the sender and the event as
* parameters, in that order.
* When you call this method, target is not retained.
*
* @param target The target object¡ªthat is, the object to which the action
* message is sent. It cannot be nil. The target is not retained.
* @param action A selector identifying an action message. It cannot be NULL.
* @param controlEvent A control event for which the action message is sent.
* See "CCControlEvent" for constants.
*/

void addTargetWithActionForControlEvent(Ref* target, Handler action, EventType controlEvent);
// 其中Eventype是Control的强枚举类型:这里需要使用的是VALUE_CHANGE数据变化
/** Kinds of possible events for the control objects. */
enum class EventType
{
TOUCH_DOWN = 1 << 0, // A touch-down event in the control.
DRAG_INSIDE = 1 << 1, // An event where a finger is dragged inside the bounds of the control.
DRAG_OUTSIDE = 1 << 2, // An event where a finger is dragged just outside the bounds of the control.
DRAG_ENTER = 1 << 3, // An event where a finger is dragged into the bounds of the control.
DRAG_EXIT = 1 << 4, // An event where a finger is dragged from within a control to outside its bounds.
TOUCH_UP_INSIDE = 1 << 5, // A touch-up event in the control where the finger is inside the bounds of the control.
TOUCH_UP_OUTSIDE = 1 << 6, // A touch-up event in the control where the finger is outside the bounds of the control.
TOUCH_CANCEL = 1 << 7, // A system event canceling the current touches for the control.
VALUE_CHANGED = 1 << 8 // A touch dragging or otherwise manipulating a control, causing it to emit a series of different values.
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

然后是MenuItemToggle的用法,这个控件的学习方法和上面一样,查看其源码就可以知道他的构造性方法和重要的API函数,我这里就不再带着大家走一遍了。 
下面是该界面的主要实现代码:

// 头文件
/*!
* \file SetLayer.h
* \date 2015/05/23 8:21
*
* \author SuooL
* Contact: hu1020935219@gmail.com
*
* \brief 设置场景,用来设置音效,音乐,音量等
*
* TODO: long description
*
* \note
*/



#ifndef __SetLayer__H__
#define __SetLayer__H__
#include "cocos2d.h"
#include "extensions/cocos-ext.h"

USING_NS_CC;
using namespace cocos2d::extension;

class SetLayer : public Layer {
public:
static Scene* createScene();
virtual bool init();
CREATE_FUNC(SetLayer);

void changeMusicVol(Ref* pSender, Control::EventType type);
void changeEffectVol(Ref* pSender, Control::EventType type);
void saveSet(Ref* pSender);
void closeBtn(Ref* pSender);
void musicSet(Ref* pSender);
void effectSet(Ref* pSender);
};
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

实现代码

Scene* SetLayer::createScene()
{
Scene* setScene = Scene::create();
SetLayer* layer = SetLayer::create();
setScene->addChild(layer);
return setScene;
}

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

float music = getFloatFromXML(MUSICVOL)*100.0f;
float effect = getFloatFromXML(SOUNDVOL)*100.0f;
// 背景精灵和关闭,保存按钮初始化
auto BG = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("image-0.png"));
BG->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
//BG->setColor(cocos2d::ccGRAY);

auto bgInterface = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("BGPicSet.png"));
bgInterface->setPosition(WINSIZE.width / 2 + 50, WINSIZE.height / 2);

auto closeBtn = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("closeSetNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("closeSetSelected.png")), CC_CALLBACK_1(SetLayer::closeBtn, this));
closeBtn->setPosition(WINSIZE.width - 150, WINSIZE.height - 100);


auto saveBtn = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("SaveSettings.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("SaveSettings.png")), CC_CALLBACK_1(SetLayer::saveSet, this));
saveBtn->setPosition(WINSIZE.width/2+40, WINSIZE.height / 2 - 190);
// 音乐开关按钮
auto musicOn = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("unchecked.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("unchecked.png")));
auto musicOff = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("Hook.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("Hook.png")));
// 音效开关按钮
auto effectOn = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("unchecked.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("unchecked.png")));
auto effectOff = MenuItemSprite::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("Hook.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("Hook.png")));

auto musicToggle = MenuItemToggle::createWithTarget(this, menu_selector(SetLayer::musicSet), musicOn, musicOff, NULL);
musicToggle->setPosition(369.5, 457);
auto effectToggle = MenuItemToggle::createWithTarget(this, menu_selector(SetLayer::effectSet), effectOn, effectOff, NULL);
effectToggle->setPosition(369.5, 357);
// 根据当前的音乐和音效状态设置开关按钮的初始化状态
if (getBoolFromXML(MUSIC_KEY))
{
musicToggle->setSelectedIndex(1);
}
else
{
musicToggle->setSelectedIndex(0);
}
if (getBoolFromXML(SOUND_KEY))
{
effectToggle->setSelectedIndex(1);
}
else
{
effectToggle->setSelectedIndex(0);
}
// 封装MenuItem到Menu并添加到场景中来
auto menu = Menu::create(closeBtn, saveBtn, musicToggle, effectToggle, NULL);
menu->setPosition(Point::ZERO);
// 初始化创建滑动条控件
auto musicSlider = ControlSlider::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bgBar.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("progressBar.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("ThumbBtn.png")));
// 绑定回调函数
musicSlider->addTargetWithActionForControlEvents(this, cccontrol_selector(SetLayer::changeMusicVol), Control::EventType::VALUE_CHANGED);
auto effectSlider = ControlSlider::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bgBar.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("progressBar.png")), Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("ThumbBtn.png")));
// 绑定回调函数
effectSlider->addTargetWithActionForControlEvents(this, cccontrol_selector(SetLayer::changeEffectVol), Control::EventType::VALUE_CHANGED);
// 设置滑动条控件的基本属性
musicSlider->setPosition(800, 457);
musicSlider->setMinimumValue(0.0f);
musicSlider->setMaximumValue(100.0f);
musicSlider->setMinimumAllowedValue(0.0f);
musicSlider->setMaximumAllowedValue(100.0f);

musicSlider->setValue(music);
effectSlider->setPosition(800, 357);
effectSlider->setMinimumValue(0.0f);
effectSlider->setMaximumValue(100.0f);
effectSlider->setMinimumAllowedValue(0.0f);
effectSlider->setMaximumAllowedValue(100.0f);
effectSlider->setValue(effect);
// 将控件添加到场景中
this->addChild(BG);
this->addChild(bgInterface);
this->addChild(musicSlider);
this->addChild(effectSlider);
this->addChild(menu);

return true;

}

// 滑动条控件的回调函数
void SetLayer::changeMusicVol(Ref* pSender, Control::EventType type)
{
auto temp = (ControlSlider*)pSender;
setFloatToXML(MUSICVOL, temp->getValue()/100.0f);
UserDefault::getInstance()->flush();
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
}

void SetLayer::changeEffectVol(Ref* pSender, Control::EventType type)
{
auto temp = (ControlSlider*)pSender;
setFloatToXML(SOUNDVOL, temp->getValue()/100.0f);
UserDefault::getInstance()->flush();
aduioEngine->setEffectsVolume(getFloatFromXML(SOUNDVOL));
}

// 菜单按钮的回调函数
void SetLayer::closeBtn(Ref* pSender)
{
PLAYEFFECT;
Director::getInstance()->replaceScene(StartLayer::createScene());
}


void SetLayer::saveSet(Ref* pSender)
{
PLAYEFFECT;
Director::getInstance()->replaceScene(StartLayer::createScene());
}
// 开关按钮的回调函数
void SetLayer::musicSet(Ref* pSender)
{
auto musicTemp = (MenuItemToggle*)pSender;
PLAYEFFECT;
if (musicTemp->getSelectedIndex() == 0)
{
setBoolToXML(MUSIC_KEY, false);
UserDefault::getInstance()->flush();
SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
else
{
setBoolToXML(MUSIC_KEY, true);
UserDefault::getInstance()->flush();
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
}

void SetLayer::effectSet(Ref* pSender)
{
auto effectTemp = (MenuItemToggle*)pSender;
if (effectTemp->getSelectedIndex() == 0)
{
setBoolToXML(SOUND_KEY, false);
UserDefault::getInstance()->flush();
}
else
{
setBoolToXML(SOUND_KEY, true);
UserDefault::getInstance()->flush();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166

以上就是设置功能场景的基本实现,其所使用的新的内容首先是UserDefault类保存和读取用户的数据,然后是ControlSlider类和MenuItemToggle类。