本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5)   

博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果,

转载的时候请务必注明出处:http://blog.csdn.net/yangyu20121224/article/details/11180135

经过上一篇文章对整个框架进行简单的分析了之后,我们可以开始着手开发了。这里

采用增量开发的方式,每一次项目的更新都完成其中一部分功能,同时保持其可扩展

性。功能的复杂性逐轮递增。

一、创建项目 

1、首先打开cocos2d-x-2.1.4目录下的“cocos2d-win32.vc2010.sln”文件,这里根据大家使用的VS版本而定。

2、打开之后,会看到左边的解决方案中有很多的项目文件,我们会在此基础上新建项目,这样的做的好处是我们不

需要在额外的关联cocos2d的类库,避免了编译项目时发生异常。大家也可以参考我之前总结过的一篇文章《解决

Cocos2d-X新建项目运行报错的问题》。

3、右击解决方案“Solution'cocos2d-win32.vc2010'”,点击“Add”->“New Project”。

4、新建项目名为“MyFishingJoy”,并且保存在“E:\Cocos2D-X Projects”文件夹下,这里视个人习惯而定。

5、点击"OK"按钮进入下一步,去掉Box2D前面默认的勾选项,因为我们在此项目中没有用到物理引擎。

6、点击“Finish”按钮,整个项目就新建好了。

写到这里,可能有些读者会觉得我很啰嗦,一个简单新建项目的过程就写了好几个步骤。但是博主写这个教程的时

候就考虑到要针对大部分的读者,当然也包括很多刚刚接触Cocos2D-X的朋友们,也有很多都是从Java直接转过来

的,以前都没有接触过C++,但是博主认为这不并不影响我们对于Cocos2D-X游戏引擎的学习以及对游戏开发的热情和

痴迷。虽然Cocos2D-X已经把这一切都封装的非常好了,但是开发的难度还是很大的,尤其是对于刚刚入门的初学者

来说。所以博主这里只想写的更详细一点,最好能详细到每一个步骤,每一个方法,让更多的人知道,其实开发游戏

也是soeasy!(不过对于这些简单的操作步骤,只会出现一次,在今后的教程中并不会重复出现)

二、创建数据 

创建好项目之后,我们首先要做的不是急着写场景、写逻辑,而是为这些场景适配数据,所以我们先完成动态数

据FishingJoyData和静态数据StaticData两个类。根据上一篇文章的分析可以知道,这两个类在整个游戏过程中只可

能出现一个实例,并且贯穿着整个游戏过程。因为,我们不妨把它们设计为单例。

单例(singleton)是软件开发过程中常用的一个设计模式。它通过控制一个全局变量,以便拥有某些独占性资

源,并达到便于管理和访问的作用,但是其缺点也很致命。它在整个程序运行周期内几乎不会被释放。同时,滥用单

例会使代码耦合性增大,不易于扩展。因此,单例模式一直备受争议。

Cocos2D-X是一个很好地运用了单例的例子。在引擎内部,有许多单例,它们都以shared为开头出现,例如:

  1. CCDirector *pDirector = CCDirector::sharedDirector();
  2. CCTextureCache *sharedTextureCache = CCTextureCache::sharedTextureCache();

仿照Cocos2D-X的做法,我们也同样设计这两个数据类单例,即实现以下功能:

<1> 将类的构造函数、析构函数和初始化函数都设为私有,禁止外部创建的新的实例。

<2> 统一使用shared*接口访问唯一的实例,并在该接口中使用延迟初始化,在需要时才创建实例。

<3> 实现purge函数,在必要时调用,以清理不必要的内存。

最后别忘了,在Cocos2D-X中,所有的对象类都必须继承自CCObject或其子类。

三、项目编码

1、新建StaticData

<1> 首先我们要新建一个类,右击该项目,点击“Add”->“Class”。

<2>在弹出的对话框中,选择“C++ Class”。

<3>然后在接下来的对话框中,取名为“staticData”,继承自CCObject类。

<4>点击“Finish”按钮,在目录中可以看到刚刚新建好的“StaticData.h”和“StaticData.cpp”这两个文件。

2、对StaticData编码

<1> StaticData.h头文件。定义这个类的作用主要是通过它可以很方便的读取“.plist”数据文件,根据键值来调用

外部的静态存储数据,以后更改数据也会非常的方便,比如图片的存放路径,金币的初始数量等等

  1. #ifndef __FishingJoy__StaticData__
  2. #define __FishingJoy__StaticData__
  3.  
  4. #include "cocos2d.h"
  5.  
  6. #define STATIC_DATA_STRING(key) StaticData::sharedStaticData()->stringFromKey(key)
  7. #define STATIC_DATA_INT(key) StaticData::sharedStaticData()->intFromKey(key)
  8. #define STATIC_DATA_FLOAT(key) StaticData::sharedStaticData()->floatFromKey(key)
  9. #define STATIC_DATA_BOOLEAN(key) StaticData::sharedStaticData()->booleanFromKey(key)
  10. #define STATIC_DATA_POINT(key) StaticData::sharedStaticData()->pointFromKey(key)
  11. #define STATIC_DATA_RECT(key) StaticData::sharedStaticData()->rectFromKey(key)
  12. #define STATIC_DATA_SIZE(key) StaticData::sharedStaticData()->sizeFromKey(key)
  13.  
  14. class StaticData : public cocos2d::CCObject
  15. {
  16. public:
  17. static StaticData* sharedStaticData();
  18.  
  19. /**
  20. * @brief 外部访问接口
  21. *
  22. * @param key 对应的static_data.plist中的Key
  23. * @return 对应的Value
  24. */
  25. const char* stringFromKey(std::string key);
  26. int intFromKey(std::string key);
  27. float floatFromKey(std::string key);
  28. bool booleanFromKey(std::string key);
  29. cocos2d::CCPoint pointFromKey(std::string key);
  30. cocos2d::CCRect rectFromKey(std::string key);
  31. cocos2d::CCSize sizeFromKey(std::string key);
  32.  
  33. /**
  34. * @brief 内存不足时调用
  35. */
  36. void purge();
  37.  
  38. CC_SYNTHESIZE_READONLY(std::string, _staticDataPath, StaticDataPath);
  39.  
  40. protected:
  41. cocos2d::CCDictionary* _dictionary;
  42. private:
  43. StaticData();
  44. ~StaticData();
  45. bool init();
  46. };
  47.  
  48. #endif

<2> StaticData.cpp文件。

  1. #include "StaticData.h"
  2.  
  3. USING_NS_CC;
  4.  
  5. using namespace std;
  6.  
  7. //定义文件的路径
  8. #define STATIC_DATA_PATH "static_data.plist"
  9.  
  10. //定义StaticData对象
  11. static StaticData* _sharedStaticData = NULL;
  12.  
  13. //得到StaticData单例对象
  14. StaticData* StaticData::sharedStaticData()
  15. {
  16. if(_sharedStaticData == NULL){
  17. _sharedStaticData = new StaticData();
  18. _sharedStaticData->init();
  19. }
  20. return _sharedStaticData;
  21. }
  22.  
  23. StaticData::StaticData()
  24. {
  25. _staticDataPath = STATIC_DATA_PATH;
  26. }
  27.  
  28. StaticData::~StaticData()
  29. {
  30. CC_SAFE_RELEASE_NULL(_dictionary);
  31. }
  32.  
  33. //初始化
  34. bool StaticData::init()
  35. {
  36. _dictionary = CCDictionary::createWithContentsOfFile(_staticDataPath.c_str());
  37. CC_SAFE_RETAIN(_dictionary);
  38. return true;
  39. }
  40.  
  41. //根据键值得到String类型数据
  42. const char* StaticData::stringFromKey(string key)
  43. {
  44. return _dictionary->valueForKey(key)->getCString();
  45. }
  46.  
  47. //根据键值得到int类型数据
  48. int StaticData::intFromKey(string key)
  49. {
  50. return _dictionary->valueForKey(key)->intValue();
  51. }
  52.  
  53. //根据键值得到float类型数据
  54. float StaticData::floatFromKey(string key)
  55. {
  56. return _dictionary->valueForKey(key)->floatValue();
  57. }
  58.  
  59. //根据键值得到bool类型数据
  60. bool StaticData::booleanFromKey(string key)
  61. {
  62. return _dictionary->valueForKey(key)->boolValue();
  63. }
  64.  
  65. //根据键值得到point类型数据
  66. cocos2d::CCPoint StaticData::pointFromKey(string key)
  67. {
  68. return CCPointFromString(_dictionary->valueForKey(key)->getCString());
  69. }
  70.  
  71. //根据键值得到rect类型数据
  72. cocos2d::CCRect StaticData::rectFromKey(string key)
  73. {
  74. return CCRectFromString(_dictionary->valueForKey(key)->getCString());
  75. }
  76.  
  77. //根据键值得到size类型数据
  78. cocos2d::CCSize StaticData::sizeFromKey(string key)
  79. {
  80. return CCSizeFromString(_dictionary->valueForKey(key)->getCString());
  81. }
  82.  
  83. //当内存不足时调用
  84. void StaticData::purge()
  85. {
  86. CC_SAFE_RELEASE_NULL(_sharedStaticData);
  87. }

通过上面的代码,我们就可以很轻松地获得plist的数据,并转换成我们想要的数据类型。为了更快速地写代码,

我们还定义了一系列接口将重复性的操作进行封装,同时使用宏定义,使代码更加的简洁。

在其init方法中,调用CCDictionary接口,读取“static_data.plist”文件,保存在缓存中。通过把plist读取到

CCDictionary后,我们得到是一个键为string类型、值为CCObject对象的字典。具体来说,值类型有3种:CCString、

CCArray和CCDictionary。对于简单的键值对,我们使用CCString来保存数据(包括字符串类型与数值类型),而对

于数组与字典,则采用后两种类型来保存。

我们来看看static_data.plist中的数据:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
  3. <plist version="1.0">
  4. <dict>
  5. <key>default_gold</key>
  6. <string>200</string>
  7. </dict>
  8. </plist>

可以看到,里面的数据都是以键值对的方式存储的,所以读取出来非常的方便,也易于管理。如果需要添加新的数

据的话,直接打开static_data.plist文件,以key-string的方式添加即可。

3、新建FishingJoyData

<1> 照着上面的方法,我们在新建一个FishingJoyData类。

<2>点击“Finish”按钮,在目录中可以看到刚刚新建好的这两个文件。

4、对FishingJoyData编码

<1> FishingJoyData.h头文件。该类的作用主要是对玩家的数据进行持久化存储,其实就是对CCUserDefault相关操

作的封装。

  1. #ifndef __FishingJoy__FishingJoyData__
  2. #define __FishingJoy__FishingJoyData__
  3.  
  4. #include "cocos2d.h"
  5.  
  6. class FishingJoyData : public cocos2d::CCObject
  7. {
  8. public:
  9. static FishingJoyData* sharedFishingJoyData();
  10. CC_SYNTHESIZE(int , _gold, Gold);
  11. CC_SYNTHESIZE(bool, _isBeginner, IsBeginner);
  12. CC_SYNTHESIZE(float, _soundVolume, SoundVolume);
  13. CC_SYNTHESIZE(float, _musicVolume, MusicVolume);
  14.  
  15. //内存不足时调用
  16. void purge();
  17.  
  18. //将数据从内存保存到外部文件中
  19. void flush();
  20.  
  21. //对Gold的操作
  22. void alterGold(int delta);
  23.  
  24. //重置游戏数据为默认数值
  25. void reset();
  26.  
  27. protected:
  28. FishingJoyData();
  29. ~FishingJoyData();
  30. bool init();
  31. };
  32.  
  33. #endif

<2> FishingJoyData.cpp文件。

  1. #include "FishingJoyData.h"
  2. #include "StaticData.h"
  3.  
  4. USING_NS_CC;
  5.  
  6. //定义FishingJoyData对象
  7. static FishingJoyData* _sharedFishingJoyData = NULL;
  8.  
  9. //得到FishingJoyData单例对象
  10. FishingJoyData* FishingJoyData::sharedFishingJoyData()
  11. {
  12. if(_sharedFishingJoyData==NULL){
  13. _sharedFishingJoyData = new FishingJoyData();
  14. _sharedFishingJoyData->init();
  15. }
  16. return _sharedFishingJoyData;
  17. }
  18.  
  19. //当内存不足时调用
  20. void FishingJoyData::purge()
  21. {
  22. CC_SAFE_RELEASE_NULL(_sharedFishingJoyData);
  23. }
  24.  
  25. FishingJoyData::FishingJoyData()
  26. {
  27.  
  28. }
  29.  
  30. FishingJoyData::~FishingJoyData()
  31. {
  32. this->flush();
  33. }
  34.  
  35. //初始化
  36. bool FishingJoyData::init()
  37. {
  38. //判断该玩家是否是第一次登录
  39. _isBeginner = CCUserDefault::sharedUserDefault()->getBoolForKey("beginner",true);
  40.  
  41. if(_isBeginner == true){
  42. this->reset();
  43. this->flush();
  44. this->setIsBeginner(false);
  45. }else{
  46. _isBeginner = CCUserDefault::sharedUserDefault()->getBoolForKey("beginner");
  47. _soundVolume = CCUserDefault::sharedUserDefault()->getFloatForKey("sound");
  48. _musicVolume = CCUserDefault::sharedUserDefault()->getFloatForKey("music");
  49. _gold = CCUserDefault::sharedUserDefault()->getIntegerForKey("gold");
  50. CCUserDefault::sharedUserDefault()->purgeSharedUserDefault();
  51. }
  52. return true;
  53. }
  54.  
  55. //重置游戏数据
  56. void FishingJoyData::reset()
  57. {
  58. int gold = STATIC_DATA_INT("default_gold");
  59. this->setGold(gold);
  60. this->setIsBeginner(true);
  61. this->setMusicVolume(1);
  62. this->setSoundVolume(1);
  63. this->flush();
  64. }
  65.  
  66. //更新金币的数量
  67. void FishingJoyData::alterGold(int delta)
  68. {
  69. this->setGold(this->getGold()+delta);
  70. }
  71.  
  72. //存储数据
  73. void FishingJoyData::flush()
  74. {
  75. CCUserDefault::sharedUserDefault()->setFloatForKey("sound", this->getSoundVolume());
  76. CCUserDefault::sharedUserDefault()->setBoolForKey("beginner", this->getIsBeginner());
  77. CCUserDefault::sharedUserDefault()->setIntegerForKey("gold", this->getGold());
  78. CCUserDefault::sharedUserDefault()->setFloatForKey("music", this->getMusicVolume());
  79. CCUserDefault::sharedUserDefault()->flush();
  80. CCUserDefault::sharedUserDefault()->purgeSharedUserDefault();
  81. }

让我们一起来分析上面的这段代码:

<1>大多数游戏对于初学者都会有相应的新手引导,因此,除了金币数量、音乐音效和音量大小外,我们还需要一个

布尔值,用于判断玩家是否为初学者。

<2> 在CCUserDefault的get*ForKey系列方法中,有两个参数:一个是字符串类型的键值,另一个是默认参数,它表

示找不到对应键值时返回的值。

<3> 在FishingJoyData类中,每次对CCUserDefault进行操作后,都会调用purgeSharedUserDefault()将其删除。这

是因为FishingJoyData和CCUserDefault中都保存着游戏的数据。因此,只在与外部文件交互时,我们才打开

CCUserDefault,保存数据,然后删除CCUserDefault,以此避免重复占用游戏数据,而对内存造成浪费。

<4> 最后,别忘了在程序进入后台时调用flush方法,及时保存游戏数据。

关于CCUserDefault的详细讲解可以参考:http://blog.csdn.net/yangyu20121224/article/details/10857813

完成了游戏数据的封装,大家是不是觉得有些枯燥无味?尽管数据操作并不复杂,但没有看得见的图片和效果,总

是让人兴奋不起来的。但是,有了数据的铺垫,那么接下来我们制作场景的过程会更加的得心应手。



源码下载地址(百度云)

【Cocos2d-X游戏实战开发】捕鱼达人之单例对象的设计(二)的更多相关文章

  1. 【全面解禁!真正的Expression Blend实战开发技巧】第九章 FluidMoveBehavior完全解析之二平滑运动的滚动条

    原文:[全面解禁!真正的Expression Blend实战开发技巧]第九章 FluidMoveBehavior完全解析之二平滑运动的滚动条 这一章讲解FluidMoveBehavior的另一个应用, ...

  2. 010-Scala单例对象、伴生对象实战详解

    010-Scala单例对象.伴生对象实战详解 Scala单例对象详解 函数的最后一行是返回值 子项目 Scala伴生对象代码实战 object对象的私有成员可以直接被class伴生类访问,但是不可以被 ...

  3. 原生Js贪吃蛇游戏实战开发笔记

    前言 本课程是通过JavaScript结合WebAPI DOM实现的一版网页游戏---贪吃蛇的开发全过程,采用面向以象的思想设计开发.通过这个小游戏的开发, 不仅可以掌握JS的语法的应用,还可以学会D ...

  4. 【Cocos2d-X游戏实战开发】捕鱼达人之游戏场景的创建(六)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5)    博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果, 转载的时候请务必注 ...

  5. 【Cocos2d-X游戏实战开发】捕鱼达人之开发前准备工作(一)

    本系列学习教程使用的是cocos2d-x-2.1.4(最新版为cocos2d-x-2.1.5) 博主发现前两个系列的学习教程被严重抄袭,在这里呼吁大家请尊重开发者的劳动成果, 转载的时候请务必注明出处 ...

  6. cocos2dx游戏开发——捕鱼达人mini版学习笔记(二)——MainMenu的搭建

    一.创建文件~ MainMenuScene.h   MainMenuScene.cpp   MainMenuLayer.h   MainMenuLayer.cpp 那个场景的搭建就不多说了,那个我的打 ...

  7. cocos2dx游戏开发——捕鱼达人mini版学习笔记(一)——FishAchor的搭建

    一.创建文件· FishAchor.h还有FishAchor.cpp. 主要就是创建每种鱼的类,方便以后的取用~,很多是重复性的操作,然后我们是mini版,暂时也就加入大概6钟鱼就好= =,然后我们现 ...

  8. c#实战开发:以太坊钱包对接私链 (二)

    上一篇讲了 以太坊私链搭建 首先下载Ethereum Wallet 钱包 可以直接百度 下载如果直接打开它会默认连接公链 所以我们要通过命令打开 "F:\Program Files\Ethe ...

  9. iOS开发中常用的单例

    定义:一个类的对象,无论在何时创建.无论创建多少次,创建出来的对象都是同一个对象. 使用场景:当有一些数据需要共享给别的类的时候,就可以把这些数据保存在单例对象中.   关键代码: + (instan ...

随机推荐

  1. 面向对象程序设计-C++ Operator Overloading & Type conversion (Static)【第十一次上课笔记】

    本次上课继续讲解了 [ ] .-> 等运算符重载的具体例子 也讲解了C++单个参数的类的类型转换的案例 最后稍微提到了 static 的第三种作用:静态数据成员 具体详解我都已注释出来了,大家可 ...

  2. HttpResponseRedirect VS HttpResponse

    当我们处理了post提交的数据之后,我们使用HttpResponseRedirect跳转到另一个页面,而不是用HttpResponse. 例如当一个投票环节时使用HttpResponse可以使用浏览器 ...

  3. 基于visual Studio2013解决C语言竞赛题之0521圆盘求和

     题目

  4. Shell中的if else语句小演示

    安安静静学习小shell,今天看到if else 喽~ 下面这个脚本是判断用户执行脚本的参数,如果是hello的话,就显示how are you 如果什么都没有,就提示输入 如果参数不是hello,就 ...

  5. JDK1.6官方下载

    JDK1.6官方下载_JDK6官方下载地址:http://www.java.net/download/jdk6/6u10/promoted/b32/binaries/jdk-6u10-rc2-bin- ...

  6. ListView属性解释

    1.android:scrollbarStyle 定义滚动条的样式和位置 参考:http://www.trinea.cn/android/android-scrollbarstyle/ 2.andro ...

  7. CheckBox控件

    前台代码: <asp:CheckBox ID="CheckBox1" runat="server" Text ="苹果"/> & ...

  8. iOS开发中关于本地数据中SQLite数据库常用的SQL语句

    创建表 CREATE TABLE IF NOT EXISTS "student" ("number" INTEGER PRIMARY KEY AUTOINCRE ...

  9. 嵌入式MCU开发群资源

     STM32CubeMX是一款图形化软件设置工具,允许使用图形化向导来生成C初始化代码.它是未来开发stm32系列产品的主流软件,是ST公司的主动原创,可以减轻开发工作,时间和费用.STM32Cube ...

  10. java - final和static 关键字 再记忆

    一.final        根据程序上下文环境,Java关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可能出于两种理解而需要阻止改变:设计或效 ...