本章節我們重點分析Cocos2d-x3.0與 場景、層相關的源碼。這部分源碼集中在 libcocos2d –> layers_scenes_transitions_nodes目錄下面
我先發個截圖大家了解一下都有哪些文件。紅色框里面的就是我們今天要分析的文件。
從命名上可以了解,這個文件夾里的文件主要包含了 場景,層,變換這三種類型的文件。
下面我們先分析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 };
這個類並且不復雜,類的注釋里面說的已經很清楚了,大致給了以下信息
- Scene 類和Node 類差異不多,只是抽象上的一個場景概念
- Scene 類與Node 類的差別在於,Scene 創建后默認錨點為正中心位置
- Scene 類目前 版本沒有自己的額外邏輯,以后的版本可能會增加些邏輯
- 在我們開發應用中,最好將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 (0); 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的源碼。