在开发游戏的时候我们经常需要在层与层之间、场景与场景之间传递数据和消息,Cocos2dx框架应用观察者模式为我们封装了一个CCNotificationCenter类,也叫消息通知中心,它也是一个单例类。

什么是观察者模式?看我的另一篇文章:设计模式C++实现——观察者模式

从观察者模式来讲,CCNotificationCenter类是观察者模式中的目标对象(主题),而CCNotificationObserver则是观察者。一个目标对象可以注册多个观察者,当目标对象的状态改变的时候,可以通知观察者对象作出相应的反应,这是标准的观察者模式的实现。但是CCNotificationCenter稍微有些许差别,CCNotificationCenter不是通过自身状态改变来通知观察者,而是通过显式地发送观察者感兴趣的消息来通知它们,消息名称则是用来标识观察者是否感兴趣。每次消息传递给CCNotificationCenter,CCNotificationCenter就会遍历所有的观察者,找到注册了该消息标识符的观察者,然后将消息发送给它们。

下面看一下这个类的API:

/** 获取CCNotificationCenter的单例类 */
static CCNotificationCenter *sharedNotificationCenter(void); /** 销毁CCNotificationCenter的单例类 */
static void purgeNotificationCenter(void); /** 将一个特定的对象添加为观察者
* target: 注册为观察者的对象
* selector: 当收到指定消息时的回调函数
* name: 消息名称,唯一标识符
* obj: 传递给回调函数的额外的参数
*/
void addObserver(CCObject *target,
SEL_CallFuncO selector,
const char *name,
CCObject *obj); /** 移除观察者 */
void removeObserver(CCObject *target,const char *name); /** 移除所有观察者 */
int removeAllObservers(CCObject *target); /** 发送不带数据的消息 */
void postNotification(const char *name); /** 发送带数据的消息 */
void postNotification(const char *name, CCObject *object);

上一篇说到使用CCTableView类实现了好友列表,然后我们需要创建一个好友详细信息的界面,当在列表中点击某个好友时,跳转到详细界面显示该好友的详细信息。这个时候就需要在两个层(或者说两个场景)之间传递数据,下面我们做一下小测试:

首先新建一个好友详细信息场景,并添加为观察者,以监听消息:

FriendDetailScene.h

#ifndef __FRIEND_DETAIL_SCENE_H__
#define __FRIEND_DETAIL_SCENE_H__ #include "cocos2d.h"
#include "cocos-ext.h" class FriendDetail : public cocos2d::CCLayer
{
public:
FriendDetail();
~FriendDetail();
virtual bool init(); static cocos2d::CCScene* scene(); void backToPrior(CCObject* pSender); void getMessage(CCObject* obj); CREATE_FUNC(FriendDetail);
}; #endif

FriendDetailScene.cpp

#include "FriendDetailScene.h"

USING_NS_CC;
USING_NS_CC_EXT; FriendDetail::FriendDetail()
{ } FriendDetail::~FriendDetail()
{
CCNotificationCenter::sharedNotificationCenter()->purgeNotificationCenter(); // 释放通知中心对象
} CCScene* FriendDetail::scene()
{
CCScene *scene = CCScene::create();
FriendDetail *layer = FriendDetail::create();
scene->addChild(layer);
return scene;
} bool FriendDetail::init()
{
if ( !CCLayer::init() )
{
return false;
} CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); // 背景
CCSprite* pSprite = CCSprite::create("IMG_Background.png");
pSprite->setPosition(ccp(visibleSize.width/2 + origin.x, visibleSize.height/2 + origin.y));
this->addChild(pSprite, 0); // 返回按钮
CCMenuItemImage *pBackItem = CCMenuItemImage::create(
"button1.png",
"button1.png",
this,
menu_selector(FriendDetail::backToPrior));
pBackItem->setPosition(680, 100);
CCMenu* pMenu = CCMenu::create(pBackItem, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, 1); // 接收消息
CCNotificationCenter::sharedNotificationCenter()->addObserver(this, callfuncO_selector(FriendDetail::getMessage), "selected_cell", NULL); return true;
} void FriendDetail::backToPrior(CCObject* pSender)
{
CCDirector::sharedDirector()->popScene();
} void FriendDetail::getMessage( CCObject* obj )
{
// 头像icon路径
std::string imagePath[10] = {"icon0.png","icon1.png","icon2.png","icon3.png","icon4.png","icon5.png","icon6.png","icon7.png","icon8.png","icon9.png"}; CCTableViewCell* cell = static_cast<CCTableViewCell*>(obj);
int idx = cell->getIdx(); CCSprite* iconSprite = CCSprite::create(imagePath[idx].c_str());
iconSprite->setPosition(ccp(400, 380));
this->addChild(iconSprite);
}

从代码中可以看出,我们在init()初始化时注册了观察者,监听名为“selected_cell”的消息,当收到这个消息时,就会执行getMessage( CCObeject* obj )函数。一般接收通知的一方在接收完通知后需要removeObserver(移除监听)或者purgeNotificationCenter(销毁通知中心)。

然后我们就可以在好友列表层FriendListLayer的tableCellTouched( CCTableView* table, CCTableViewCell* cell )添加发送消息的相关代码:

void FriendListLayer::tableCellTouched( CCTableView* table, CCTableViewCell* cell )
{
//CCLOG("Cell touched at index: %i", cell->getIdx()+1);
// 一定要先注册监听,然后发送消息,这样才可以实现数据的传递。
CCScene* pScene = FriendDetail::scene();
CCDirector::sharedDirector()->pushScene(pScene); CCNotificationCenter::sharedNotificationCenter()->postNotification("selected_cell", (CCObject*)cell);
}

这里是将被点击的单元格cell传递过去,当FriendDetailLayer接收到cell时可以获取它的idx,这样就实现了数据的传递。

注意:如果改成下面这样将无法传递数据...

void FriendListLayer::tableCellTouched( CCTableView* table, CCTableViewCell* cell )
{
//CCLOG("Cell touched at index: %i", cell->getIdx()+1);
CCNotificationCenter::sharedNotificationCenter()->postNotification("selected_cell", (CCObject*)cell); CCScene* pScene = FriendDetail::scene();
CCDirector::sharedDirector()->pushScene(pScene);
}

因为添加监听(addObserver)和发送消息(postNotification)是有先后顺序的,一定要先注册监听,然后发送消息,这样才可以实现数据的传递。

测试效果:

【Cocos2dx游戏开发】CCNotificationCenter传递消息和数据的更多相关文章

  1. Cocos2d-x游戏开发中的消息机制:CCNotificationCenter的使用

    在HTML5游戏开发中,js可以使用Event对象的addEventListener(添加事件监听).dispatchEvent(触发事件)实现监听机制,如果在coocos2d-x中,去实现这种机制该 ...

  2. cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发

     cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发 的产生 视持续更新中.... 视频存放地址例如以下:http://ipd.pps.tv/user/1058663622     ...

  3. Cocos2dx游戏开发系列笔记13:一个横版拳击游戏Demo完结篇

    懒骨头(http://blog.csdn.net/iamlazybone QQ:124774397 ) 写下这些东西的同时 旁边放了两部电影 周星驰的<还魂夜> 甄子丹的<特殊身份& ...

  4. cocos2d-x游戏开发系列教程-前言

    cocos2d-x游戏开发前景: 最近企业对于Cocos2D-X开发人才的用人需求很大,而且所提供的薪资相当可观. 为满足广大向往游戏开发行业同学的需求,特推出适合新手的Cocos2D-X手游开发教程 ...

  5. cocos2d-x 游戏开发之有限状态机(FSM) (四)

    cocos2d-x 游戏开发之有限状态机(FSM) (四) 虽然我们了解了FSM,并且可以写自己的FSM,但是有更好的工具帮我们完成这个繁琐的工作.SMC(http://smc.sourceforge ...

  6. cocos2d-x 游戏开发之有限状态机(FSM) (三)

    cocos2d-x 游戏开发之有限状态机(FSM) (三) 有限状态机简称FSM,现在我们创建一个专门的FSM类,负责管理对象(Monkey)的状态.然后Monkey类就实现了行为与状态分离.Monk ...

  7. cocos2d-x 游戏开发之有限状态机(FSM) (一)

    cocos2d-x 游戏开发之有限状态机(FSM) (一) 参考:http://blog.csdn.net/mgphuang/article/details/5845252<Cocos2d-x游 ...

  8. cocos2d-x 游戏开发之有限状态机(FSM) (二)

    cocos2d-x 游戏开发之有限状态机(FSM)  (二) 1 状态模式

  9. 《Cocos2d-x游戏开发实战精解》学习笔记4--实战一个简单的钢琴

    上一节学习了使用Cocos2d-x播放音乐的方法,但是那种方法一般只适合于播放较大的音乐,而一般比较短小的音乐(如游戏中的打斗.按键音效等)则要通过playEffect来播放.本节使用该方法以及之前学 ...

随机推荐

  1. Android 新闻app的顶部导航栏,怎么实现动态加载?

    TabLayout + viewpager 其中viewpager的适配器要继承FragmentPagerAdapter,要实现动态更新,最主要的是适配器的写法,要在数据发生变化之后清除Fragmen ...

  2. Appium基于python unittest自动化测试并生成html测试报告

    本文基于python单元测试框架unittest完成appium自动化测试,生成基于html可视化测试报告 代码示例: #利用unittest并生成测试报告 class Appium_test(uni ...

  3. Verification Mind Games---how to think like a verifier像验证工程师一样思考

    1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题.具体来说,验证更加关心在严格遵循协议的基础上发现设计里面的bug,搜索corner cases,对设计的不一致要保持零容忍的态度. m ...

  4. 网络编程基础_3.APC队列

    APC队列 #include <stdio.h> #include <windows.h> // 保存 IO 操作的结果 CHAR Buffer1[] = { }; CHAR ...

  5. 这段代码很Pythonic | 相见恨晚的 itertools 库

    前言 最近事情不是很多,想写一些技术文章分享给大家,同时也对自己一段时间来碎片化接受的知识进行一下梳理,所谓写清楚才能说清楚,说清楚才能想清楚,就是这个道理了. 很多人都致力于把Python代码写得更 ...

  6. [Luogu] P4254 [JSOI2008]Blue Mary开公司

    题目背景 Blue Mary 最近在筹备开一家自己的网络公司.由于他缺乏经济头脑,所以先后聘请了若干个金融顾问为他设计经营方案. 题目描述 万事开头难,经营公司更是如此.开始的收益往往是很低的,不过随 ...

  7. numpy.random模块常用函数解析

    numpy.random模块中常用函数解析 numpy.random模块官方文档 1. numpy.random.rand(d0, d1, ..., dn)Create an array of the ...

  8. MySQL数据库开启、关闭、查看函数功能的方法

    应用 MySQL 时,会遇到不能创建函数的情况.出现如下错误信息: ERROR 1418 : This function has none of DETERMINISTIC, NO SQL, or R ...

  9. Linux设置history命令显示行数以及时间

    Linux和unix上都提供了history命令,可以查询以前执行的命令历史记录但是,这个记录并不包含时间项目因此只能看到命令,但是不知道什么时间执行的如何让history记录时间呢? 解决方案 注意 ...

  10. 访问请求参数request.getParameter()

    访问请求参数request.getParameter() 制作人:全心全意 getParameter() 例: 传递参数页: <%@ page language="java" ...