Cocos2d-x觀察者模式其實很簡單!!--之遊戲開發《趙雲要格鬥》(13),趙雲要格鬥
這裡是Evankaka的部落格,歡迎大家前來討論與交流~~~~~~
轉載請註明出處http://blog.csdn.net/evankaka
本文主要詳細講解了設計模式中的觀察都模式及其在Coco2d-x的簡單應用,最後,結合遊戲中的技能冷卻類放大招進行了一個使用。
cocos2d-x版本:2.2.5
工程環境:windows7+VS2010
開啟檔案:將工程放在cocos2d-x安裝目錄下的project檔案夾下用VS開啟
先來看看效果:
本文效果:
一、觀察者模式簡介
觀察者模式(有時又被稱為發布/訂閱模式)是軟體設計模式的一種。在此種模式中,一個目標對象管理所有相依於它的觀察者對象,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實作事件處理系統。我的另一篇博文,24天學會設計模式------觀察者模式,這裡有更加詳細的介紹,有興趣可以看這裡。
在開發遊戲的時候我們經常需要在層與層之間、情境與情境之間傳遞資料和訊息,Cocos2dx架構應用觀察者模式為我們封裝了一CCNotificationCenter類,也叫訊息通知中樞,它也是一個單例類。
從觀察者模式來講,CCNotificationCenter類是觀察者模式中的目標對象(主題),而CCNotificationObserver則是觀察者。一個目標對象可以註冊多個觀察者,當目標對象的狀態改變的時候,可以通知觀察者對象作出相應的反應,這是標準的觀察者模式的實現。但是CCNotificationCenter稍微有些許差別,CCNotificationCenter不是通過自身狀態改變來通知觀察者,而是通過顯式地發送觀察者感興趣的訊息來通知它們,訊息名稱則是用來標識觀察者是否感興趣。每次訊息傳遞給CCNotificationCenter,CCNotificationCenter就會遍曆所有的觀察者,找到註冊了該訊息標識符的觀察者,然後將訊息發送給它們。
實現步驟:
1、添加觀察者:
在任何地方,只要你你對某個訊息感興趣(和pureMVC中的listNotification一樣),你就可以在那裡監聽該訊息。
void addObserver(CCObject* target,SEL_CallFuncO callBack,const char* name, CCObject* data);
參數1為事件監聽的目標,參數2為回呼函數(即接收到訊息後執行的函數),參數3為訊息名,參數4為訊息體。
具體實現如下:
CCNotificationCenter::sharedNotificationCenter()->addObserver(this,
callfunco_selector(GameLayer::callBack),
name,
NULL
2、發送訊息:在需要發送訊息的地方,調用postNotification方法即可,postNotification有兩種,可以不帶資料和帶資料。
void postNotification(const char* name);void postNotification(const char* name,CCObject* data);
name是訊息名,是訊息唯一標識,在整個遊戲過程中是唯一的,因此,我們一般把所有的訊息名放在一個標頭檔中,紡織訊息名重複,data是訊息體,即發送的資料。
發送通知如下:
CCNotificationCenter::sharedNotificationCenter()->postNotification(name);
3、釋放訊息觀察者:
釋放訊息觀察者是很重要的,不釋放的話,會產生記憶體泄露。我們需要在解構函式方法裡面,釋放訊息觀察者。
CCNotificationCenter::sharedNotificationCenter()->removeObserver(
this,
name //訊息名
}
二、使用範例1、一個層內使用觀察者模式
首先,建立一個HelloWord的工程,然後HelloWorldScene.h添加
<span style="font-size:18px;">//添加目標式通知觀察者之後調用的事件void ObserverFunction(CCObject * object);</span>
開啟HelloWorldScene.cpp,在init()函數添加
//註冊Message,如果接收到了,執行ObserverFunctionCCNotificationCenter::sharedNotificationCenter()->addObserver(this,callfuncO_selector(HelloWorld::ObserverFunction),"Message",NULL);
然後HelloWorld::~HelloWorld()添加:
//注意最後一定要釋放訊息,否則內容泄露 CCNotificationCenter::sharedNotificationCenter()->removeObserver(this,"Message");
再實現函數:
//添加目標式通知觀察者之後調用的事件void HelloWorld::ObserverFunction(CCObject * object){CCLOG("You Click menuButton");}
接下來就可以給觀察都通知事件 了~,這裡我直接把項目的menu按鈕的事件(它原本是退出的)改成:
//第一個參數是訊息的名字,第二個參數是CCObject * 類型的訊息值,也就是你要發送的東西CCNotificationCenter::sharedNotificationCenter()->postNotification("Message",NULL);
看看效果:
觀察都模式不僅可以通知更新,也可以傳遞資料 ,下面來看看第2個例子
2、兩個不同的層使用觀察都模式
(1)首先,還是建立一個HelloWord工程,然後建立一個層類 SecondLayer
標頭檔 SecondLayer.h
<span style="font-size:18px;">#ifndef __SecondLayer_SCENE_H__#define __SecondLayer_SCENE_H__#include "cocos2d.h"class SecondLayer : public cocos2d::CCLayer{public: virtual bool init(); ~SecondLayer(); static cocos2d::CCScene* scene(); CREATE_FUNC(SecondLayer);//添加目標式通知觀察者之後調用的事件void ObserverFunction(CCObject * object);};#endif // __SecondLayer_SCENE_H__</span>
實現檔案SecondLayer.cpp
#include "SecondLayer.h"USING_NS_CC;CCScene* SecondLayer::scene(){ CCScene *scene = CCScene::create(); SecondLayer *layer = SecondLayer::create(); scene->addChild(layer); return scene;}SecondLayer::~SecondLayer(){//注意最後一定要釋放訊息,否則內容泄露CCNotificationCenter::sharedNotificationCenter()->removeObserver(this,"Message");}bool SecondLayer::init(){ if ( !CCLayer::init() ) { return false; }//註冊Message,如果接收到了,執行ObserverFunctionCCNotificationCenter::sharedNotificationCenter()->addObserver(this,callfuncO_selector(SecondLayer::ObserverFunction),"Message",NULL); return true;}//添加目標式通知觀察者之後調用的事件void SecondLayer::ObserverFunction(CCObject * object){CCLOG("SecondLayer Receive num=%d",(int)object);}
(2)使用
HelloWorldScene.cpp中添加標頭檔 #include "SecondLayer.h"
init()函數中添加:
SecondLayer* second=SecondLayer::create();this->addChild(second,0);
改寫項目menu按鈕的事件:
void HelloWorld::menuCloseCallback(CCObject* pSender){int num=CCRANDOM_0_1()*1000;//0-1000的隨機數CCNotificationCenter::sharedNotificationCenter()->postNotification("Message",(CCObject *)num);//向觀察者傳遞資料}(3)效果:
看到了吧,SenondLayer類可以收到目標發給它的訊息了啦!
三、《趙雲要格鬥》中使用觀察者模式
前面我們設計了一個技能冷卻的類,不懂看這裡Cocos2d-x技能冷卻還要等多久?---之遊戲開發《趙雲要格鬥》(9),它是一個層類,現在我們要實現我們一旦按下特殊技術的按鈕,趙雲就要釋放特殊技術(放大招),這裡我的思路是在英雄類(即趙雲)中設定成一個觀察者,一旦觀察到按下了特殊技術的按鈕,而且技能不在冷卻,那麼趙雲就停下所有動作,直接放大招。
英雄類標頭檔 Hero.h中添加
//技能特效 void SkillAmiation(CCObject * object);//注意要有參數,因為是觀察者模式的調用函數,要不會提示“類型轉換”: 無法從“void (__thiscall Hero::* )(void)”轉換為“cocos2d::SEL_CallFuncO”
英雄類實現檔案 Hero.cpp中初始化英雄InitHeroSprite(char *hero_name)函數中添加
//註冊MessageSkill,如果接收到了,執行SkillAmiationCCNotificationCenter::sharedNotificationCenter()->addObserver(this,callfuncO_selector(Hero::SkillAmiation),"MessageSkill",NULL);
一旦觀察到技能按鈕按下,調用函數:
//技能特效void Hero::SkillAmiation(CCObject * object){m_HeroSprite->stopAllActions();//當前精靈停止所有動畫CCAnimation* animation = CCAnimation::create(); for( int i=1;i<=6;i++) { char szName[100] = {0}; sprintf(szName,"skill_%d.png",i); animation->addSpriteFrameWithFileName(szName); //載入動畫的幀 } animation->setDelayPerUnit(0.1f); animation->setRestoreOriginalFrame(true); animation->setLoops(5); //動畫迴圈//將動畫封裝成一個動作CCAnimate* act=CCAnimate::create(animation);//建立回調動作,攻擊結束後調用AttackEnd()CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(Hero::AttackEnd));//建立連續動作CCActionInterval* skillattack=CCSequence::create(act,callFunc,NULL); IsAttack=true;m_HeroSprite->runAction(skillattack);}
最後記得要釋放:
Hero::~Hero(void){//注意最後一定要釋放訊息,否則內容泄露 CCNotificationCenter::sharedNotificationCenter()->removeObserver(this,"MessageSkill");}然後在SkillButton.cpp的BeginSkill()函數中,這個類可以看Cocos2d-x技能冷卻還要等多久?---之遊戲開發《趙雲要格鬥》(9)
添加一句:
//第一個參數是訊息的名字,第二個參數是CCObject * 類型的訊息值,也就是你要發送的東西CCNotificationCenter::sharedNotificationCenter()->postNotification("MessageSkill",NULL);
好了,Ok,:
四、再說觀察者模式1、優點:
實現了目標對象和觀察者之間的抽象耦合,在本例中,則是實現了訊息與觀察者的抽象耦合。可以定義一種訊息與訊息處理對象的一對多的關係,而不用擔心彼此的實現細節。
2、缺點
如果一個被觀察者對象有很多的直接和間接的觀察者的話,將所有的觀察者都通知到會花費很多時間。
3、適用場合
(1)一個抽象模型有兩個方面,其中一個方面依賴於另一個方面。將這些方面封裝在獨立的對象中使它們可以各自獨立地改變和複用。
(2)一個對象的改變將導致其他一個或多個對象也發生改變,而不知道具體有多少對象將發生改變,可以降低對象之間的耦合度。
(3)一個對象必須通知其他對象,而並不知道這些對象是誰。需要在系統中建立一個觸發鏈,A對象的行為將影響B對象,B對象的行為將影響C對象……,可以使用觀察者模式建立一種鏈式觸發機制。
更多的觀察都模式講解可以看24天學會設計模式------觀察者模式
後記:
這幾天好冷,寫個好的博文不容易啊。這文章都趟我草稿箱好久了啊,又寫代碼又寫文字的又,GIF動畫還不能超2M,我都不知重新了多少張了!CSDN你這個功能要好好的改改下,遊戲中加了聲音了,可惜沒法傳上來聽。。。。看了兩晚的電影,這個遊戲都沒更新了,推薦大家去看《親愛的》(很感人的,要記得內建紙巾。。),《星球崛起》(1,2,拍得很好),《太極》(1,2,打得很舒服),美劇《摩登家庭》(很搞笑.)啦啦啦。我又廢話了,好久沒這麼多廢話了,這個遊戲要完結了,我也要轉到3.3了,下個遊戲出打飛機!