Cocos2d-x   发布时间:2022-05-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了1.Cocos2d-x-3.2编写3d打飞机,粒子管理器代码大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。


Cocos2d-x中的一个单例效果:

@H_673_38@ @H_673_38@ @H_673_38@

#ifndef __Moon3d__ParticleManager__

#define __Moon3d__ParticleManager__

#include "cocos2d.h"

USING_NS_CC;

class ParticleManager

{

public:

static ParticleManager* geTinstance()@H_675_147@//定义获取实例方法,单例设计模式.see notes

{

if ( @H_685_173@m_pInstance == nullptr )@H_675_147@//如果实例为空,

@H_685_173@m_pInstance = new ParticleManager();@H_675_147@//创建实例

return @H_685_173@m_pInstance;@H_675_147@//返回实例

}

private:

ParticleManager();@H_675_147@//构造函数

static ParticleManager* @H_685_173@m_pInstance;@H_675_147@//粒子管理器实例

class CGarbo@H_675_147@//内部类,主要作用是退出游戏的时候,清理内存,原理:程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。

{

public:

~CGarbo()@H_675_147@//析构函数

{

if (ParticleManager::@H_685_173@m_pInstance!= nullptr)@H_675_147@//如果实例不为空

{

delete ParticleManager::@H_685_173@m_pInstance;@H_675_147@//清除单例

}

}

};

static CGarbo @H_685_173@m_garbo;@H_675_147@//定义内部类变量

public:

std::@H_101_139@map<String,ValueMap> @H_685_173@m_plistMap;@H_675_147@//定义存放粒子数据的集合

void AddPlistData(String strPlist,133); font-family:新宋体; font-size:9.5pt">String strName);@H_675_147@//把粒子数据添加到集合里

ValueMap GetPlistData(String strName);@H_675_147@//从粒子集合中获取粒子数据

};

#endif @H_675_147@/* defined(__Moon3d__ParticleManager__) */

#include "ParticleManager.h"

ParticleManager* ParticleManager::@H_685_173@m_pInstance=NULL;@H_675_147@//变量初始化

ParticleManager::CGarbo ParticleManager::@H_685_173@m_garbo;@H_675_147@//变量初始化

ParticleManager()

{

@H_685_173@m_plistMap.clear();@H_675_147@//构造函数集合清理

}

void ParticleManager::String strName)

{

auto plistData=FileUtils::geTinstance()->getValueMapFromFile(strPlist);@H_675_147@//获取粒子数据

ValueMap>::iterator it = @H_685_173@m_plistMap.begin();@H_675_147@//获取集合

@H_685_173@m_plistMap.insert(it,133); font-family:新宋体; font-size:9.5pt">pair<ValueMap>(strName,plistData));@H_675_147@//把粒子数据存放到集合里

}

ValueMap String strplist)

{

auto plistData=@H_685_173@m_plistMap.find(strplist)->second;@H_675_147@//获取粒子数据

return plistData;@H_675_147@//返回粒子数据

}

说明:

@H_675_147@/*****************************************************************************

单例模式也称为单件模式、单子模式,可能是使用最广泛的设计模式。其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。有很多地方需要这样的功能模块,如系统的日志输出,GUI应用必须是单鼠标,@H_128_7@mODEM的联接需要一条且只需要一条电话线,操作系统只能有一个窗口管理器,一台PC连一个键盘。

@H_675_147@ 单例模式有许多种实现方法,在C++中,甚至可以直接用一个全局变量做到这一点,但这样的代码显的很不优雅。 使用全局对象能够保证方便地访问实例,但是不能保证只声明一个对象——也就是说除了一个全局实例外,仍然能创建相同类的本地实例。

@H_675_147@ 《设计模式》一书中给出了一种很不错的实现,定义一个单例类,使用类的私有静态指针变量指向类的唯一实例,并用一个公有的静态方法获取该实例。

@H_675_147@ 单例模式通过类本身来管理其唯一实例,这种特性提供了解决问题的方法。唯一的实例是类的一个普通对象,但设计这个类时,让它只能创建一个实例并提供对此实例的全局访问。唯一实例类Singleton在静态成员函数中隐藏创建实例的操作。习惯上把这个成员函数叫做Instance(),它的返回值是唯一实例的指针。

@H_675_147@定义如下:

@H_675_147@[cpp] view plaincopy

@H_675_147@class CSingleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ CSingleton() //构造函数是私有的

@H_675_147@ {

@H_675_147@ }

@H_675_147@ static CSingleton *m_pInstance;

@H_675_147@public:

@H_675_147@ static CSingleton * GeTinstance()

@H_675_147@ {

@H_675_147@ if(m_pInstance == NULL) //判断是否第一次调用

@H_675_147@ @H_76_3@m_pInstance = new CSingleton();

@H_675_147@ return m_pInstance;

@H_675_147@ }

@H_675_147@};

用户访问唯一实例的方法只有GeTinstance()成员函数。如果不通过这个函数,任何创建实例的尝试都将失败,因为类的构造函数是私有的。GeTinstance()使用懒惰初始化,也就是说它的返回值是当这个函数首次被访问时被创建的。这是一种防弹设计——所有GeTinstance()之后的调用都返回相同实例的指针:

@H_675_147@ CSingleton* p1 = CSingleton :: GeTinstance();

@H_675_147@ CSingleton* p2 = p1->GeTinstance();

@H_675_147@ CSingleton & ref = * CSingleton :: GeTinstance();

@H_675_147@ GeTinstance稍加修改,这个设计模板便可以适用于可变多实例情况,如一个类允许最多五个实例。

@H_675_147@

@H_675_147@单例类CSingleton有以下特征:

@H_675_147@ 它有一个指向唯一实例的静态指针@H_128_7@m_pInstance,并且是私有的;

@H_675_147@ 它有一个公有的函数,可以获取这个唯一的实例,并且在需要的时候创建该实例;

@H_675_147@ 它的构造函数是私有的,这样就不能从别处创建该类的实例。

@H_675_147@ 大多数时候,这样的实现都不会出现问题。有经验的读者可能会问,@H_128_7@m_pInstance指向的空间什么时候释放呢?更严重的问题是,该实例的析构函数什么时候执行?

@H_675_147@ 如果在类的析构行为中有必须的操作,比如关闭文件,释放外部资源,那么上面的代码无法实现这个要求。我们需要一种方法,正常的删除该实例。

@H_675_147@ 可以在程序结束时调用GeTinstance(),并对返回的指针掉用delete操作。这样做可以实现功能,但不仅很丑陋,而且@R_593_10197@。因为这样的附加代码很容易被忘记,而且也很难保证delete之后,没有代码再调用GeTinstance函数。

@H_675_147@ 一个妥善的方法是让这个类自己知道在合适的时候把自己删除,或者说把删除自己的操作挂在操作系统中的某个合适的点上,使其在恰当的时候被自动执行。

@H_675_147@ 我们知道,程序在结束的时候,系统会自动析构所有的全局变量。事实上,系统也会析构所有的类的静态成员变量,就像这些静态成员也是全局变量一样。利用这个特征,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一工作就是在析构函数中删除单例类的实例。如下面的代码中的CGarbo类(Garbo意为垃圾工人):

@H_675_147@[cpp] view plaincopy

@H_675_147@class CSingleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ CSingleton()

@H_675_147@ {

@H_675_147@ }

@H_675_147@ static CSingleton *m_pInstance;

@H_675_147@ class CGarbo //它的唯一工作就是在析构函数中删除CSingleton的实例

@H_675_147@ {

@H_675_147@ public:

@H_675_147@ ~CGarbo()

@H_675_147@ {

@H_675_147@ if(CSingleton::m_pInstancE)

@H_675_147@ delete CSingleton::m_pInstance;

@H_675_147@ }

@H_675_147@};

@H_675_147@static CGarbo Garbo; //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数

@H_675_147@public:

@H_675_147@ static CSingleton * GeTinstance()

@H_675_147@ {

@H_675_147@ if(m_pInstance == NULL) //判断是否第一次调用

@H_675_147@ @H_76_3@m_pInstance = new CSingleton();

@H_675_147@ return m_pInstance;

@H_675_147@ }

@H_675_147@};

@H_675_147@ CGarbo被定义为CSingleton的私有内嵌类,以防该类被在其他地方滥用。

程序运行结束时,系统会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。

@H_675_147@ 使用这种方法释放单例对象有以下特征:

在单例类内部定义专有的嵌套类;

@H_675_147@ 在单例类内定义私有的专门用于释放的静态成员;

@H_675_147@ 利用程序在结束时析构全局变量的特性,选择最终的释放时机;

@H_675_147@ 使用单例的代码不需要任何操作,不必关心对象的释放。

@H_675_147@

@H_675_147@ 进一步的讨论

@H_675_147@ 但是添加一个类的静态对象,总是让人不太满意,所以有人用如下方法来重新实现单例和解决它相应的问题,代码如下:

@H_675_147@

@H_675_147@[cpp] view plaincopy

@H_675_147@class CSingleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ CSingleton() //构造函数是私有的

@H_675_147@ {

@H_675_147@}

@H_675_147@public:

@H_675_147@ static CSingleton & GeTinstance()

@H_675_147@ {

@H_675_147@ static CSingleton instance; //局部静态变量

@H_675_147@ return instance;

@H_675_147@ }

@H_675_147@};

使用局部静态变量,非常强大的方法,完全实现了单例的特性,而且代码量更少,也不用担心单例销毁的问题。

@H_675_147@ 但使用此种方法也会出现问题,当如下方法使用单例时问题来了,

@H_675_147@ Singleton singleton = Singleton :: GeTinstance();

这么做就出现了一个类拷贝的问题,这就违背了单例的特性。产生这个问题原因在于:编译器会为类生成一个默认的构造函数,来支持类的拷贝。

最后没有办法,我们要禁止类拷贝和类赋值,禁止程序员用这种方式来使用单例,当时领导的意思是GeTinstance()函数返回一个指针而不是返回一个引用,函数的代码改为如下:

@H_675_147@

@H_675_147@[cpp] view plaincopy

@H_675_147@class CSingleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ CSingleton() //构造函数是私有的

@H_675_147@ {

@H_675_147@ }

@H_675_147@public:

@H_675_147@ static CSingleton * GeTinstance()

@H_675_147@ {

@H_675_147@ static CSingleton instance; //局部静态变量

@H_675_147@ return &instance;

@H_675_147@ }

@H_675_147@};

但我总觉的不好,为什么不让编译器不这么干呢。这时我才想起可以显示的声明类拷贝的构造函数,和重载 = 操作符,新的单例类如下:

@H_675_147@

@H_675_147@[cpp] view plaincopy

@H_675_147@class CSingleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ CSingleton() //构造函数是私有的

@H_675_147@ {

@H_675_147@ }

@H_675_147@ CSingleton(const cSingleton &);

@H_675_147@ CSingleton & operator = (const cSingleton &);

@H_675_147@public:

@H_675_147@ static CSingleton & GeTinstance()

@H_675_147@ {

@H_675_147@ static CSingleton instance; //局部静态变量

@H_675_147@ return instance;

@H_675_147@ }

@H_675_147@};

@H_675_147@ 关于Singleton(const Singleton); Singleton & operate = (const Singleton&);函数,需要声明成私有的,并且只声明不实现。这样,如果用上面的方式来使用单例时,不管是在友元类中还是其他的,编译器都是报错。

@H_675_147@ 不知道这样的单例类是否还会有问题,但在程序中这样子使用已经基本没有问题了。

@H_675_147@

@H_675_147@ 虑到线程安全、异常安全,可以做以下扩展

@H_675_147@[cpp] view plaincopy

@H_675_147@class Lock

@H_675_147@{

@H_675_147@private:

@H_675_147@ CCriticalSection m_cs;

@H_675_147@public:

@H_675_147@ Lock(CCriticalSection cs) : m_cs(cs)

@H_675_147@ {

@H_675_147@ @H_76_3@m_cs.Lock();

@H_675_147@ }

@H_675_147@ ~Lock()

@H_675_147@ {

@H_675_147@ @H_76_3@m_cS.Unlock();

@H_675_147@ }

@H_675_147@};

@H_675_147@

@H_675_147@class Singleton

@H_675_147@{

@H_675_147@private:

@H_675_147@ Singleton();

@H_675_147@ Singleton(const Singleton &);

@H_675_147@ Singleton& operator = (const Singleton &);

@H_675_147@

@H_675_147@public:

@H_675_147@ static Singleton *Instantialize();

@H_675_147@ static Singleton *pInstance;

@H_675_147@ static CCriticalSection cs;

@H_675_147@};

@H_675_147@

@H_675_147@Singleton* Singleton::pInstance = 0;

@H_675_147@

@H_675_147@Singleton* Singleton::Instantialize()

@H_675_147@{

@H_675_147@ if(pInstance == NULL)

@H_675_147@ { //double check

@H_675_147@ Lock lock(cs); //lock实现线程安全,用资源管理类,实现异常安全

@H_675_147@ //使用资源管理类,在抛出异常的时候,资源管理类对象会被析构,析构总是发生的无论是因为异常抛出还是语句块结束。

@H_675_147@ if(pInstance == NULL)

@H_675_147@ {

@H_675_147@ pInstance = new Singleton();

@H_675_147@}

@H_675_147@ }

@H_675_147@ return pInstance;

@H_675_147@}

@H_675_147@

之所以在Instantialize函数里面对pInstance 是否为空做了两次判断,因为该方法调用一次就产生了对象,pInstance == NULL 大部分情况下都为false,如果按照原来的方法,每次获取实例都需要加锁,效率太低。而改进的方法只需要在第一次 调用的时候加锁,可大大提高效率。

@H_675_147@*/

大佬总结

以上是大佬教程为你收集整理的1.Cocos2d-x-3.2编写3d打飞机,粒子管理器代码全部内容,希望文章能够帮你解决1.Cocos2d-x-3.2编写3d打飞机,粒子管理器代码所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。