Cocos2dx instance development-flappybird (Entry edition) and cocos2dxflappybird

Source: Internet
Author: User

Cocos2dx instance development-flappybird (Entry edition) and cocos2dxflappybird

There is a series of blogs in the cocos2dx community that completely copies all the features of the original flappybird. However, the code is complicated and cannot be understood by beginners. Here I have written a simple version. The demo is as follows:



Create a project VS2013 + cocos2dx 3.2 Create A win32 project. As it is just learning, it is not compiled as an executable file for Android, ios, or WP platform. The final project structure is as follows:
Very simple. There are only three categories: pre-loading, game main scenario, and application proxy. beginners like to write a lot of things in as few categories as possible.
The game design structure is as follows. The game includes preload scenarios and main scenarios. The home scene includes backgrounds, birds, pipelines, and various UI interfaces.

Development procedure 1. Material collectionExtract some images and audio from the apk file, and use TexturePatcher to construct a large image to export the plist file.

2. pre-loading scenarioCreate a new LoadingScene file, add a startup image to it, and add all the image clips, bird frame animations, and audio files to the cache through asynchronous texture loading and callback, after loading, jump to the main scenario of the game.
// Add the loading callback function and asynchronously load the texture Director: getInstance ()-> getTextureCache ()-> addImageAsync ("game.png", CC_CALLBACK_1 (LoadingScene: loadingCallBack, this ));
Void LoadingScene: loadingCallBack (Texture2D * texture) {// pre-load the frame cache texture SpriteFrameCache: getInstance ()-> addSpriteFramesWithFile ("game. plist ", texture); // pre-loaded Frame Animation auto birdAnimation = Animation: create (); birdAnimation-> setDelayPerUnit (0.2f); birdAnimation-> addSpriteFrame (SpriteFrameCache :: getInstance ()-> submit ("bird1.png"); birdAnimation-> addSpriteFrame (SpriteFrameCache: getInstance ()-> getSpriteFrameByName ("bird2.png ")); birdAnimation-> addSpriteFrame (SpriteFrameCache: getInstance ()-> submit ("bird3.png"); AnimationCache: getInstance ()-> addAnimation (birdAnimation, "birdAnimation "); // Add the bird animation to the animation cache // preload the sound effects SimpleAudioEngine: getInstance ()-> preloadEffect ("die.mp3"); SimpleAudioEngine: getInstance () -> preloadEffect ("hitrate"); SimpleAudioEngine: getInstance ()-> preloadEffect (" pointeffects "); SimpleAudioEngine: getInstance ()-> preloadEffect (" swooshing= "); simpleAudioEngine: getInstance ()-> preloadEffect ("wing.mp3"); // jump to the game scenario after loading. auto gameScene = GameScene: createScene (); TransitionScene * transition = TransitionFade :: create (0.5f, gameScene); ctor: getInstance ()-> replaceScene (transition );}

3. Main game scenarios3.1. Use the image genie for the background and logo.
// Add the 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 should be hidden after the game starts. 3.2, 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); // auto up = MoveBy: create (0.4f, Point (0, 8 )); auto upBack = up-> reverse (); if (gameStatus = GAME_READY) {swingAction = RepeatForever: create (Sequence: create (up, upBack, NULL )); birdSprite-> runAction (swingAction); // up/down shaking animation}
In addition to the wings, the preparation interface also has up and down movements.
3.3, the Left shift of the floor is achieved by repeating the Left shift of two misplaced floor images. You must use a custom scheduler to adjust the movement speed.
// Add two land1 = Sprite: createWithSpriteFrameName ("land.png"); land1-> setAnchorPoint (Point: ZERO); land1-> setPosition (Point: ZERO ); this-> addChild (land1, 10); // place it at the top level of land2 = Sprite: createWithSpriteFrameName ("land.png"); land2-> setAnchorPoint (Point: ZERO ); land2-> setPosition (Point: ZERO); this-> addChild (land2, 10 );
Size visibleSize = Director: getInstance ()-> getVisibleSize (); // two images are cyclically moved to 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 water pipe group consists of two or more water pipes, which are packed with nodes. A vector container is used to add two groups of pipes. Each time only two groups of pipes appear on the screen, when a group disappears within the screen range, you need to reset its horizontal coordinates and calculate the spacing or height in advance.
// Only two tubes are displayed on the same screen, which are placed in the container and 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: Pipeline ("pipe_down.png "); node * singlePipe = Node: create (); // bind the upper pipe to the rigid body auto pipeUpBody = PhysicsBody: createBox (pipeUp-> getContentSize ()); pipeUpBody-> setDynamic (false); pipeUpBody-> setContactTestBitmask (1); pipeUp-> setAnchorPoint (Vec2: Pipeline); pipeUp-> setPhysicsBody (pipeUpBody ); // set the rigid body for the two tubes separately, so that the birds can leave a gap in the middle to bind the rigid body to the lower tube. auto pipeDownBody = PhysicsBody: createBox (pipeDown-> getContentSize ()); pipeDownBody-> setDynamic (false); pipeDownBody-> setContactTestBitmask (1); pipeDown-> setAnchorPoint (Vec2: Pipeline); pipeDown-> setPhysicsBody (pipeDownBody ); pipeUp-> setPosition (0, PIPE_HEIGHT + PIPE_SPACE); singlePipe-> addChild (pipeUp); singlePipe-> addChild (pipeDown); // pipeDown is added to (0, 0) by default, merge up and down, at this time, the center of the pipes below singlePipe is the anchor singlePipe-> setPosition (I * PIPE_INTERVAL + WAIT_DISTANCE, getRandomHeight (); // set the initial height singlePipe-> setName ("newPipe "); this-> addChild (singlePipe); // adds both tubes to the layer pipes. pushBack (singlePipe); // Add two tubes to the container successively}
// Pipe scrolling for (auto & singlePipe: pipes) {singlePipe-> setPositionX (singlePipe-> getPositionX ()-1.0f); if (singlePipe-> getPositionX () <-PIPE_WIDTH/2) {singlePipe-> setPositionX (visibleSize. width + PIPE_WIDTH/2); singlePipe-> setPositionY (getRandomHeight (); singlePipe-> setName ("newPipe"); // reset a pipe each time, marked as new }}
3.5. the built-in physical engine was introduced after cocos2dx 3.0 was added to the physical world. Its usage is similar to that of box2D. Physical World Initialization
GameScene-> getPhysicsWorld ()-> setGravity (Vec2 (0,-900); // you can set the gravity field. The acceleration of gravity can be reduced based on the touch.
GameLayer-> setPhysicWorld (gameScene-> getPhysicsWorld (); // bind the physical world
Bird binds a Rigid Body
// Bind the birdBody to the rigid body auto birdBody = PhysicsBody: createCircle (BIRD_RADIUS); // use the birdBody as a circle, so you are too lazy to get the exact outline of birdBody-> setDynamic (true ); // set birdBody to be acted by a physical location-> setContactTestBitmask (1 ); // you must set this parameter to 1 to detect the collision between different objects, birdBody-> setGravityEnable (false). // you can specify whether the collision is affected by gravity, prepare birdSprite-> setPhysicsBody (birdBody) on the screen without gravity impact; // set a rigid body for the bird
Floor binding Rigid Body
// Set the floor rigid body Node * groundNode = Node: create (); auto groundBody = PhysicsBody: createBox (Size (visibleSize. width, land1-> getContentSize (). height); groundBody-> setDynamic (false); groundBody-> setContactTestBitmask (1); groundNode-> setAnchorPoint (Vec2: ANCHOR_MIDDLE ); // The Rigid Body in the physical engine can only be set as the center groundNode-> setPhysicsBody (groundBody); groundNode-> setPosition (visibleOrigin. x + visibleSize. width/2, land1-> getContentSize (). height/2); this-> addChild (groundNode );
Set the rigid body for the MPs queue, and set the upper and lower half root respectively to leave gaps in the middle.
// Bind a rigid body auto pipeUpBody = PhysicsBody: createBox (pipeUp-> getContentSize (); pipeUpBody-> setDynamic (false); pipeUpBody-> setContactTestBitmask (1 ); pipeUp-> setAnchorPoint (Vec2: ANCHOR_MIDDLE); pipeUp-> setPhysicsBody (pipeUpBody); // set the rigid body for the two tubes separately, you can leave a gap in the middle so that the bird binds the rigid body auto pipeDownBody = PhysicsBody: createBox (pipeDown-> getContentSize (); pipeDownBody-> setDynamic (false ); pipeDownBody-> setContactTestBitmask (1); pipeDown-> setAnchorPoint (Vec2: ANCHOR_MIDDLE); pipeDown-> setPhysicsBody (pipeDownBody );
Collision Detection now adds collision listening to the event distributor in the init layer.
// Add collision monitoring auto contactListener = listener: create (); contactListener-> onContactBegin = CC_CALLBACK_1 (GameScene: onContactBegin, this); _ eventDispatcher-> listener (contactListener, this );
// Collision monitoring bool GameScene: onContactBegin (const PhysicsContact & contact) {if (gameStatus = GAME_OVER) // when the game ends, no monitoring collision return false; gameOver (); return true ;}
3.6, touch Detection
// Touch listening bool GameScene: onTouchBegan (touch * Touch, Event * event)
3.7, after the control bird changes from the preparation mode to the start mode of the game, the touch screen will give the bird an upward speed, written in the touch Detection
BirdSprite-> getPhysicsBody ()-> setVelocity (Vec2 (0,250); // give an upward initial speed
The rotation angle of a bird is related to the vertical speed, which is written in update ().
// Auto curVelocity = birdSprite-> getPhysicsBody ()-> getVelocity (); birdSprite-> setRotation (-curVelocity. y * 0.1-20); // The rotation angle is calculated based on the vertical speed, and the clockwise value is negative.
3.8. Start various timers after the game starts.
// Game start void GameScene: gameStart () {gameStatus = GAME_START; score = 0; // reset score scoreLabel-> setString (String: createWithFormat ("% d ", score)-> getCString (); this-> getChildByName ("logo")-> setVisible (false); // scoreLabel for logo disappearance-> setVisible (true ); // start this-> scheduleUpdate (); // start the default update this-> schedule (schedule_selector (GameScene: scrollLand), 0.01f ); // start the tube and floor rolling birdSprite-> stopAction (swingAction); // stop floating birdSprite up and down after the game starts-> getPhysicsBody ()-> setGravityEnable (true ); // start to be affected by gravity}
3.9. scoring and data are stored in the default update () function to judge and update scores, and historical scores are stored in the default xml.
// When the game starts, the score can be determined. This can also be written elsewhere, for example, in the update function of tube rolling or in the touch monitoring if (gameStatus = GAME_START) {for (auto & pipe: pipes) {if (pipe-> getName () = "newPipe ") // judge {if (pipe-> getPositionX () <birdSprite-> getPositionX () {score ++; scoreLabel-> setString (String :: createWithFormat ("% d", score)-> getCString (); SimpleAudioEngine: getInstance ()-> playEffect ("pointcompare "); pipe-> setName ("passed"); // mark the pipe that has passed }}}}
4.0. The game is over
// Void GameScene: gameOver () {gameStatus = GAME_OVER; // obtain the historical data bestScore = UserDefault: getInstance ()-> getIntegerForKey ("BEST "); if (score> bestScore) {bestScore = score; // update the BEST score UserDefault: getInstance ()-> setIntegerForKey ("BEST", bestScore);} SimpleAudioEngine: getInstance () -> playEffect ("hitrate"); // after the game ends, stop rolling floors and pipelines. this-> unschedule (schedule_selector (GameScene: scrollLand ));}
The current score and historical score are compared to be updated. 4.1. The audio effect file has been added to the cache. Add the global Audio Controller to play the sound effect at the right place.
SimpleAudioEngine::getInstance()->playEffect("hit.mp3");
4.2. After the scorecard game ends, it slides into the scoreboard and displays the replay button.
// Add the scoreboard and replay menu void GameScene: gamePanelAppear () {Size size = Director: getInstance ()-> getVisibleSize (); Vec2 origin = Director :: getInstance ()-> getVisibleOrigin (); // use node to tie the gameoverlogo and scoreboard together. Node * gameOverPanelNode = Node: create (); auto gameOverLabel = Sprite :: createWithSpriteFrameName ("gameover.png"); gameOverPanelNode-> addChild (gameOverLabel); auto panel = Sprite: createWithSpriteFrameName ("board. PNG "); // note that this is an upper-case PNG image. The original image uses a suffix, Which is case sensitive. gameOverLabel-> setPositionY (panel-> getContentSize (). height); // set the coordinates gameOverPanelNode-> addChild (panel); // Add two scores on the score board: auto curScoreTTF = LabelTTF: create (String :: createWithFormat ("% d", score)-> getCString (), "Arial", 20); curScoreTTF-> setPosition (panel-> getContentSize (). width-40, panel-> getContentSize (). height-45); curScoreTTF-> setColor (Color3B (255, 0, 0); panel-> addChild (curScoreTTF); auto bestScoreTTF = LabelTTF: create (String :: createWithFormat ("% d", bestScore)-> getCString (), "Arial", 20); bestScoreTTF-> setPosition (panel-> getContentSize (). width-40, panel-> getContentSize (). height-90); bestScoreTTF-> setColor (Color3B (0,255, 0); panel-> addChild (bestScoreTTF); this-> addChild (gameOverPanelNode ); gameOverPanelNode-> setPosition (origin. x + size. width/2, origin. y + size. height); // slide into the animation gameOverPanelNode-> runAction (MoveTo: create (0.5f, Vec2 (origin. x + size. width/2, origin. y + size. height/2); SimpleAudioEngine: getInstance ()-> playEffect ("swooshing.pdf"); // Add the 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,150); this-> addChild (menu);} // The game restarts void GameScene: gameRetart (Ref * sender) {// return to the initial screen. auto gameScene = GameScene: createScene (); ctor: getInstance ()-> replaceScene (gameScene); // you are too lazy to add special effects here, direct transfer}

:
 

Source code: MyFlappyBird
There are still many improvements, such as the absence of image numbers and social sharing.



I want to learn how to develop a game using cocos2dx. What do I need to learn first?

X is developed using c ++, and of course c ++ language.

Android game development process with cocos2dx

In the development environment vs2010, go to the cocos2dx compressed package on the official website, decompress the package, and install the template to start development.

It is recommended to read books. There are a lot of books such as "cocos2dx authoritative guide ".

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.