Cocos2d-x v3.2 FlappyBird Class Object code analysis (5)
Today we will introduce the MPs queue layer.
PipeLayer. h
PipeLayer. cpp
The main purpose of the MPs queue layer is to translate the MPs queue from the right to the left and remove the MPs queue after it is finished. In addition, the MPs queue length is different, and then how to determine whether a bird passes through a media transcoding queue. Let's talk about the pipeline translation. This is very simple. We can use a function to encapsulate the two pipelines and make them moveby or moveto. After the translation, we can use a callback function to remove ourselves, of course, after encapsulating the pipeline, we need to put every pipeline in an array for easy management. Then, the pipeline height is different. Here we use a picture to represent it:
Finally, the bird judges through the pipeline. Here we determine whether a complete pipeline passes through the center line of the screen (because the bird is fixed in the center of the screen and moves up and down ). This class is about this content.
The figure below explains why the physical model of the upward pipeline should be canceled after the pipeline stops moving to prevent the bird from directly falling into the pipeline after it dies:
The following is code analysis:
// PipeLayer. h # pragma once # include "cocos2d. h" class PipeLayer: public cocos2d: Layer {public: PipeLayer ();~ PipeLayer (); bool init (); // Add a mobile combined MPs queue void addPipe (float); // callback function void pipeMoveOver (cocos2d :: ref *); // The pipeline stops moving void stopPipe (); // The timer executes the void update (float) function; // The pipeline begins to move void startPipe (); CREATE_FUNC (PipeLayer ); private: // cocos2d: Array * pipe_arr; // cocos2d: Array * pipe_arr2; bool btn ;};
// PipeLayer. cpp # include "PipeLayer. h" # include "define. h" # include "NumberLayer. h" USING_NS_CC; PipeLayer: PipeLayer () {} PipeLayer ::~ PipeLayer () {// destructor release array pipe_arr-> release (); pipe_arr2-> release ();} bool PipeLayer: init () {if (! Layer: init () {return false;} // initialize two arrays. In fact, only one array is enough, when I first started writing, I was dumb. // The pipe_arr Array is used to detect the extra points. // pipe_arr2 Array is used to facilitate unified processing of pipeline pipe_arr = Array: create (); // prevent automatically released pipe_arr-> retain (); pipe_arr2 = Array: create (); pipe_arr2-> retain (); btn = true; return true;} void PipeLayer:: addPipe (float) {log ("this pipe"); // initialize auto pipe_up = Sprite: createWithSpriteFrameName ("pipe_up.png") to the upper pipe "); pipe_up-> setPosition (Point (pipe_up-> getContentSize (). width/2, pipe_up-> getContentSize (). height/2); auto body_up = PhysicsBody: create (); auto body_shape_up = PhysicsShapeBox: create (pipe_up-> getContentSize (); body_up-> addShape (body_shape_up ); body_up-> setDynamic (false); body_up-> setGravityEnable (false); body_up-> setCategoryBitmask (1); body_up-> setCollisionBitmask (-1 ); body_up-> setContactTestBitmask (-1); pipe_up-> setPhysicsBody (body_up); // initialize the downstream pipeline. The THROUGH_HEIGHT here is the gap between the two pipelines. auto pipe_down = Sprite :: createWithSpriteFrameName ("pipe_down.png"); pipe_down-> setPosition (Point (pipe_down-> getContentSize (). width/2, pipe_down-> getContentSize (). height/2 + pipe_up-> getContentSize (). height + THROUGH_HEIGHT); auto body_down = PhysicsBody: create (); auto body_shape_down = PhysicsShapeBox: create (pipe_down-> getContentSize (); body_down-> addShape (Lag ); body_down-> setDynamic (false); body_down-> setGravityEnable (false); body_down-> setCategoryBitmask (1); body_down-> setCollisionBitmask (-1 ); body_down-> setContactTestBitmask (-1); pipe_down-> setPhysicsBody (body_down ); // The node here is equivalent to a container that encapsulates the two pipelines in one node and sets targetauto Node = node: create (); node-> addChild (pipe_up, 0, PIPE_UP); node-> addChild (pipe_down, 0, PIPE_DOWN); node-> setAnchorPoint (Point: ANCHOR_BOTTOM_LEFT ); // for setting the Y coordinate of the MPs Queue (that is, handling different upper and lower lengths of the MPs Queue), check the legend and make it unclear. // The MPs queue is moved from the right to the left, therefore, the PIPE_X value must be greater than the game width. Here it is set to 300int range = rand () % PIPE_RANGE; node-> setPosition (Point (PIPE_X, PIPE_Y + range )); // The pipeline movement time, distance, and direction auto moveby = MoveBy: create (PIPE_TIME, PIPE_VELOCITY); // The callback function auto callback = CallFuncN :: create (CC_CALLBACK_1 (PipeLayer: pipeMoveOver, this); // put the callback after the pipeline is moved and ended into the queue auto sequence = Sequence: create (moveby, callback, NULL); node-> runAction (sequence); this-> addChild (node); // put the pipeline in two arrays pipe_arr-> addObject (node ); pipe_arr2-> addObject (node); // start the timer, which is used to determine the score // that is, whether the bird passes through the pipeline // It is enough to start once, so here there is a btnif (btn) {this-> scheduleUpdate (); btn = false ;}// after moving, remove the pipe void PipeLayer from the class and array :: pipeMoveOver (Ref * r) {Sprite * sp = (Sprite *) r; this-> removeChild (sp); pipe_arr2-> removeObject (sp );} // stop pipeline Movement (after bird death) void PipeLayer: stopPipe () {this-> unschedule (schedule_selector (PipeLayer: addPipe); this-> unscheduleUpdate (); // the physical structure of the upward pipeline is canceled here. // This is done so that when the bird hits the downward pipeline, it will die and will not fall onto the upward pipeline. // see the legend Ref * p; CCARRAY_FOREACH (pipe_arr2, p) {auto n = (Node *) p; // The pipeline stops moving n-> stopAllActions (); // cancel the physical structure n-> getChildByTag (PIPE_UP)-> getPhysicsBody ()-> setEnable (false); }}// point void PipeLayer: update (float) {auto origin = Director: getInstance ()-> getVisibleOrigin (); auto visibleSize = Director: getInstance ()-> getVisibleSize (); // if the number of pipelines is 0, if (pipe_arr-> count () <= 0) {return ;}// obtain the first pipe (the first generated pipe) in the MPs queue array) // Node * tn = (Node *) pipe_arr-> getObjectAtIndex (0) at the beginning of the MPs queue movement; // if the overall MPs queue is half of the scenario, then add points // At the same time, remove this pipe from this array // so that the next pipe located after this pipe will become the front pipe. // For example: // index: 0 1 2 3 4 // array: a B C D E // pipeline // This is A pipe with A sequence of 0. when it passes through the scene point, it is removed from the array, and then it becomes // index: 0 1 2 3 4 // arrat: B c d e f // pipeline B will become the sequence 0, then check if (tn-> getPositionX () <(visibleSize. width/2-52) {log ("X: % f", tn-> getContentSize (). width); pipe_arr-> removeObjectAtIndex (0); CocosDenshion: SimpleAudioEngine: getInstance ()-> playEffect ("sounds/sfx_pointmask"); NumberLayer: getInstance () -> addScore () ;}}// the pipeline starts to move void PipeLayer: startPipe () {this-> schedule (schedule_selector (PipeLayer: addPipe), PIPE_FRE );}
End