There is a series of blogs in the COCOS2DX community that completely replicates all the features of the original Flappybird. It's just that the code is more complicated, the novice learns a little bit elusive, here I wrote a simple version number. The demo sample is as follows:
watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvdtaxmjizndexnq==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">
Create a projectVS2013+COCOS2DX 3.2 Create the Win32 project. Because it's just learning, there's no executable file compiled for Android, iOS, or WP platforms. Finally the project structure for projects such as the following:
watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvdtaxmjizndexnq==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">
Very easy, there are only three classes, pre-loaded classes. Game main scene class, application proxy class. Beginners just like to write a lot of things in as few classes as possible.
Game Design game structure such as the following, the game includes pre-loaded scenes and main scenes, the main scene includes the background, birds, pipelines and various UI interface.
watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvdtaxmjizndexnq==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">
Development Steps 1, Material collection extract some pictures and audio from the APK file, and use Texturepatcher to build a large image and export the plist file.
2. Pre-loading the scene creates a new Loadingscene, adds a boot image to it, adds all the picture footage, the bird frame animation, and the audio file to the cache in a way that asynchronously loads the texture and callbacks to the game's main scene after loading is complete.
Add the load callback function to load the texture director::getinstance ()->gettexturecache ()->addimageasync ("Game.png", Cc_callback_1 ( Loadingscene::loadingcallback, this));
void Loadingscene::loadingcallback (Texture2d *texture) {//Pre-loaded frame cache texture Spriteframecache::getinstance () Addspriteframeswithfile ("game.plist", texture);//pre-loading frame animation Auto Birdanimation = Animation::create ();birdanimation-> Setdelayperunit (0.2f); Birdanimation->addspriteframe (Spriteframecache::getinstance () Getspriteframebyname ("Bird1.png")); Birdanimation->addspriteframe (Spriteframecache::getinstance () Getspriteframebyname ("Bird2.png")); Birdanimation->addspriteframe (Spriteframecache::getinstance () Getspriteframebyname ("Bird3.png")); Animationcache::getinstance ()->addanimation (birdanimation, "birdanimation"); Add a bird animation to the animation cache//pre-loaded Sound simpleaudioengine::getinstance ()->preloadeffect ("Die.mp3"); Simpleaudioengine::getinstance ()->preloadeffect ("Hit.mp3"); Simpleaudioengine::getinstance ()->preloadeffect ("Point.mp3"); Simpleaudioengine::getinstance ()->preloadeffect ("Swooshing.mp3"); Simpleaudioengine::getinstance ()->preloadeffect ("Wing.mp3");//load complete jump to game scene auto Gamescene = GAmescene::createscene (); Transitionscene *transition = transitionfade::create (0.5f, Gamescene);D irector::getinstance ()->replaceScene ( Transition);}
3, Game home View3.1. Background and logo with Picture Wizard can
Added game background Sprite *background = Sprite::createwithspriteframename ("Bg.png"); Background->setposition ( Visibleorigin.x + VISIBLESIZE.WIDTH/2, VISIBLEORIGIN.Y + VISIBLESIZE.HEIGHT/2); This->addchild (backGround);// Logoauto Gamelogo = Sprite::createwithspriteframename ("Bird_logo.png"); Gamelogo->setposition (visibleOrigin.x + VISIBLESIZE.WIDTH/2, VISIBLEORIGIN.Y + visiblesize.height/2+100); Gamelogo->setname ("logo"); This->addChild ( Gamelogo);
The logo will be hidden after the game starts.
3.2. Bird
Bird Birdsprite = Sprite::create (); Birdsprite->setposition (visibleorigin.x + VISIBLESIZE.WIDTH/3, VISIBLEORIGIN.Y + VISIBLESIZE.HEIGHT/2); This->addchild (birdsprite); auto Birdanim = Animate::create (Animationcache::getinstance ( )->animationbyname ("Birdanimation")); Birdsprite->runaction (Repeatforever::create (BirdAnim) ); Fin Animation Auto up = Moveby::create (0.4f, point (0, 8)), Auto Upback = Up->reverse (), if (gamestatus = = Game_ready) {Swingactio n = repeatforever::create (Sequence::create (UP, Upback, NULL)); Birdsprite->runaction (swingaction); Flick Animation}
In the preparation of the interface in addition to the wing of the movement, there are floating up and down movements.
3.3, the left shift of the floor floor is achieved by using two misplaced floor pictures to move left.
Need to use their own definition of the scheduler, pay attention to adjust the speed of movement.
Add two Landland1 = Sprite::createwithspriteframename ("Land.png"); Land1->setanchorpoint (Point::zero); Land1->setposition (Point::zero); This->addchild (Land1, ten); Place the topmost land2 = Sprite::createwithspriteframename ("Land.png"); Land2->setanchorpoint (Point::zero);land2-> SetPosition (Point::zero); This->addchild (Land2, 10);
Size visiblesize = director::getinstance ()->getvisiblesize ();//two pictures loop move land1->setpositionx (land1-> Getpositionx ()-1.0f); Land2->setpositionx (Land1->getpositionx () + land1->getcontentsize (). width-2.0f); if (Land2->getpositionx () <= 0) land1->setposition (Point::zero);
3.4, a group of water pipe from the upper and lower 2 half-root, with node wrapped up, get a vector container to join two sets of pipes. Each time out of the current screen of the pipe only two groups, when a group of disappeared in the screen range is reset its horizontal axis, you need to calculate the various spacing or height in advance.
There are only two tubes appearing on the same screen. Placed inside the container, bound to a for (int i = 0; i < 2; i++) {Auto visiblesize = director::getinstance ()->getvisiblesize (); Sprite *pipeup = Sprite::createwithspriteframename ("Pipe_up.png"); Sprite *pipedown = Sprite::createwithspriteframename ("Pipe_down.png"); Node *singlepipe = Node::create ();//bind rigid body to upper tube auto Pipeupbody = Physicsbody::createbox (Pipeup->getcontentsize ()); Pipeupbody->setdynamic (False);p Ipeupbody->setcontacttestbitmask (1);p Ipeup->setanchorpoint (Vec2:: Anchor_middle);p ipeup->setphysicsbody (pipeupbody);//Set a rigid body separately for two tubes. Can leave the middle of the gap so that the bird through//to the tube bound rigid body Auto Pipedownbody = Physicsbody::createbox (Pipedown->getcontentsize ());p ipedownbody- >setdynamic (False);p Ipedownbody->setcontacttestbitmask (1);p Ipedown->setanchorpoint (Vec2::ANCHOR_ Middle);p ipedown->setphysicsbody (pipedownbody);p ipeup->setposition (0, pipe_height + PIPE_SPACE); singlePipe- >addchild (Pipeup); Singlepipe->addchild (Pipedown); Pipedown By default add to (0,0), merge up and down, at this time singlepipe with the following pipe center as anchor Point SINGLEPIPE->SETPOSition (I*pipe_interval + wait_distance, getrandomheight ()); Set the initial height singlepipe->setname ("newpipe"); This->addchild (singlepipe); Add two tubes to the layer pipes.pushback (singlepipe); Two tubes successively added to the container}
Pipe rolling for (auto &singlepipe:pipes) {Singlepipe->setpositionx (Singlepipe->getpositionx ()-1.0f); Singlepipe->getpositionx () <-PIPE_WIDTH/2) {Singlepipe->setpositionx (VISIBLESIZE.WIDTH+PIPE_WIDTH/2); Singlepipe->setpositiony (Getrandomheight ()); Singlepipe->setname ("Newpipe"); Reset one tube at a time, labeled new}}
3.5. Adding physics to the World COCOS2DX 3.0 introduced the physics engine that comes with it, using methods like box2d and so on almost identical. Physical World Initialization
Gamescene->getphysicsworld ()->setgravity (VEC2 (0,-900)); Set gravitational field, the gravitational acceleration can be changed according to the feeling.
Gamelayer->setphysicworld (Gamescene->getphysicsworld ()); Binding the physical world
Bird bound Rigid Body
Bird binding rigid body Auto Birdbody = physicsbody::createcircle (Bird_radius); Think of the bird as a circle, too lazy to get the exact contour line birdbody->setdynamic (true); Set to be able to be action by the physical Place Birdbody->setcontacttestbitmask (1); This must be set for 1 talents to detect different objects colliding birdbody->setgravityenable (false); Whether the setting is affected by gravity, the preparation screen is not affected by gravity birdsprite->setphysicsbody (birdbody); Set up a rigid body for a bird
Floor-bound Rigid body
Set floor rigid body Node *groundnode = node::create (); Auto Groundbody = Physicsbody::createbox (Size (Visiblesize.width, land1-> Getcontentsize ()); Groundbody->setdynamic (false); Groundbody->setcontacttestbitmask (1); groundNode- >setanchorpoint (Vec2::anchor_middle); The rigid body in the physics engine only agrees that the node anchor is set to center Groundnode->setphysicsbody (groundbody); Groundnode->setposition (visibleorigin.x+ Visiblesize.width/2,land1->getcontentsize (). HEIGHT/2); This->addchild (Groundnode);
Pipe set rigid body, the upper and lower halves are set separately, leaving the middle gap
to the upper tube bound rigid body Auto Pipeupbody = Physicsbody::createbox (Pipeup->getcontentsize ());p ipeupbody->setdynamic (false); Pipeupbody->setcontacttestbitmask (1);p ipeup->setanchorpoint (vec2::anchor_middle);p ipeup-> Setphysicsbody (pipeupbody);//To set up a rigid body for two tubes, to allow the gap between the middle of the bird through//to the tube bound rigid body Auto Pipedownbody = Physicsbody::createbox ( Pipedown->getcontentsize ());p ipedownbody->setdynamic (False);p Ipedownbody->setcontacttestbitmask (1); Pipedown->setanchorpoint (Vec2::anchor_middle);p ipedown->setphysicsbody (pipedownbody);
Collision detection increases collision interception in the event dispatcher in the INIT layer today
Add Collision Monitor Auto Contactlistener = Eventlistenerphysicscontact::create (); contactlistener->oncontactbegin = CC_ Callback_1 (Gamescene::oncontactbegin, this); _eventdispatcher->addeventlistenerwithscenegraphpriority ( Contactlistener, this);
Collision monitoring bool Gamescene::oncontactbegin (const physicscontact& Contact) {if (GameStatus = = game_over) // When the game is over, no longer monitor the collision return False;gameover (); return true;}
3.6, Touch detection
Touch monitor bool Gamescene::ontouchbegan (Touch *touch, Event *event)
3.7. Control the bird from Prep mode to game start mode, touch the screen will give the bird an upward speed. Written in a touch test.
Birdsprite->getphysicsbody ()->setvelocity (Vec2 (0, 250)); Give an upward initial velocity
The angle of rotation of the bird is related to the longitudinal velocity and is written in update ().
The bird spins auto curvelocity = Birdsprite->getphysicsbody ()->getvelocity (); Birdsprite->setrotation (- CURVELOCITY.Y*0.1-20); Calculates the rotation angle according to the velocity in the vertical direction. Negative counter-clockwise
3.8, start the game after the beginning of various timers
The game starts with void Gamescene::gamestart () {gamestatus = Game_start;score = 0;//Resets the score scorelabel->setstring (String:: Createwithformat ("%d", score)->getcstring ()) This->getchildbyname ("logo")->setvisible (false); Logo disappears scorelabel->setvisible (true); Score starts this->scheduleupdate ();//start default update This->schedule (Schedule_selector (Gamescene::scrollland), 0.01f); Start the pipe and floor rolling birdsprite->stopaction (swingaction); The game starts to stop up and down floating birdsprite->getphysicsbody ()->setgravityenable (true); Begin to be subjected to gravity}
3.9, scoring and data store infer and update scores in the default update () function, storing historical fractions by default XML
When the game starts, it infers the score, which in fact can be written elsewhere. For example, the update function of the tube scrolling inside or the touch monitor inside if (GameStatus = = Game_start) {for (auto &pipe:pipes) {if (pipe->getname () = = "Newpipe")//New to A pipe is inferred {if (Pipe->getpositionx () < Birdsprite->getpositionx ()) {score++;scorelabel->setstring (String:: Createwithformat ("%d", score)->getcstring ()); Simpleaudioengine::getinstance ()->playeffect ("Point.mp3");p ipe->setname ("passed"); Mark the pipe that has passed out}}}}
4.0. Game Over
Game over void Gamescene::gameover () {gamestatus = game_over;//get historical Data Bestscore = Userdefault::getinstance () Getintegerforkey ("best"); if (Score > Bestscore) {bestscore = score; Update Best Score Userdefault::getinstance ()->setintegerforkey ("good", Bestscore);} Simpleaudioengine::getinstance ()->playeffect ("Hit.mp3");//stop rolling this->unschedule the floor and pipe after the game is over (Schedule_ Selector (Gamescene::scrollland));}
Compare the current score and the historical score at the end. For updates. 4.1, audio sound files have been added to the cache, where appropriate, plus a global audio controller to play sound effects can be
Simpleaudioengine::getinstance ()->playeffect ("Hit.mp3");
4.2, the scoreboard game ends and slides into the scoreboard and displays the replay button.
Add scoreboard and Replay menu void Gamescene::gamepanelappear () {Size size = Director::getinstance ()->getvisiblesize (); VEC2 origin = Director::getinstance ()->getvisibleorigin ();//Use node to bind Gameoverlogo and scoreboard together node *gameoverpanelnode = Node::create (); Auto Gameoverlabel = Sprite::createwithspriteframename ("gameover.png");gameoverpanelnode-> AddChild (gameoverlabel); auto Panel = sprite::createwithspriteframename ("board. PNG ");//Note this is the uppercase PNG. What suffix does the original picture use here, distinguish between uppercase and lowercase gameoverlabel->setpositiony (panel->getcontentsize (). height); Set the coordinates gameoverpanelnode->addchild (panel);//Scoreboard add two points auto Curscorettf = Labelttf::create (String:: Createwithformat ("%d", score)->getcstring (), "Arial", "Curscorettf->setposition" (panel->getcontentsize (). width-40, Panel->getcontentsize (). height-45) Curscorettf->setcolor (color3b (255, 0, 0));p anel-> AddChild (CURSCORETTF); auto Bestscorettf = Labelttf::create (String::createwithformat ("%d", Bestscore) Getcstring (), "Arial", Bestscorettf->setposition (panel->getcontentsize (). width-40, Panel->getcontentsize (). height-90); Bestscorettf->setcolor (color3b (0, 255, 0) );p Anel->addchild (BESTSCORETTF); This->addchild (Gameoverpanelnode); Gameoverpanelnode->setposition ( Origin.x + SIZE.WIDTH/2, ORIGIN.Y + size.height);//Slide into animation gameoverpanelnode->runaction (Moveto::create (0.5f, VEC2 ( Origin.x + SIZE.WIDTH/2, ORIGIN.Y + SIZE.HEIGHT/2)); Simpleaudioengine::getinstance ()->playeffect ("Swooshing.mp3");//Add menu Menuitemimage *restartitem = MenuItemImage :: Create ("Start_btn.png", "Start_btn_pressed.png", This,menu_selector (Gamescene::gameretart)); auto menu = Ccmenu:: Createwithitem (Restartitem); Menu->setposition (origin.x + SIZE.WIDTH/2); This->addchild (menu);} The game starts again void Gamescene::gameretart (Ref *sender) {////again back to the splash screen auto Gamescene = Gamescene::createscene ();D irector:: GetInstance ()->replacescene (Gamescene); It's too lazy to add special effects, direct transitions}
:
watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvdtaxmjizndexnq==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">
watermark/2/text/ahr0cdovl2jsb2cuy3nkbi5uzxqvdtaxmjizndexnq==/font/5a6l5l2t/fontsize/400/fill/i0jbqkfcma==/ Dissolve/70/gravity/southeast ">
SOURCE csdn Download: Myflappybirdgithub Download: Myflappybird
There are a lot of good things to do, such as no increase in image numbers, social sharing and so on.
Flappybird of COCOS2DX Instance Development (Starter Edition)