1. 程式人生 > >cocos2d-x 模態對話框的實現

cocos2d-x 模態對話框的實現

dir public item cti xtu priority net create instance

心情不好,恩。不扯淡了。直接講。


==================================

在泰然看了一篇實現模態對話框的文章,寫的還不錯,然後在其基礎上加了我簡單加了一層灰色透明背景,這樣子界面效果看起來會更友好一點。好吧,原諒我的無恥,原創轉載什麽的也不在意了,原文在這裏,今天感覺有點累,恩,主要是大神不能帶我飛了。非常是失落,好吧,不說廢話了。

在遊戲中,我們經常須要實現彈出一個模態對話框,比方說遊戲暫停,退出提示對話框等

對話框特點例如以下:


1.可定制的,比方說背景圖。標題,文本,按鈕等,依據須要加入和設置

2.須要屏蔽對話框下層的觸摸

3.為了友好的效果顯示。把不可觸摸的部分變為灰色


先來看一張效果圖:


技術分享圖片


為了完畢這樣一個效果。思路例如以下:


1.設計一個彈出對話框的類PopupLayer。繼承於LayerColor,這樣子我們就能夠設置背景版透明,看起來好像把對話框下層的變灰暗了


        setColor(ccc3(0,0,0));  
        setOpacity(128);  


2.加入觸摸事件。屏蔽下層觸摸。也就是在Layer中設置不向下傳遞

        //add layer touch event
	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);//不向下傳遞觸摸
	listener->onTouchBegan = CC_CALLBACK_2(PopupLayer::onTouchBegan, this);
	listener->onTouchMoved = CC_CALLBACK_2(PopupLayer::onTouchMoved, this);
	listener->onTouchEnded = CC_CALLBACK_2(PopupLayer::onTouchEnded, this);
	auto dispatcher = Director::getInstance()->getEventDispatcher();
	dispatcher->addEventListenerWithSceneGraphPriority(listener, this);

3.PopupLayer類 實現 可定制對話框標題,按鈕,文本。背景圖片等


    //標題
    void setTitle(const char* title, int fontsize = 20);
    //文本
    void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);
    //設置button回調事件
    void setCallbackFunc(Ref* target, SEL_CallFuncN callfun);
     //加入button
    bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);

4.按鈕回調函數實現也比較簡單。首先設置外部的回調對象和回調函數


    Ref* m_callbackListener;    //回調對象
    SEL_CallFuncN m_callback;   //回調函數

    //設置按鈕的回調函數
    void PopupLayer::setCallbackFunc(Ref* target, SEL_CallFuncN callfun){
    m_callbackListener = target;
    m_callback = callfun;  
    }


然後在PopupLayer類中比方說我們加入一個菜單按鈕


 // 創建圖片菜單按鈕
    auto item = MenuItemImage::create(
        normalImage,
        selectedImage,
        CC_CALLBACK_1(PopupLayer::buttonCallBack,this));
    item->setTag(tag);

設置button回調函數,然後由這個回調函數去調用外部的button監聽函數,然後關閉對話框


//button回調函數
    void PopupLayer::buttonCallBack(Ref* pSender){
    Node* node = dynamic_cast<Node*>(pSender);
    CCLog("【====PopupLayer::buttonCallBack====】touch tag: %d", node->getTag());
    if (m_callback && m_callbackListener){
        (m_callbackListener->*m_callback)(node);
    }
    this->removeFromParent();}


5.然後使用方法也比較簡單。假設須要對話框內容顯示中文。能夠參考:cocos2d-x 3.0 使用Sax解析xml文檔(解決中文顯示問題)這篇文章

    //彈出對話框
    pl = PopupLayer::create("BackGround.png",Size(400,350));
    pl->setTitle("title");
    pl->setContentText("Are you sure exit?", 20, 60, 250);
    pl->setCallbackFunc(this, callfuncN_selector(WelcomeScene::popButtonCallback));//設置按鈕回調
    pl->addButton("pop_button.png", "pop_button.png", "yes", 0);
    pl->addButton("pop_button.png", "pop_button.png", "no", 1);
    this->addChild(pl);

外部回調函數實現。依據tag推斷點了什麽按鈕


void WelcomeScene::popButtonCallback(Node *pNode){
    CCLog("【=====WelcomeScene::popButtonCallback======】button call back. tag: %d", pNode->getTag());
    //exit
    if(pNode->getTag() == 0){
        Director::getInstance()->end();
    }
}



恩。思路大概這樣子,完整的對話框類例如以下,親們能夠復制直接使用

#pragma once

#include "cocos2d.h"
#include "cocos-ext.h"

using namespace cocos2d;
using namespace cocos2d::extension;

class PopupLayer : public LayerColor{
public:
	PopupLayer();
	~PopupLayer();
	
	virtual bool init();
	CREATE_FUNC(PopupLayer);
	static PopupLayer* create(const char* backgroundImage,Size dialogSize);

	//touch事件監聽 屏蔽向下觸摸
	bool onTouchBegan(Touch *touch, Event *event);
	void onTouchMoved(Touch *touch, Event *event);
	void onTouchEnded(Touch* touch, Event* event);

	//標題
	void setTitle(const char* title, int fontsize = 20);
	//文本
	void setContentText(const char* text, int fontsize = 20, int padding = 50, int paddintTop = 100);
	//設置button回調事件
	void setCallbackFunc(Ref* target, SEL_CallFuncN callfun);
	//加入button
	bool addButton(const char* normalImage, const char* selectedImage, const char* title, int tag = 0);

	virtual void onEnter();
	virtual void onExit();

	void backgroundFinish();

private:
	
	void buttonCallBack(Ref* pSender);

	// 文字內容兩邊的空白區
	int m_contentPadding;
	int m_contentPaddingTop;

	Size m_dialogContentSize;

	Ref* m_callbackListener;
	SEL_CallFuncN m_callback;

	//set and get
	CC_SYNTHESIZE_RETAIN(Menu*, m__pMenu, MenuButton);
	CC_SYNTHESIZE_RETAIN(Sprite*, m__sfBackGround, SpriteBackGround);
	CC_SYNTHESIZE_RETAIN(Scale9Sprite*, m__s9BackGround, Sprite9BackGround);
	CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltTitle, LabelTitle);
	CC_SYNTHESIZE_RETAIN(LabelTTF*, m__ltContentText, LabelContentText);
};

cpp文件實現例如以下:


#include "PopupLayer.h"

PopupLayer::PopupLayer():
	m__pMenu(NULL)
	, m_contentPadding(0)
	, m_contentPaddingTop(0)
	, m_callbackListener(NULL)
	, m_callback(NULL)
	, m__sfBackGround(NULL)
	, m__s9BackGround(NULL)
	, m__ltContentText(NULL)
	, m__ltTitle(NULL)
{

}

PopupLayer::~PopupLayer(){
	CC_SAFE_RELEASE(m__pMenu);
	CC_SAFE_RELEASE(m__sfBackGround);
	CC_SAFE_RELEASE(m__ltContentText);
	CC_SAFE_RELEASE(m__ltTitle);
	CC_SAFE_RELEASE(m__s9BackGround);
}

bool PopupLayer::init(){
	if(!LayerColor::init()){
		return false;
	}
	// 初始化須要的 Menu
	Menu* menu = Menu::create();
	menu->setPosition(CCPointZero);
	setMenuButton(menu);

	//add layer touch event
	auto listener = EventListenerTouchOneByOne::create();
	listener->setSwallowTouches(true);
	listener->onTouchBegan = CC_CALLBACK_2(PopupLayer::onTouchBegan, this);
	listener->onTouchMoved = CC_CALLBACK_2(PopupLayer::onTouchMoved, this);
	listener->onTouchEnded = CC_CALLBACK_2(PopupLayer::onTouchEnded, this);
	auto dispatcher = Director::getInstance()->getEventDispatcher();
	dispatcher->addEventListenerWithSceneGraphPriority(listener, this);

	setColor(ccc3(0,0,0));  
	setOpacity(128);  

	return true;
}

bool PopupLayer::onTouchBegan(Touch *touch, Event *event){
	return true;
}

void PopupLayer::onTouchMoved(Touch *touch, Event *event){

}

void PopupLayer::onTouchEnded(Touch* touch, Event* event){

}

PopupLayer* PopupLayer::create(const char* backgroundImage, Size dialogSize){
	
	PopupLayer* layer = PopupLayer::create();
	
//	layer->setSpriteBackGround(Sprite::create(backgroundImage));
	layer->setSprite9BackGround(Scale9Sprite::create(backgroundImage));

	layer->m_dialogContentSize = dialogSize;

	return layer;
}

void PopupLayer::setTitle(const char* title, int fontsize /* = 20 */){
	LabelTTF* label = LabelTTF::create(title,"",fontsize);
	setLabelTitle(label);
}

void PopupLayer::setContentText(const char *text, int fontsize, int padding, int paddingTop){
	LabelTTF* ltf = LabelTTF::create(text, "", fontsize);
	setLabelContentText(ltf);
	m_contentPadding = padding;
	m_contentPaddingTop = paddingTop;
}

void PopupLayer::setCallbackFunc(Ref* target, SEL_CallFuncN callfun){
	m_callbackListener = target;
	m_callback = callfun;    
}

bool PopupLayer::addButton(const char* normalImage, const char* selectedImage, const char* title, int tag /* = 0 */){
	
	auto size = Director::getInstance()->getWinSize();
	auto center = Point(size.width / 2, size.height / 2);

	// 創建圖片菜單按鈕
	auto item = MenuItemImage::create(
		normalImage,
		selectedImage,
		CC_CALLBACK_1(PopupLayer::buttonCallBack,this));
	item->setTag(tag);
	item->setPosition(center);

	// 加入文字說明並設置位置
	Size itemSize = item->getContentSize();
	LabelTTF* ttf = LabelTTF::create(title, "", 20);
	ttf->setColor(Color3B(0, 0, 0));
	ttf->setPosition(Point(itemSize.width / 2, itemSize.height / 2));
	item->addChild(ttf);

	getMenuButton()->addChild(item);

	return true;
}

void PopupLayer::buttonCallBack(Ref* pSender){
	Node* node = dynamic_cast<Node*>(pSender);
	CCLog("【====PopupLayer::buttonCallBack====】touch tag: %d", node->getTag());
	if (m_callback && m_callbackListener){
		(m_callbackListener->*m_callback)(node);
	}
	this->removeFromParent();
}

void PopupLayer::onEnter(){
	LayerColor::onEnter();

	Size winSize = CCDirector::getInstance()->getWinSize();
	Point pCenter = Point(winSize.width / 2, winSize.height / 2);

//	Size contentSize ;
	// 設定好參數,在執行時載入
	//假設沒有設置 ContentSize 。那麽採取的方案是。窗體大小與傳入圖片一樣大
// 	if (getContentSize().equals(this->getParent()->getContentSize())) {
// 		getSpriteBackGround()->setPosition(ccp(winSize.width / 2, winSize.height / 2));
// 		this->addChild(getSpriteBackGround(), 0, 0);
// 		contentSize = getSpriteBackGround()->getTexture()->getContentSize();
// 	} else {
// 		Scale9Sprite *background = getSprite9BackGround();
// 		background->setContentSize(getContentSize());
// 		background->setPosition(ccp(winSize.width / 2, winSize.height / 2));
// 		this->addChild(background, 0, 0);
// 		contentSize = getContentSize();
// 	}
	//加入背景圖片
	Scale9Sprite *background = getSprite9BackGround();
	background->setContentSize(m_dialogContentSize);
	background->setPosition(Point(winSize.width / 2, winSize.height / 2));
	this->addChild(background,0,0);

	// 彈出效果
	Action* popupLayer = Sequence::create(
		ScaleTo::create(0.0, 0.0),
		ScaleTo::create(0.2, 1.05),
		ScaleTo::create(0.2, 0.95),
		ScaleTo::create(0.1, 1.0), 
		CallFunc::create(CC_CALLBACK_0(PopupLayer::backgroundFinish,this)),
		NULL
		);
	background->runAction(popupLayer);



}

void PopupLayer::backgroundFinish(){

	Size winSize = CCDirector::getInstance()->getWinSize();
	Point pCenter = Point(winSize.width / 2, winSize.height / 2);

	// 加入按鈕,並設置其位置
	this->addChild(getMenuButton());
	float btnWidth = m_dialogContentSize.width / (getMenuButton()->getChildrenCount() + 1);

	Vector<Node*> vector = getMenuButton()->getChildren();
	Ref* pObj = NULL;
	int i = 0;
	for(Node* pObj : vector){
		Node* node = dynamic_cast<Node*>(pObj);
		node->setPosition(Point( winSize.width / 2 - m_dialogContentSize.width / 2 + btnWidth * (i + 1), winSize.height / 2 - m_dialogContentSize.height / 3));
		i++;
	}

	// 顯示對話框標題
	if (getLabelTitle()){
		getLabelTitle()->setPosition(ccpAdd(pCenter, ccp(0, m_dialogContentSize.height / 2 - 35.0f)));
		this->addChild(getLabelTitle());
	}

	// 顯示文本內容
	if (getLabelContentText()){
		CCLabelTTF* ltf = getLabelContentText();
		ltf->setPosition(ccp(winSize.width / 2, winSize.height / 2));
		ltf->setDimensions(CCSizeMake(m_dialogContentSize.width - m_contentPadding * 2, m_dialogContentSize.height - m_contentPaddingTop));
		ltf->setHorizontalAlignment(kCCTextAlignmentLeft);
		this->addChild(ltf);
	}
}



void PopupLayer::onExit(){

	CCLog("popup on exit.");
	CCLayerColor::onExit();
}


cocos2d-x 模態對話框的實現