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,如果接收到了,执行ObserverFunction
	CCNotificationCenter::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,如果接收到了,执行ObserverFunction
	CCNotificationCenter::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,如果接收到了,执行SkillAmiation
	CCNotificationCenter::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了,下个游戏出打飞机!

时间: 2024-10-13 00:05:33

Cocos2d-x观察者模式其实很简单--之游戏开发《赵云要格斗》(13)的相关文章

Cocos2d-x《赵云要格斗》游戏开源啦!要代码要资源就来!~~~~~~~~~~~~~~~~~~~~~

笔者自行开发的Cocos2d-x原创游戏<赵云要格斗>这里把全部的代码和资源全部共享,保证全部可以免费下载,笔者之前开发这个游戏的时就说过,此游戏最后一定会开源.游戏其实还没弄完,只是近期好多博友都在找笔者要代码要资源,笔者原本是想等游戏全部完成之后,再来公布的.现在打算提前点,笔者也认为社区大于代码,开源好于自己闭门造车.虽说笔者这游戏也很简单,代码有些地方也学有待完善,还是有很多地方需要增强.但是,笔者还是打算公布出来,而且要全部免费下载,论坛下载积分对我也没什么用,也希望下载后的人,有什

【Cocos2D研究院之游戏开发】

http://www.xuanyusong.com/archives/category/ios/cocos2d_game 分类目录归档:[Cocos2D研究院之游戏开发] 201211-19 Cocos2D研究院之打开全新ViewController与返回(八) 雨松MOMO [Cocos2D研究院之游戏开发] 围观5745次 17条评论          之前cocos2d的文章都是由魏凯同学维护,从今天开始我也会抽时间写点cocos2d的文章.最近在研究如何将IOS游戏与软件结合起来.通常游

Cocos2d-x显示中文与字幕滚动--之游戏开发《赵云要格斗》(14)

    这里是林炳文Evankaka的博客,欢迎大家前来讨论与交流------ 转载请注明出处http://blog.csdn.net/evankaka     本文将要解决Cocos2d-x中显示中文时出现乱码的情形,并且实现一个字幕滚动的功能,这个功能是通过遮罩来实现的. cocos2d-x版本:2.2.5 工程环境:windows7+VS2010 打开方式:将工程放在cocos2d-x安装目录下的project文件夹下用VS打开 先来看看效果: 在windows环境下使用visual st

【译】什么是游戏开发实体系统框架(一)

什么是游戏开发实体系统框架(一) 原文链接:http://www.richardlord.net/blog/what-is-an-entity-framework 原文很长,译文将分开几部分,此为第一部分. 上周我发布了Ash(一个Actionscript 游戏开发的实体系统框架),后来很多朋友问我说:“什么是实体系统框架(entity system framework)?”.下面是我对此做出的非常长的解答(译者注:确实有些啰嗦...): 实体系统目前已经越来越流行,比如众所周知的Unity.较

游戏怎么分类?怎么学游戏开发?

Unity对游戏行业的贡献是无可非议的,Unity发展角度来说,更有利于学游戏的人,也说明了游戏的前景是非常好的,从Unity第一代到现在Unity4.3一步步成长都说明了Unity在游戏中地位.现在游戏分为三种:PC类端游这类游戏在线人说较多,游戏中要处理的数据也非常庞大.所以对服务器性能要求非常高,一般都是采用C++做为开发语言,C++可以直接操作内存数据,与操作系统直接交互,减少数据之间的复制.C++运行效率高,处理速度快,是很适合这里游戏开发语言.如果你想学习开发这样大的游戏需要学习的大

一款简单射击游戏IOS源码

源码描述: 一款基于cocos2d的简单设计游戏,并且也是一款基于cocos2d的简单射击游戏(含苹果IAD广告), 游戏操作很简单,哪个数字大就点击射击哪个.里面有苹果iad广告,功能简单完整,适合学习一下cocos2d整套游戏的开发. 使用方法:   截图: <ignore_js_op> <ignore_js_op> 详细说明:http://ios.662p.com/thread-1445-1-1.html

OpenGL简单绘制游戏角色阴影

在游戏开发中很多Q版游戏绘制角色阴影会简单的绘制一个半透明的椭圆,如下图: 这种方法的优点是实现简单,但表现效果明显不够真实.作为Q版风格尚可被玩家接受,而对于写实类游戏,多采用由美术提供针对性制作的图片作为阴影图层.这种方案效果最为理想,缺点是需要多制作大量的图片资源,使游戏包增加不少. 在最近的开发中,我想到了另一种角色阴影图形的绘制方法,这里把它分享给大家. 原理很简单,就是利用OpenGL的图像变形技术,通过把角色自身的图片进行调整,使之变成一个阴影图像. 先上效果图: 具体实现: Op

一些很棒的游戏推荐

最近开了个公众号,目的是每天推荐一款精彩的游戏,一款不错的游戏可以给我灵感,也可以带给我快乐.游戏程序员怎么能够不了解游戏呢? 目前已经推荐了六款游戏,分别是wrassling.Light House.antiyoy.Cobe the gallery.Noir.Seen.如果你也对游戏感兴趣,那么可以跟我一起交流哦! 下面的文章转自我的公众号,你可以在公众号里直接查看,因为视频无法在博客园显示. 我的公众号叫做:怪物程序员 你也可以扫二维码: 第一款游戏是wrassling: 今天推荐的游戏是一

最近这两天看了关于H5游戏开发的一个教程,实践很短暂,看了很多理论的东西,现在呢也只是想回忆回忆关于EUI的部分知识吧

首先我了解了什么是Egret: Egret中文就是白鹭的意思,Egret是一套H5游戏开发的软件.(纯粹属于个人理解) 其次我对以下几款软件的相关知识做了些了解: Egret Engine(引擎),Egret Wing(编辑器),Texture Merger(可将零散纹理拼合为整图,同时也可以解析SWF.GIF动画,导出可供Egret使用的配置文件),Egret Feather(是一款粒子效果编辑器)ResDepot(是针对资源配置文件的创建,编辑和管理工具)等.......ps:现在我只看了这