Cocos2d-x游戏开发实战精解
上QQ阅读APP看书,第一时间看更新

2.1 在Cocos2d-x中创建一个新的场景

在Cocos2d-x中新建一个项目,命名为CocosProject01,并在Visual Studio 2013中打开,可以看到它的目录如图2-1所示。

图2-1 Cocos2d-x项目的目录

右击该项目,在快捷菜单中选择“添加”|“类”命令,创建一个新类,命名为MyScene,然后参照HelloWorldScene.h中的内容对文件MyScene.h进行编辑,如范例2-1所示。

【范例2-1】新建类MyScene的定义。

01 #include "cocos2d.h"
02      class MyWorld :public cocos2d::Layer 
03      { 
04      public:
05              static cocos2d::Scene* createScene();   //静态函数,用于获取场景对象
06              virtual bool init();                    //初始化场景
07              CREATE_FUNC(MyWorld);                   //这里使用了一个宏
08      };

接下来再在MyScenecpp中实现MyScene.h中定义的方法,如范例2-2所示。

【范例2-2】新建类MyScene中方法的实现。

01 #include "MyScene.h"
02      USING_NS_CC;
03      Scene* MyWorld::createScene() 
04      { 
05              auto scene = Scene::create();       //创建一个场景对象
06              auto layer = MyWorld::create();     //创建Myscene对象
07              scene->addChild(layer);                  //将layer加入到场景scene中去
08              return scene;                       //返回创建好的场景对象
09      } 
10      bool MyWorld::init() 
11      {
12              if (!Layer::init())
13              {
14                      return false;
15              }
16              //今后就在这里向场景中加入内容
17              return true; 
18      }

好了,到目前为止我们已经实现了一个新的类,但是读者应该还是迷迷糊糊的,不知道这究竟是要干嘛,那么接下来的任务就是解析这两段代码。

看范例2-2的第03~09行,该方法实现了创建并返回一个场景对象的功能。首先在第05行中创建一个Scene类型的对象scene,注意这并不是使用的MyWorld本身,之后才是创建了一个MyWorld类型的对象layer并将scene加入到其中,如第06、07行所示。

这里需要注意两个问题,首先就是在第05、06行中定义对象时使用了关键字auto,这是在C++ 11中新定义的自动类型变量,编译器将会在编译时自动对变量类型进行识别;其次是在第06行中使用的MyWorld类中的create方法与在第05行使用的create方法是不同的,那么这种不同又是怎样产生的呢?

现在看范例2-1的第07行,这里使用了一个宏定义。在Visual Studio中选中CREATE_FUNC,然后右击鼠标,在快捷菜单中选择“查看定义”命令就可以查看关于该宏定义的解释,如范例2-3所示。

【范例2-3】宏CREATE_FUNC的定义。

01 #define CREATE_FUNC(__TYPE__) \
02      static __TYPE__* create() \
03      { \
04          __TYPE__ *pRet = new __TYPE__(); \
05          if (pRet && pRet->init()) \
06          { \
07              pRet->autorelease(); \
08              return pRet; \
09          } \
10          else \
11          { \
12              delete pRet; \
13              pRet = NULL; \
14              return NULL; \
15          } \
16      }

也许这让人看起来一头雾水,不过先不要着急,现在把这个宏定义的参数MyWorld带入到代码中,如范例2-4所示。

【范例2-4】将参数MyWorld带入到宏定义中。

01 static MyWorld * create()
02      { 
03          MyWorld *pRet = new MyWorld (); 
04          if (pRet && pRet->init()) 
05          { 
06              pRet->autorelease(); 
07              return pRet; 
08          } 
09          else 
10          { 
11              delete pRet; 
12              pRet = NULL; 
13              return NULL; 
14          } 
15      }

这样看起来好像是清楚多了,但仔细推敲的话貌似雾水还在,不过没有关系,现在所需要知道的只是在MyWorld和Scene类中的create方法是两个不同的方法就可以了。

注意:这里唯一需要强调的就是MyScene虽然因为命名习惯将文件名叫做scene,而且也经常在习惯上将其称呼为场景类,但是它却并不是继承自Scene而是继承自Layer,因此它是一个层而不是一个场景。对于这一点的理解在今后的开发中非常重要。

在HelloWorldScene.h文件中可以看到如下所示的代码:

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
//对类的定义
#endif

这是干什么用的呢?

原来在实际的Cocos2d-x项目中,多个类之间经常会相互引用,比如要从MyWorld中切换到HelloWorld中就需要在MyWorldScene.h中引入HelloWorldScene.h,而再从HelloWorld切换回MyWorld则又要在HelloWorldScene.h中引入MyWorldScene.h,这就导致了编译器在编译时会重复许多工作。有了这段宏定义则可以保证,编译器确认对该类进行过编译工作后,就直接跳过这段代码,这节省了许多麻烦。