我的Cocos2d-x学习笔记(三)游戏逻辑架构与HelloWorld分析

 先来看看Cocos2d-x中关于游戏的一些基础概念,首先盗用官网的图描述一下游戏中各个游戏对象的关系。


    从上图中可以知道在Cocos2d-x中只存在一个导演,而事实上之前我们也看到CCDirector是一个单例对象;而游戏中可以存在多个场景,图中存在N个场景;每个场景中又可以存在多个层;每个层中又可以包含多个精灵。

    一个导演同一时间只能运行一个场景,一个场景当中,可以同时加载多个层,一个层同可以可载多个精灵。层中亦可以加层。

    其实CCScen、CCLayer与CCSprite都直接或间接派生自CCNode;CCNode是与渲染有关的基类,定义了一些用于显示子类的方法,之后再详细介绍它。

导演(CCDirector):

     Cocos2d-x中统筹游戏大局的类,游戏中一些常用的的操作就是由CCDirector来控制,在游戏中是单例对象,项目中没错获取的CCDirector都是同一个对象。例如:OpenGL ES的初始化,场景的转换,游戏的暂停与继续控制,世界坐标与GL坐标的转换,对游戏节点的控制等都是CCDirector控制。

场景(CCScene):

    场景的基础关系:class CC_DLL CCScene : public CCNode。

    场景是游戏当中相对来说不变的一个游戏元素,由场景来承载层与精灵,一些层与精灵表现出的游戏内容存放在一个场景中,往往场景切换对应着关卡切换。其重要的作用就是进行流程控制。

   在CCDirector中有关CCScene的函数有如下几种,截取类中一部分代码如下:

	class CC_DLL CCDirector : public CCObject, public TypeInfo
	{
	public:
		void runWithScene(CCScene *pScene);
		void pushScene(CCScene *pScene);
		void popScene(void);
		void replaceScene(CCScene *pScene);
		void end(void);
		void pause(void);
		void resume(void);
	}
    void runWithScene(CCScene *pScene):这个函数在启动游戏时候调用,运行场景pScene。AppDelegate.cpp中曾经调用过,其实这个函数是第一次执行主场景时候调用。如果已有正在运行的场景则不能调用该方法。

    void pushScene(CCScene *pScene):将当前运行中的场景暂停并压入到代码执行场景栈中,再将传入的pScene设置为当前运行场景,只有存在正在运行的场景时才调用该方法。

    void popScene(void);:释放当前场景,再从代码执行场景中弹出栈顶的场景,并将其设置为当前运行场景。如果栈为空,直接结束应用。和PushScene结对使用。

    void replaceScene(CCScene *pScene);:直接使用传入的pScene替换当前场景来切换画面,当前场景被释放。这是切换场景时最常用的方法。

    void pause(void);:暂停当前运行场景中的所有计时器和动作,场景仍然会显示在屏幕上。

    void resume(void): 恢复当前运行场景的所有计时器和动作,场景仍然会显示在屏幕上。

    void end(void):释放和终止执行场景,同时退出应用。

场景切换用到的代码如下:

	CCScene* pScene = TestLayer::scene();
	CCDirector::sharedDirector()->pushScene(pScene);
	CCDirector::sharedDirector()->popScene();
	CCDirector::sharedDirector()->replaceScene(pScene);
其中我们要知道的是CCScene* pScene = TestLayer::scene();返回的是一个场景指针,执行之后的代码便可进行场景入栈,出栈和场景替换了,当然不能在同一代码库中同时运行。

层(CCLayer):

    层的继承关系:class CC_DLL CCLayer : public CCNode, public CCTouchDelegate, public CCAccelerometerDelegate, public CCKeypadDelegate。

    由层的继承关系可以看出,层可以接受触摸、加速度计、键盘输入。

    层包含显示在屏幕上的内容,多个层可以组成复杂的场景。

    层可以包含任何Node作为子节点,包括CCSprites(精灵),,Labels(标签),甚至其他的Layer对象。

    要向场景添加层,我们可以使用addChild方法。

    addChild方法是继承自CCNode中,只要CCNode的子类,都存在addChild()方法,并且可以利用此方法把节点添加到另一个节点上去,在CCNode中定义如下:

class CC_DLL CCNode : public CCObject
{
public:
	virtual void addChild(CCNode * child);
	virtual void addChild(CCNode * child, int zOrder);
	virtual void addChild(CCNode* child, int zOrder, int tag);
}
    其中,child参数就是节点。先添加的节点会被置于后添加的节点之下。可以使用不同的zOrder值指定先后顺序,zOrder值越大离屏幕越近,越不容易被覆盖。tag是节点的标识号码,如果为子节点设置了tag值,就可以在它的父节点中利用tag值就可以找到它了。

精灵(CCSprite):

    精灵的继承关系:class CC_DLL CCSprite : public CCNodeRGBA, public CCTextureProtocol。
    层和场景是其他游戏元素的容器,它们看起来是透明的。而精灵是具体可见的图形,可以执行动画等。


导演、场景、层、精灵暂且学习到这里,下面看看HelloWorld中的一些内容。此HelloWorld为精简化的,HelloWorld头文件内容如下:

#ifndef __HelloWorld_H__
#define __HelloWorld_H__
#include "cocos2d.h"
USING_NS_CC;

class HelloWorld:public CCLayer
{
public:
	static CCScene* scene();
	CREATE_FUNC(HelloWorld);
	bool init();
};

#endif
其中先来看看CREATE_FUNC:

#define CREATE_FUNC(__TYPE__) 
static __TYPE__* create() 
{ 
    __TYPE__ *pRet = new __TYPE__(); 
    if (pRet && pRet->init()) 
    { 
        pRet->autorelease(); 
        return pRet; 
    } 
    else 
    { 
        delete pRet; 
        pRet = NULL; 
        return NULL; 
    } 
}
由此可知CREATE_FUNC是一个宏,这个宏预处理后在程序中添加了一个静态create()函数。把HelloWorld中的进一步翻译后的到如下代码,当我们需要包含参数的create函数的时候,就必须自己仿照下面代码来写这个create函数了。

static HelloWorld* create()
{
	HelloWorld *pRet = new HelloWorld();
	if (pRet && pRet->init())
	{
		pRet->autorelease();
		return pRet;
	}
	else
	{
		delete pRet;
		pRet = NULL;
		return NULL;
	}
}
再来看看static CCScene* scene()函数与bool init()函数,这两个函数在HelloWorld.cpp中定义:

#include "HelloWorld.h"

CCScene* HelloWorld::scene()
{
	CCScene* scene = CCScene::create();
	HelloWorld* layer = HelloWorld::create();

	scene->addChild(layer);
	return scene;

}

bool HelloWorld::init()
{
	if (!CCLayer::init())return false;
	return true;
}

    static CCScene* scene()中首先创建了一个场景对象保存了指向它的指针,利用CCScene中的create()函数;然后用HelloWorld中的create()函数创建了一个HelloWorld对象并保存了指向它的指针,此时用到的create()函数就是之前CREATE_FUNC替换后的函数;之后通过addChild把HelloWorld对象添加到场景对象scene中;最后返回场景对象指针scene。
    bool HelloWorld::init()中是我们编写程序的主要地方,因为Cocos2d-x中有许多类不使用构造函数进行初始化,所以在HelloWorld::init()中首先调用了其父类的init()函数进行初始化,以防错误发生;如果父类init()产生错误,返回false,之后运行一系列我们自定义的函数后,返回true。


    其实static CCScene* scene()在需要返回场景时候类中可以添加,不需要返回场景时候可以不添加,具体如何看实际情况。

原文地址:https://www.cnblogs.com/gongyan/p/4539410.html