Thật sự là khó để tìm thấy lỗi trong mã của bạn khi bạn đang tìm kiếm chúng, thậm chí còn khó khăn hơn khi bạn giả định mã của bạn có lỗi. Donald Knuth
STDIO Trong quá trình xây dựng và phát triển lại Sins. Bản thân tôi và nhóm phát triển luôn được học tập và phát triển về kiến thức lập trình game, đặc biệt là với Cocos2d-x 3.x.x. Trong bài viết này, tôi sẽ hướng dẫn về một kỹ thuật mà chúng tôi đang sử dụng để xây dựng và thiết kế, đặc biệt trong Menu Game.
Nội dung bài viết

Giới thiệu

Với một Menu có đây đủ những thông tin, sự tương tác của người chơi với game, nội dung, ...và cách thiết kế vô cùng đặc sắc. Trong bài viết này, tôi sẽ giới thiệu cho các bạn một kỹ thuật được sử dụng trong game là Popup Component.

ss_1

Trong bài viết này, tôi sử dụng Windowns 10, Cocos2d-x 3.8 Microsoft Visual Stdio Ultillmate 2013.

Đặt vấn đề

Trong Menu Game Sins gồm một số các thành phần (Component) như sau:

  • Cài đặt (Setting): PopupSetting
  • Thông tin (About): PopupAbout
  • Bộ sưu tập (Remuneration): PopupRemuneration

ss_2

Ý tưởng

Khi người chơi chọn một trong các Button Options (Ở phía dưới góc trái). Thì sẽ xuất hiện các Popup tương ứng với chức năng của mỗi Button đi từ ngoài phía bên phải vào. Và khi người chơi muốn thoát khỏi Popup hiện tại, sẽ có một Button Back và rồi các Popup tương ứng sẽ đi vào trong (Từ trái sang phải).

Hiện thực

Tất cả các thành phần (Components) ở trên đều có chung một số thành phần như là Background, Title, và các hiệu ứng xuất hiện (Appear), biến mất (Disappear).

Một số kiến thức liên quan, bạn có thể tham khảo chi tiết tại các bài viết:

Popup class

Header

///@ Popup.h
#ifndef __SINS_POPUP_H__
#define __SINS_POPUP_H__

#include "string"

#include "cocos2d.h"
#include "ui/CocosGUI.h"

#include "Config.h" 
#include "Resources.h"

using namespace cocos2d::ui;

USING_NS_CC;

class Popup : public Node 
{
public:
    CREATE_FUNC(Popup);

    virtual bool init();
    virtual void onExit();

    virtual void disappear();
    virtual void appear();

    virtual void setTitlePopup(std::string _titlePopup);

protected:
    Layer                       *m_popupLayer;

    Size                        backgroundContentSize;
    Size                        visibleSize;
    Point                       origin;

    ActionInterval              *m_appearAction;
    ActionInterval              *m_disappearAction;

private:
};

#endif /* defined (__SINS_POPUP_H__) */

Phân tích

Trong class này, bạn cần quan tâm tới những điều sau:

  • appear(): Đây là phương thức được gọi tới khi một Popup cần xuất hiện.
  • disappear(): Đây là phương thức được gọi tới khi một Popup cần biến mất.
  • m_popupLayer: Đây là nơi chứa các thành phần riêng biệt của mỗi Popup. 

Source

///@ Popup.cpp
#include "Popup.h"

bool Popup::init()
{
	if (!Node::init()) return false;

	m_visibleSize = Director::getInstance()->getVisibleSize();
	m_origin = Director::getInstance()->getVisibleOrigin();
    
	m_popupLayer = Layer::create();
	m_popupLayer->setAnchorPoint(Vec2::ZERO);
	m_popupLayer->setPosition(Vec2(m_visibleSize.width + m_origin.x, m_origin.y));
	addChild(m_popupLayer);
   
    auto _background = Sprite::create(SPR_RES_PATH[SPR_BACKGROUND_POPUP]);
    _background->setAnchorPoint(Vec2::ZERO);
    _background->setPosition(Point::ZERO);
    m_popupLayer->addChild(_background);  

    backgroundContentSize = _background->getContentSize()

	m_appearAction = TargetedAction::create(m_popupLayer,
                     MoveTo::create(POPUP_FADING_TIME,
                     Vec2(m_visibleSize.width - backgroundContentSize.width + m_origin.x, m_origin.y)));
	
    m_disappearAction = TargetedAction::create(m_popupLayer,
		             MoveTo::create(POPUP_FADING_TIME,
                     Vec2(m_visibleSize.width + m_origin.x, m_origin.y)));

	m_appearAction->retain();
	m_disappearAction->retain();
	
	return true;
}

void Popup::disappear() 
{
	this->runAction(m_disappearAction->clone());
}

void Popup::appear() 
{
	this->runAction(m_appearAction->clone());	
}

void Popup::setTitlePopup(std::string _titlePopup) 
{
	auto _title = Label::createWithBMFont(
                     FNT_RES_PATH[FNT_EN_COMMON],
                     Singleton<LanguageManager>::getInstance()->getStringForKey(_titlePopup).c_str());
	
    _title->setAdditionalKerning(7.0f);
	_title->setPosition(Point(backgroundContentSize.width / 2 + m_origin.x,
                     backgroundContentSize.height * 8 / 10 + m_origin.y));

    _title->setColor(COLOR_TEXT_YELOW);
	_title->setScale(1.5f);

    m_popupLayer->addChild(_title);
}

void Popup::onExit() 
{ 
    m_appearAction->release(); 
    m_disappearAction->release(); 
    
    Node::onExit(); 
}

PopupSetting

Header

///@ PopupSetting.h
#ifndef __POPUP_SETTING_H__
#define __POPUP_SETTING_H__

#include "Popup.h"

enum 
{
    eSldMusic = 0,
    eSldSound
};

class PopupSetting : public Popup 
{
public:
	CREATE_FUNC(PopupSetting);

	bool init();
	virtual void onExit();

	void sliderEvent(Ref *pSender, Slider::EventType type);
	void checkBoxSelectedEvent(Ref* pSender, CheckBox::EventType type);

	void changeVolumeOfAudio(int _typeAudio, float _valueVolume);

protected:
private:
	CheckBox					*m_checkboxMuteAllSound;
	Slider						*m_sliderOptionMusics[2];
};

#endif /* defined (__POPUP_SETTING_H__) */

Source

///@ PopupSetting.cpp
#include "PopupSetting.h"

bool PopupSetting::init() 
{	
	if (!Popup::init()) 
		return false;
	
	setTitlePopup("STR_SETTING_TITLE");
	
	for (int index = 0; index < 2; index++) 
    {
		// label
		auto  _label = Label::createWithBMFont(FNT_RES_PATH[FNT_EN_COMMON], 
                              Singleton<LanguageManager>::getInstance()->getStringForKey(SRT_SETTING[index]).c_str());
		_label->setAdditionalKerning(7.0f);
		_label->setPosition(Vec2(backgroundContentSize.width / 2 + m_origin.x,
                backgroundContentSize.height * (7 - index*2) / 10 + m_origin.y));
		_label->setColor(COLOR_TEXT_YELOW);
		m_popupLayer->addChild(_label, Z_POPUP);

		// slider bar
		m_sliderOptionMusic[index] = Slider::create();
		m_sliderOptionMusic[index]->setTag(index); 

		m_sliderOptionMusic[index]->loadBarTexture(SPR_RES_PATH[SPR_SLIDEBAR_OFF]);
		m_sliderOptionMusic[index]->loadSlidBallTextures(SPR_RES_PATH[SPR_SLIDER_NODE_PRESS],
			                                             SPR_RES_PATH[SPR_SLIDER_NODE_NORMAL],
			                                             SPR_RES_PATH[SPR_SLIDER_NODE_DISABLE]);
		m_sliderOptionMusic[index]->loadProgressBarTexture(SPR_RES_PATH[SPR_SLIDEBAR_ON]);

		m_sliderOptionMusic[index]->setPosition(Vec2(backgroundContentSize.width / 2 + m_origin.x,
                                    backgroundContentSize.height * (6 - index * 2) / 10 + m_origin.y));
		m_sliderOptionMusic[index]->addEventListener(CC_CALLBACK_2(PopupSetting::sliderEvent, this));
		m_popupLayer->addChild(m_sliderOptionMusic[index], Z_POPUP);
	}

	/// init checkbox
	// label
	auto  _labelMuteAllSound = Label::createWithBMFont(FNT_RES_PATH[FNT_EN_COMMON], 
                               Singleton<LanguageManager>::getInstance()->getStringForKey("STR_SETTING_MUTEALLSOUND").c_str());
	_labelMuteAllSound->setAdditionalKerning(7.0f);
	_labelMuteAllSound->setPosition(Vec2(backgroundContentSize.width * 2 / 3 + m_origin.x,
                        backgroundContentSize.height * 1 / 4 + m_origin.y));
	_labelMuteAllSound->setColor(COLOR_TEXT_YELOW);
	m_popupLayer->addChild(_labelMuteAllSound, Z_POPUP);

	// checkbox
	m_checkboxMuteAllSound = CheckBox::create(SPR_RES_PATH[SPR_CHECKBOX_NORMAL],
											  SPR_RES_PATH[SPR_CHECKBOX_NORMAL_PRESS],
											  SPR_RES_PATH[SPR_CHECKBOX_ACTIVE],
											  SPR_RES_PATH[SPR_CHECKBOX_NORMAL_DISABLE],
											  SPR_RES_PATH[SPR_CHECKBOX_ACTIVE_DISABLE]);
	m_checkboxMuteAllSound->setPosition(Vec2(backgroundContentSize.width * 1 / 3 + m_origin.x,
                            backgroundContentSize.height * 1 / 4 + m_origin.y));
	m_checkboxMuteAllSound->addEventListener(CC_CALLBACK_2(PopupSetting::checkBoxSelectedEvent, this));
	m_popupLayer->addChild(m_checkboxMuteAllSound, Z_POPUP);

	return true;
}

void PopupSetting::sliderEvent(Ref *pSender, Slider::EventType type) 
{
	switch (type)
    {
	case Slider::EventType::ON_PERCENTAGE_CHANGED:
    {
		Slider* _slider = dynamic_cast<Slider*>(pSender);
		float _valueVolume = float(_slider->getPercent()) / 100;
		changeVolumeOfAudio(_slider->getTag(), _valueVolume);
        break;
    }
    default:
        break;
	}
}

void PopupSetting::checkBoxSelectedEvent(Ref* pSender, CheckBox::EventType type) 
{	
	switch (type)
	{
	case CheckBox::EventType::SELECTED:
    {
		m_sliderOptionMusic[eSldMusic]->setPercent(0);
		m_sliderOptionMusic[eSldSound]->setPercent(0);
		
		// m_audio->setEffectsVolume(0.0f);
		// m_audio->setBackgroundMusicVolume(0.0f);
		break;
    }
	case CheckBox::EventType::UNSELECTED:
    {
		m_sliderOptionMusic[eSldSound]->setPercent(50);
		m_sliderOptionMusic[eSldMusic]->setPercent(50);
			
		//m_audio->setEffectsVolume(0.5f);
		//m_audio->setBackgroundMusicVolume(0.5f);
		break;
    }
	default:
		break;
	}
}

void PopupSetting::changeVolumeOfAudio(int _typeAudio, float _valueVolume) 
{
	/* if (_typeAudio == eSldSound)
		m_audio->setEffectsVolume(_valueVolume);
	else
		m_audio->setBackgroundMusicVolume(_valueVolume); */
}

void PopupSetting::onExit() 
{
    Popup::onExit(); 
}

Sử dụng Popup trong Scene

Khởi tạo

#include "PopupSetting.h"

...

PopupSetting  *m_popupSetting = PopupSetting::create();
m_popupSetting->retain();

addChild(m_popupSetting);

Khi click vào Button Setting trong Menu Game sẽ xuất hiện Popup Setting.

m_btnSetting = Button::create(SPR_BUTTON_SHORT[SPR_BUTTON_NORMAL_SHORT],
                              SPR_BUTTON_SHORT[SPR_BUTTON_SELECT_SHORT],
                              SPR_BUTTON_SHORT[SPR_BUTTON_DISABLE_SHORT]);

m_btnSetting->setAnchorPoint(Vec2::ZERO);
m_btnSetting->setPosition(Vec2::ZERO);
m_btnSetting->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
        switch (type)
        {
                case ui::Widget::TouchEventType::BEGAN:
                        break;
                case ui::Widget::TouchEventType::ENDED:
                       m_popupSetting->appear();
                        break;
                default:
                        break;
        }
});

addChild(m_btnSetting , Z_POPUP_BACKGROUND);

Khi cick vào Button Back trong Menu Game thì Popup Setting sẽ mất đi.

m_btnBack ->addTouchEventListener([&](Ref* sender, Widget::TouchEventType type) {
        switch (type)
        {
                case ui::Widget::TouchEventType::BEGAN:
                        break;
                case ui::Widget::TouchEventType::ENDED:
                        m_popupSetting->disappear();
                        break;
                default:
                        break;
        }
});

ss_3

Download

Dưới đây là các demo về Popup.

CLASSES

RESOURCE

Bạn cần hỗ trợ các dự án kết nối không dây?

Quí doanh nghiệp, cá nhân cần hỗ trợ, hợp tác các dự án IoT, kết nối không dây. Vui lòng liên hệ, hoặc gọi trực tiếp 0942.111912.

  • TỪ KHÓA
  • Arduino
  • ESP32
  • ESP8266
  • Wifi
  • Bluetooth
  • Zigbee
  • Raspberry Pi
THẢO LUẬN
ĐÓNG