Cocos2d-X3.0 刨根问底(八)----- 场景(Scene)、层(Layer)相关源码分析

时间:2023-01-21 00:34:41

本章节我们重点分析Cocos2d-x3.0与 场景、层相关的源码。这部分源码集中在 libcocos2d –> layers_scenes_transitions_nodes目录下面

我先发个截图大家了解一下都有哪些文件。红色框里面的就是我们今天要分析的文件。

Cocos2d-X3.0 刨根问底(八)----- 场景(Scene)、层(Layer)相关源码分析

从命名上可以了解,这个文件夹里的文件主要包含了  场景,层,变换这三种类型的文件。

下面我们先分析Scene类

打开CCScene.h文件

/** @brief Scene is a subclass of Node that is used only as an abstract concept.

Scene and Node are almost identical with the difference that Scene has its
anchor point (by default) at the center of the screen. For the moment Scene has no other logic than that, but in future releases it might have
additional logic. It is a good practice to use a Scene as the parent of all your nodes.
*/
class CC_DLL Scene : public Node
{
public:
/** creates a new Scene object */
static Scene *create(); // Overrides
virtual Scene *getScene() override; using Node::addChild;
virtual std::string getDescription() const override; CC_CONSTRUCTOR_ACCESS:
Scene();
virtual ~Scene(); virtual bool init() override; protected:
friend class Node;
friend class ProtectedNode;
friend class SpriteBatchNode; private:
CC_DISALLOW_COPY_AND_ASSIGN(Scene); #if CC_USE_PHYSICS
public:
virtual void addChild(Node* child, int zOrder, int tag) override;
virtual void update(float delta) override;
inline PhysicsWorld* getPhysicsWorld() { return _physicsWorld; }
static Scene *createWithPhysics(); CC_CONSTRUCTOR_ACCESS:
bool initWithPhysics(); protected:
void addChildToPhysicsWorld(Node* child); PhysicsWorld* _physicsWorld;
#endif // CC_USE_PHYSICS
};

这个类并且不复杂,类的注释里面说的已经很清楚了,大致给了以下信息

  1. Scene 类和Node 类差异不多,只是抽象上的一个场景概念
  2. Scene 类与Node 类的差别在于,Scene 创建后默认锚点为正中心位置
  3. Scene 类目前 版本没有自己的额外逻辑,以后的版本可能会增加些逻辑
  4. 在我们开发应用中,最好将Scene设置成所有结点的根结点。也就是以Scene为单位,所有的Node都为Scene的子结点。

我们看一下成员变量,这个类只比Node增加了一个成员变量

PhysicsWorld* _physicsWorld;

从命名上可以了解,这是用来描述物理属性的一个变量,从这点可以知道,Scene支持物理特性。

下面我们看一下构建对象的方法

Scene *Scene::create()
{
Scene *ret = new Scene();
if (ret && ret->init())
{
ret->autorelease();
return ret;
}
else
{
CC_SAFE_DELETE(ret);
return nullptr;
}
}

与Node结点的Create函数的结构一样,所有Scene对象都要从这个函数来创建。

创建过程主要是init方法。

下面看一下init函数。

bool Scene::init()
{
bool ret = false;
do
{
Director * director;
CC_BREAK_IF( ! (director = Director::getInstance()) );
this->setContentSize(director->getWinSize());
// success
ret = true;
} while ();
return ret;
}

这个函数只干了一件事,一是设置了Scene的大小,从director对象得到了容器的大小,然后将场景的大小设置成窗口大小。

接下来我们看一下Scene构造函数。

Scene::Scene()
#if CC_USE_PHYSICS
: _physicsWorld(nullptr)
#endif
{
_ignoreAnchorPointForPosition = true;
setAnchorPoint(Point(0.5f, 0.5f));
}

构造函数里面设置了Scene的锚点位置,使用了 _ignoreAnchorPointForPosition  忽略了函数的绝对位置,并且将锚点设置在中心位置 0.5 ,0.5

在上面一系列结点构建的方法中 我们并没有看到物理属性的初始化。

Scene类还有一种创建对象的方法就是带有物理属性的Scene对象创建。

static Scene *createWithPhysics();

bool initWithPhysics();

这两个方法就是创建带有物理属性的Scene对象的方法。 里面的实现过程与和面的非物理结点的创建基本一样,就是增加了对_physicsWorld这个成员变量的初始化过程。

在Scene类还有几个重载的函数

virtual void addChild(Node* child, int zOrder, int tag) override;
virtual void update(float delta) override;

这两个方法实现上都是调用了基类Node的相应方法,唯一的区别就是多了一个物理属性操作的步骤。

好啦,Scene类的源码就分析到这个,其实Scene就是一个概念上的与其它的Node做了一个区分,从源码上来看,确实没有什么特殊的逻辑,就是Node结点的一个简单封装。

接下来,我们分析Layer类先看头文件。

打开CClayer.h文件我们可以找到与layer相关的五个类,先看Layer类。

Layer类中有很多方法都被声明否决了,也就是将在以后的版本会被废弃,这些声明否决的函数我们就不做分析了。下面看一下我整理好的完整的layer类。

class CC_DLL Layer : public Node
{
public:
/** creates a fullscreen black layer */
static Layer *create(); /* Callback function should not be deprecated, it will generate lots of warnings.
Since 'setTouchEnabled' was deprecated, it will make warnings if developer overrides onTouchXXX and invokes setTouchEnabled(true) instead of using EventDispatcher::addEventListenerWithXXX.
*/
virtual bool onTouchBegan(Touch *touch, Event *unused_event);
virtual void onTouchMoved(Touch *touch, Event *unused_event);
virtual void onTouchEnded(Touch *touch, Event *unused_event);
virtual void onTouchCancelled(Touch *touch, Event *unused_event); virtual void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);
virtual void onTouchesCancelled(const std::vector<Touch*>&touches, Event *unused_event);
/* Callback function should not be deprecated, it will generate lots of warnings.
Since 'setAccelerometerEnabled' was deprecated, it will make warnings if developer overrides onAcceleration and invokes setAccelerometerEnabled(true) instead of using EventDispatcher::addEventListenerWithXXX.
*/
virtual void onAcceleration(Acceleration* acc, Event* unused_event); /* Callback function should not be deprecated, it will generate lots of warnings.
Since 'setKeyboardEnabled' was deprecated, it will make warnings if developer overrides onKeyXXX and invokes setKeyboardEnabled(true) instead of using EventDispatcher::addEventListenerWithXXX.
*/
virtual void onKeyPressed(EventKeyboard::KeyCode keyCode, Event* event);
virtual void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event); // Overrides
virtual std::string getDescription() const override; CC_CONSTRUCTOR_ACCESS:
Layer();
virtual ~Layer(); virtual bool init() override; protected:
bool _touchEnabled;
bool _accelerometerEnabled;
bool _keyboardEnabled;
EventListener* _touchListener;
EventListenerKeyboard* _keyboardListener;
EventListenerAcceleration* _accelerationListener; Touch::DispatchMode _touchMode;
bool _swallowsTouches; private:
CC_DISALLOW_COPY_AND_ASSIGN(Layer); };

先整体看一下,Layer类也是Node类的子类,增加了对事件的侦听,有几个成员变量

EventListener* _touchListener;
EventListenerKeyboard* _keyboardListener;
EventListenerAcceleration* _accelerationListener;

也就是说,Layer类就是可以响应事件的Node结点。它包含的事件有 触摸,键盘,重力计。

既然知道了Layer类增加了Node对事件的支持,那么我们来找一下事件的侦听与回调都在什么位置。

在上面我整理出来的一个非否决版本的头文件中并没有发现侦听事件的函数。小鱼仔细的看了一下头文件源码。发现了一个函数下面着重分析一下。

void Layer::setTouchEnabled(bool enabled)
{
if (_touchEnabled != enabled)
{
_touchEnabled = enabled;
if (enabled)
{
if (_touchListener != nullptr)
return; if( _touchMode == Touch::DispatchMode::ALL_AT_ONCE )
{
// Register Touch Event
auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesBegan = CC_CALLBACK_2(Layer::onTouchesBegan, this);
listener->onTouchesMoved = CC_CALLBACK_2(Layer::onTouchesMoved, this);
listener->onTouchesEnded = CC_CALLBACK_2(Layer::onTouchesEnded, this);
listener->onTouchesCancelled = CC_CALLBACK_2(Layer::onTouchesCancelled, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
_touchListener = listener;
}
else
{
// Register Touch Event
auto listener = EventListenerTouchOneByOne::create();
listener->setSwallowTouches(_swallowsTouches); listener->onTouchBegan = CC_CALLBACK_2(Layer::onTouchBegan, this);
listener->onTouchMoved = CC_CALLBACK_2(Layer::onTouchMoved, this);
listener->onTouchEnded = CC_CALLBACK_2(Layer::onTouchEnded, this);
listener->onTouchCancelled = CC_CALLBACK_2(Layer::onTouchCancelled, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
_touchListener = listener;
}
}
else
{
_eventDispatcher->removeEventListener(_touchListener);
_touchListener = nullptr;
}
}
}

这个函数作用是设置是否启用触摸事件,如果启动触摸事件,那么就会创建Touch的侦听器并且加入到了侦听队列里面。

我们可以看到 onTouchesBegan, onTouchesMoved, onTouchesEnded, onTouchesCancelled 四个函数就是相应的触摸过程的回调函数。

小结:

Layer是一个带有事件侦听的Node,Layer类里有很多声明否决的方法,如果要实现自己的事件回调,那么继承Layer然后重载它的回调方法,这块使我们回想到最开始我们看到的HelloWorld例子,那里面HelloWorld就是继承了Layer,并且在上面加了一些东西。

关于Layer的构造函数与析构函数与Scene差不多,这里我们就不多分析了。

CCLayer.h里面还有关于Layer的其它几个类,大家可以看一下,就是在Layer上面又扩展了一些功能,

__LayerRGBA 扩展对 __RGBAProtocol接口的实现

LayerColor 扩展了颜色的混合。

LayerGradient 扩展了颜色的渐变。

LayerMultiplex 扩展了多层变化。

本章节先到这里,下一节,我们分析CCTransition的源码。