Cocos2d-x mobile game source code
In the previous chapter, we analyze the source code of scene and layer-related classes, and have a preliminary understanding of the Cocos2d-x scenario. In this chapter, we will analyze the scenario transformation transitionscene source code.
Let's look at the definition of transitionscene.
class CC_DLL TransitionScene : public Scene{public: /** Orientation Type used by some transitions */ enum class Orientation { /// An horizontal orientation where the Left is nearer LEFT_OVER = 0, /// An horizontal orientation where the Right is nearer RIGHT_OVER = 1, /// A vertical orientation where the Up is nearer UP_OVER = 0, /// A vertical orientation where the Bottom is nearer DOWN_OVER = 1, }; /** creates a base transition with duration and incoming scene */ static TransitionScene * create(float t, Scene *scene); /** called after the transition finishes */ void finish(void); /** used by some transitions to hide the outer scene */ void hideOutShowIn(void); // // Overrides // virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override; virtual void onEnter() override; virtual void onExit() override; virtual void cleanup() override; CC_CONSTRUCTOR_ACCESS: TransitionScene(); virtual ~TransitionScene(); /** initializes a transition with duration and incoming scene */ bool initWithDuration(float t,Scene* scene); protected: virtual void sceneOrder(); void setNewScene(float dt); Scene *_inScene; Scene *_outScene; float _duration; bool _isInSceneOnTop; bool _isSendCleanupToScene;private: CC_DISALLOW_COPY_AND_ASSIGN(TransitionScene);};
This class is not big. We can see from the Class header information inheritance relationship that the scenario switching class is actually a scenario.
The old rule is to analyze the member variables first.
The transitionscene class has a total of five member variables. These five variables can be guessed from the variable name.
SCENE * _ inscene; // The scenario pointer SCENE * _ outscene for scenario switching; // The scenario pointer float _ duration for scenario switching; // time consumed by scenario switching bool _ isinsceneontop; // The scene switching description specifies the rendering hierarchy between the cut-in scenario and the cut-out scenario. True indicates that the cut-in scenario is at the top layer of the cut-out scenario bool _ issendcleanuptoscene; // indicates whether the clear command has been sent to the switch-out scenario.
Here, we can guess the process in which the transitionscene class implements scenario switching,
Transitionscene is an intermediary scenario. It holds the scene (_ inscene) on the left and the scene (_ outscene) on the right ), let these two scenes complete the process of switching the scene in a gorgeous way on your own, and finally exit the intermediary scenario and hand over the stage to the new scene.
We have guessed the principle of implementing scenario switching in transitionscene. We are curious about the specific process of implementing scenario switching and scenario switching in transitionscene? Are we guessing that the switching principle is correct?
Let's continue to look at the source code to find the answer.
We start with the method for creating transitionscene.
The constructor of transitionscene is an empty function ignored. Let's take a look at the static method transitionscene: Create to start analysis.
TransitionScene * TransitionScene::create(float t, Scene *scene){ TransitionScene * pScene = new TransitionScene(); if(pScene && pScene->initWithDuration(t,scene)) { pScene->autorelease(); return pScene; } CC_SAFE_DELETE(pScene); return nullptr;}
See the structure of the create function familiar can no longer be familiar with, in the basic year of Cocos2d-x node class and subclass creation is this structure.
Next, let's take a look at the initwithduration initialization method.
bool TransitionScene::initWithDuration(float t, Scene *scene){ CCASSERT( scene != nullptr, "Argument scene must be non-nil"); if (Scene::init()) { _duration = t; // retain _inScene = scene; _inScene->retain(); _outScene = Director::getInstance()->getRunningScene(); if (_outScene == nullptr) { _outScene = Scene::create(); } _outScene->retain(); CCASSERT( _inScene != _outScene, "Incoming scene must be different from the outgoing scene" ); sceneOrder(); return true; } else { return false; }}
Judging from the parameters of this function, this initialization function initializes a scenario switching mediation scenario (transitionscene) by specifying the scenario switching duration and the scenario pointer to be switched).
Initial process of transitionscene instance
- Call the scene Initialization Method of the base class. Scene: init
- Assign a value to the passed duration parameter _ duration = T;
- Cut-in scenario assignment _ inscene = scene; note that a reference to the cut-in scenario is added here, because a cut-in scenario is referenced in the mediation scenario, so a reference count is added.
- The output scenario value indicates that the current director class is running through Director: getinstance ()-> getrunningscene (); we can get the value assigned to _ outscene for the currently running scenario. If there is no running scenario, an empty scenario will be created as the output scenario, in addition, a pair is added to the reference count of the scene.
- After the sceneorder () function is called, the name of this function indicates that the scenario is sorted once. What have you done? The following is an analysis of sceneorder.
void TransitionScene::sceneOrder(){ _isInSceneOnTop = true;}
Sceneorder: This is a virtual function. The process is very simple. It only sets the _ isinsceneontop mark to specify the hierarchy between the scene and the scene, that is, who is on whom.
After creating a transitionscene instance, we have analyzed how the scenario switching process is implemented.
Take a look at the transitionscene Class header file and find the following functions.
virtual void draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated) override; virtual void onEnter() override; virtual void onExit() override; virtual void cleanup() override;
The functions of these four functions are as follows:
Draw Rendering Method
Called when the onenter mediation scenario enters the stage
Called when the onexit mediation scenario exits the stage
Clearup cleanup scenario method.
Read onenter for one analysis
void TransitionScene::onEnter(){ Scene::onEnter(); // disable events while transitions _eventDispatcher->setEnabled(false); // outScene should not receive the onEnter callback // only the onExitTransitionDidStart _outScene->onExitTransitionDidStart(); _inScene->onEnter();}
Function Process Analysis:
- Call the onenter of the scene base class
- The event distributor is set to unavailable. Scene switching is an animation process in which events are not processed to avoid unexpected errors.
- Call the onexittransitiondidstart method of the cut-out scenario. Friends who have read the previous chapters should still be impressed. This method is defined in the node base class, and the function meaning is the callback method at the beginning of Scene Change. It is reasonable to call this method when the current scenario leaves when the intermediary scenario enters the stage.
- At last, the onenter of the scenario is called. There is no problem at all. When the scenario is switched out, it begins to exit and enters the stage. This is the process in which the intermediary scenario is exchanged between the left and right hands.
Let's look at the onexit method again.
void TransitionScene::onExit(){ Scene::onExit(); // enable events while transitions _eventDispatcher->setEnabled(true); _outScene->onExit(); // _inScene should not receive the onEnter callback // only the onEnterTransitionDidFinish _inScene->onEnterTransitionDidFinish();}
Function Process Analysis:
- Call the onexit method of the base class scene.
- The availability of the event distributor is restored.
- Call the exit callback for the cut-out scenario
- Call the callback for entry completion in the cut-in scenario.
We can compare the onenter and onexit methods.
Through analysis, we can understand the sequence of function calls from the scene to the stage. Here we will summarize it.
Enter the stage ----> exit the stage. (The stage here can be understood as the area that can be displayed on the screen)
Onenter (enter stage) ---> onentertransitiondidfinish (enter complete) ---> onexittransitiondidstart (start to exit stage) ---> onexit (Exit)
After learning about the sequence of function calls in the scenario, we can understand what the onexit and onenter functions in the mediation scenario do.
When an intermediary scenario enters the stage, it is precisely when the scenario is switched out and the scenario is switched into the stage.
The intermediary scenario is now on the stage, the scenario is finished, and the scenario is switched off the stage.
At this time, both the mediation scenario and the scene were taken off the stage, leaving the scene to be switched.
Next, let's take a look at the other two virtual functions.
void TransitionScene::draw(Renderer *renderer, const kmMat4 &transform, bool transformUpdated){ Scene::draw(renderer, transform, transformUpdated); if( _isInSceneOnTop ) { _outScene->visit(renderer, transform, transformUpdated); _inScene->visit(renderer, transform, transformUpdated); } else { _inScene->visit(renderer, transform, transformUpdated); _outScene->visit(renderer, transform, transformUpdated); }}
The draw method has no difficulty, that is, based on _ isinsceneontop, the entries recorded here cut in two scene hierarchies for separate rendering.
void TransitionScene::cleanup(){ Scene::cleanup(); if( _isSendCleanupToScene ) _outScene->cleanup();}
The clearup method also calls other clearup methods and then clears the scene based on whether the _ issendcleanuptoscene mark has been cleared.
Next, let's take a look at the methods of transitionscene.
void TransitionScene::finish(){ // clean up _inScene->setVisible(true); _inScene->setPosition(Point(0,0)); _inScene->setScale(1.0f); _inScene->setRotation(0.0f); _inScene->setAdditionalTransform(nullptr); _outScene->setVisible(false); _outScene->setPosition(Point(0,0)); _outScene->setScale(1.0f); _outScene->setRotation(0.0f); _outScene->setAdditionalTransform(nullptr); //[self schedule:@selector(setNewScene:) interval:0]; this->schedule(schedule_selector(TransitionScene::setNewScene), 0);}
This finish method is called when the scenario switching is complete.
The function process in it is also very simple. You can set the switch-in scenario to the display status, switch-out scenario not to be displayed, and restore the rotation, scaling, and position of the scenario to the initial state.
It is worth noting that the callback function is added to the timer transitionscene: setnewscene. The callback interval is 0, that is, it will be called at the next frame.
Next, let's take a look at what this setnewscene function does.
void TransitionScene::setNewScene(float dt){ CC_UNUSED_PARAM(dt); this->unschedule(schedule_selector(TransitionScene::setNewScene)); // Before replacing, save the "send cleanup to scene" Director *director = Director::getInstance(); _isSendCleanupToScene = director->isSendCleanupToScene(); director->replaceScene(_inScene); // issue #267 _outScene->setVisible(true);}
This function has a parameter but is not used. It may be reserved.
In this function, the director class is used to clear the scene tag and assigned the Variable _ issendcleanuptoscene.
Note this line of code Director-> replacescene (_ inscene );
We know that Director manages the scenario and can only have one runningscene. This line of code actually gives the stage through director to the scenario we want to cut in (_ inscene)
void TransitionScene::hideOutShowIn(){ _inScene->setVisible(true); _outScene->setVisible(false);}
FunctionHideoutshowinHide and show cut-in scenes. There is nothing to say.
All the methods in the transitionscene class have been analyzed. You may have some questions.
- We only analyzed the callbacks for some scenarios to cut into the stage and leave the stage, but did not see the switching process for those dynamic scenarios.
- How do intermediary scenarios enter the stage? How can I use an intermediary scenario for scenario switching?
- The finish function is not called, so it seems that the name is actually saved.
With questions, we continue to look for answers in the source code.
Let's take a look at the header file cctransition. H. In addition to transitionscene, it also defines a lot of sub-classes of the transitionscene class. Next we will select a class to analyze it.
/** @brief TransitionRotoZoom:Rotate and zoom out the outgoing scene, and then rotate and zoom in the incoming */class CC_DLL TransitionRotoZoom : public TransitionScene{public: static TransitionRotoZoom* create(float t, Scene* scene); // // Overrides // virtual void onEnter() override;protected: TransitionRotoZoom(); virtual ~TransitionRotoZoom();private: CC_DISALLOW_COPY_AND_ASSIGN(TransitionRotoZoom);};
Let's take a look at the comments of this class. The scene is scaled and rotated, and the scene is rotated and scaled.
The transitionrotozoom class inherits the transitionscene class and does not add any attributes and methods. Instead, the onenter method is overloaded. What changes are there in onenter?
Follow-up code:
void TransitionRotoZoom:: onEnter(){ TransitionScene::onEnter(); _inScene->setScale(0.001f); _outScene->setScale(1.0f); _inScene->setAnchorPoint(Point(0.5f, 0.5f)); _outScene->setAnchorPoint(Point(0.5f, 0.5f)); ActionInterval *rotozoom = (ActionInterval*)(Sequence::create ( Spawn::create ( ScaleBy::create(_duration/2, 0.001f), RotateBy::create(_duration/2, 360 * 2), nullptr ), DelayTime::create(_duration/2), nullptr )); _outScene->runAction(rotozoom); _inScene->runAction ( Sequence::create ( rotozoom->reverse(), CallFunc::create(CC_CALLBACK_0(TransitionScene::finish,this)), nullptr ) );}
I saw the onenter implementation, which is so interesting. There are animations, latencies ....... Start analysis.
Onenter function process:
- Call the onenter of the base class to connect the onenter and onexit-related scenario process callback.
- Set the cut-in scene to 0.001 times the size of the cut-in scene to the original size.
- Place the point of the cut-in and cut-out scenario in the center of the scenario.
- Here is a new class actioninterval, which is named as an animation class. Here we set two change processes, one being scaling and the other being rotating. This action is executed in the switch-out scenario.
- The previously defined action process rotozoom-> reverse () is reversed in the scenario ()
- A callback function callfunc: Create (cc_callback_0 (Transitionscene: Finish, This), haha, here we seeTransitionscene: FinishThis function is completely understandable here. When the scene animation is played completely, the intermediate scene's finish method is called. In the finish method, the replacescene method of ctor Ctor is used to add the scenario to the stage.
Note: actioninterval and other animation-related classes are used here. Here we only need to know the approximate functions of these animation classes. We will analyze the subsequent chapters one by one.
Ainemo wrote a demo to show you the procedure of switching the transitionrotozoom scenario.
Through the analysis of transitionrotozoom, a derived class of the transitionscene class, we understand the action process of the transitionscene class, which is summarized as follows:
- The transitionscene class is the base class for scenario switching, and the scenario effects of Cocos2d-x all inherit this class. However, this class does not have any effect on switching scenarios. It only provides several function interfaces, such as onenter onexit, and reloads these interface functions in the subclass to implement switching in specific scenarios.
- The transitionscene series class is the intermediary class of a scenario. In this class, onenter and onexit of the scenario are called one after another.
- If you define the effect of scenario switching, do not forget to callTransitionscene: FinishMethod.
Now all the above three questions have been answered.
Some readers may have questions.
Here, I will discuss the association between scenario switching and director class and engine.
First, let's talk about how to use the transitionscene class.
See the following code.
auto visibleSize = Director::getInstance()->getVisibleSize(); Scene *myScene = Scene::create(); Sprite * sp = Sprite::create("mv2.jpg"); sp->setPosition( visibleSize.width / 2, visibleSize.height / 2 ); myScene->addChild( sp ); TransitionRotoZoom *tranScene = TransitionRotoZoom::create( 2.0, myScene ); Director::getInstance()->replaceScene( tranScene );
This example shows the code snippet of the GIF image above. It mainly uses the transitionrotozoom change.
The first five lines of code are simple, that is, I created a new scenario called scenario 2. I put an image on scenario 2.
Line 6: I created a transitionrotozoom scenario to switch the object instance, set the switching time to 2 seconds, and pass scenario 2 as the output scenario.
Line 7: Find the Director Instance Object and use scenario 2 to replace the current scenario.
The above results are achieved with these lines of code.
In a word, the intermediate scenario of scenario change is added to the stage during scenario switching. We have analyzed the mediation scenario above. At the end, we will actually replace the scenario into the stage.
For better understanding, the above instance code is used as an example to analyze the code of several broken ctor related functions here.
Let's first look at what replacescene has done.
Void Director: replacescene (SCENE * scene) // The input scene is our mediation scenario myscene {ccassert (_ runningscene, "Use runwithscene: instead to start the Director "); ccassert (scene! = Nullptr, "the scene shocould not be null"); If (_ nextscene) // if you have specified the next scene to be switched, release the next scene here. {If (_ nextscene-> isrunning () {_ nextscene-> onexittransitiondidstart (); _ nextscene-> onexit () ;}_ nextscene-> cleanup (); _ nextscene = nullptr;} // put myscene to the top of the scene stack and modify _ nextscene to myscene ssize_t Index = _ scenesstack. size (); _ sendcleanuptoscene = true; _ scenesstack. replace (index-1, Scene); _ nextscene = scene;} // After the function is completed, _ nextscene in ctor Ctor is our myscene. In the main loop of each director frame, let's look for the processing of _ nextscene.
Let's review mainctor's mainloop.
Void displaylinkdirector: mainloop () {If (_ purgedirectorinnextloop) {_ purgedirectorinnextloop = false; purgedirector ();} else if (! _ Invalid) {drawscene (); // you do not need to check the other settings. We will follow up with drawscene to find the processing method for _ nextscene. // Release the objects poolmanager: getinstance ()-> getcurrentpool ()-> clear ();}}
The following is the code snippet of drawscene.
Void Director: drawscene (){............ // Omitted above
/* To avoid Flickr, nextscene must be here: After tick and before draw. XXX: Which bug is this one. it seems that it can't be reproduced with v0.9 */If (_ nextscene) // There are _ nextscene processing in drawscene, in this case, _ nextscene is the myscene {setnextscene ();} kmglpushmatrix ();
............ // Omitted below}
Follow up the setnextscene method.
Void Director: setnextscene () {// note the following two conversions, in this case, _ runningscene is a common scene in scenario 1. Therefore, when performing dynamic_cast conversion, It is null bool runningistransition = dynamic_cast <transitionscene *> (_ runningscene )! = Nullptr; // here runningistransition = false bool newistransition = dynamic_cast <transitionscene *> (_ nextscene )! = Nullptr; // here newistransition = true // if it is not a transition, call onexit/cleanup if (! Newistransition) // because _ nextscene is of the transiton type, this if judgment will not walk in {If (_ runningscene) {_ runningscene-> onexittransitiondidstart (); _ runningscene-> onexit ();} // issue #709. the root node (scene) shocould receive the cleanup message too // otherwise it might be leaked. if (_ sendcleanuptoscene & _ runningscene) {_ runningscene-> cleanup () ;}} if (_ runningscene) // The reference count of _ runningscene is released here, because _ runningscene needs Replaced by _ nextscene {_ runningscene-> release ();} _ runningscene = _ nextscene; // _ nextscene adds a reference count _ nextscene-> retain (); _ nextscene = nullptr; If ((! Runningistransition) & _ runningscene) // This Judgment will enter, if you do not understand it, think carefully. Although the current _ runningscene is of the Transition type, the _ nextscene has not been replaced when we get the runningistransition value. {_ Runningscene-> onenter (); // Finally, the onenter in the mediation scenario myscene is called here, and then there is a series of rotation and scaling changes. This is the process of analyzing the transitionscene class. Wait until the finish method of myscene switches scenario 2 to the stage. _ Runningscene-> onentertransitiondidfinish ();}}
Well, today's content is basically the same.
Through the above analysis we have Cocos2d-x scene change is how to do. Here I only give you an instance, if you want to know more about the Cocos2d-x are prepared for us which changes to the scenario, you may wish to make the cctransition. H class inside the demo have a try.
Today, we have encountered an action-related class in our analysis. Now we only know that it has something to do with animation changes. What exactly are the actions series?
Well, let's get it done. We will analyze the action-related source code in the next chapter.