Cocos2d-x game development parkour (7) add gold coins and rocks

Source: Internet
Author: User

Intermittently, this cool code has finally been written. I will write two more articles to sum up. This game is even completed, and I hope this series will be helpful to new players. If you can look at these articles with a deep understanding, I believe you will surely gain something. Of course, the source code will certainly be opened at the end, please rest assured.


Recently, I have seen some websites repost my articles. I am very happy and welcome them. But can you specify the source? Although it is not commercially available, it is also the result of my work. Can I respect it. Some websites should be web crawlers who are dedicated to crawling my blog. Even the pictures have been scanned, but please drag my links together, OK?

My blog: http://blog.csdn.net/dawn_moon


The general idea of my Parkour is similar to that of the Tyan JS version. As I am a physical world implemented by Box2D, this section is slightly different.

This parkour map is an infinite map in the true sense. See my floor definition:

// Floor b2EdgeShape shape; shape. Set (b2Vec2 (0, GROUND_HEIGHT/RATIO), b2Vec2 (INT_MAX, GROUND_HEIGHT/RATIO ));

The floor length is INT_MAX, which varies according to the platform.

An infinite map is made up of two maps:

During initialization, the two maps are spliced horizontally. The map is wider than the screen. The map that is not displayed is outside the screen. The camera (which can be seen as the visible area of the screen) is on the leftmost side, then the character runs, and the camera follows and moves. The characters here are actually running, and the X-axis coordinates keep increasing. When the screen is moved to the second map, the first map will be invisible. when the camera is still moving, you need to connect to another map after the second map, otherwise, when the camera X coordinates exceed the second map, the camera becomes dark and cannot see the map. A simple method is to put the first invisible map behind the second one. To put it simply, the old map is placed behind the new map, and the cycle is alternating.


A map is an infinite map, so gold coins and rocks are just an object on the map. You just need to determine the position of each object. Looking at the JS version of the Code, the gold coins are basically the same as the rocks, but the textures are different. The gold coins have an extra rotation animation. I began to build these two classes for laziness. One gold coin and one rock were not well designed. In fact, if you are careful, you will find that most of the Code for these two classes are consistent, then these two classes belong to the same class. At this time, these two classes can be abstracted and classified into one category.

Here, by the way, I understand C ++ and Java classes. C ++ and Java are both object-oriented languages and abstract in the real world. However, their abstract concepts are different. Classes in C ++ are the concept of classification, which is a kind of attribute-based classification for various instances in reality. They are abstracted from the bottom up. Since it is a classification method, a thing can be classified into different classes according to different attributes. Example:

A group of animals, cats, mice, pigs, dogs, tigers, and leopards. You may implement it according to the actual category, which means that you can design it like this: a cat class, a mouse class, a pig class, a dog class, and a tiger class, A leopard class. Okay, that's what I did when I made the gold coins and rocks. However, this will be very stupid. You need to copy and paste a lot of code, because these animals have many identical attributes, such as four legs with sharp teeth, they are all mammals. If you have another rabbit, you need to create another rabbit class, copy and paste N multiple codes, and get bored. Well, maybe they can be classified by crawlers and abstracted. Then, abstract the parrots, swallows, and Huang Yu among others into one category. However, there are a lot of things in this world that are not so simple. For example, Bat may have some characteristics of crawling animals, but at the same time it will fly and have some characteristics of flying birds, you can inherit these two base classes for implementation. It is the multi-inheritance in C ++. All these classes can finally be abstracted into a base class, animal, which is what I said from the bottom up.

Java classes abstract reality, which is a top-down subdivision. Daosheng 1: second in life, second in life, and third in life. They all belong to animal, then subdivided into fetal animals, egresses, and finally sub-classes such as cats, dogs, pigs, rats, and rabbits. As you know, Java only has a single inheritance. But in reality, multiple inheritance is everywhere. For example, if you have both your father's genetic and your mother's genetic, you have inherited half of your parents. (It seems to be a little far away. I won't talk about it)

Well, I used to copy the JS version and created two classes to implement them separately. At the end of the collision detection, I was so stupid that I had to use a lot of code to determine whether it was a gold coin or a rock. Then I simply made an abstraction, called BaseObject, and added several functions to help destroy gold coins and rocks.

class BaseObject : public cocos2d::CCNode{public:        virtual B2Sprite* getObjSprite() = 0;        virtual void destroy() = 0;        virtual void setObjVisible(bool visible) = 0;};

Gold coins and rocks are sub-classes of this class. In fact, the logic is quite simple. They are all CCNode, and the texture inside is made of B2Sprite, which is a kinematics object b2_kinematicBody. B2_kinematicBody is a kinematics object. It is similar to a static object and is not affected by gravity. It is not flushed by a dynamic object (b2_dynamicBody.

Let's take a look at the implementation:

////  Coin.h//  Parkour////  Created by lerry on 3/26/14.////#ifndef __Parkour__Coin__#define __Parkour__Coin__#include "cocos2d.h"#include "B2Sprite.h"#include "Box2D/Box2D.h"#include "resources.h"USING_NS_CC;class Coin : public BaseObject{    b2World* mWorld;        B2Sprite* mSprite;        CCSpriteBatchNode* mBatchNode;        CCPoint mPosition;        b2Body* mBody;    public:    Coin();        inline static const CCSize& getCoinSize()    {        B2Sprite* coin = B2Sprite::createWithSpriteFrameName(coin0);        return coin->getContentSize();    };        static Coin* create(CCSpriteBatchNode* batchNode, b2World* world, const CCPoint& pos);        bool init(CCSpriteBatchNode* batchNode, b2World* world, const CCPoint& pos);        void initAnimation();        void initPhysicalCoin();        inline virtual B2Sprite* getObjSprite()    {        return mSprite;    };        inline virtual void setObjVisible(bool visible)    {        mSprite->setVisible(visible);    };        CC_SYNTHESIZE(int, mapIndex, Map);        virtual void destroy();};#endif /* defined(__Parkour__Coin__) */

//// Coin. cpp // Parkour /// Created by lerry on 3/26/14. //// # include "Coin. h "Coin: Coin (): mWorld (NULL), mSprite (NULL), mBatchNode (NULL), mPosition (ccp (0, 0), mapIndex (0 ), mBody (NULL) {} Coin * Coin: create (cocos2d: CCSpriteBatchNode * batchNode, b2World * world, const CCPoint & pos) {Coin * coin = new Coin (); if (coin & coin-> init (batchNode, world, pos) {coin-> autorelease (); return coin;} else {CC_SAFE_D ELETE (coin); return NULL ;}} bool Coin: init (cocos2d: CCSpriteBatchNode * batchNode, b2World * world, const CCPoint & pos) {if (! CCNode: init () {return false;} mWorld = world; mBatchNode = batchNode; mPosition = pos; mSprite = B2Sprite: createWithSpriteFrameName (coin0 ); mSprite-> setTag (COINTAG); initPhysicalCoin (); initAnimation (); CCAnimation * animation = CCAnimationCache: sharedAnimationCache ()-> animationByName ("coinAction "); mSprite-> runAction (CCAnimate: create (animation); mBatchNode-> addChild (mSprite); return true;} v Oid Coin: initAnimation () {CCArray * animateFrames = CCArray: create (); char str [50] = {0}; for (int I = 0; I! = 8; ++ I) {sprintf (str, "coin1_d.png", I); animateFrames-> addObject (CCSpriteFrameCache: extract ()-> spriteFrameByName (str ));} CCAnimation * animationRunning = CCAnimation: animation (animateFrames, 0.1); // set the infinite loop animationRunning-> setLoops (-1); // coin animation name: sharedAnimationCache () -> addAnimation (animationRunning, "coinAction");} void Coin: initPhysicalCoin () {b2BodyDef bodyDef; bodyDef. type = b2_kinematicBody; bodyDef. position = b2Vec2 (mPosition. x/RATIO, mPosition. y/RATIO); mBody = mWorld-> CreateBody (& bodyDef); mSprite-> setB2Body (mBody); mSprite-> setPTMRatio (RATIO); mBody-> SetUserData (this ); b2CircleShape shape; shape. m_p.Set (0, 0); shape. m_radius = 0.95 * mSprite-> getContentSize (). width/2/RATIO; b2FixtureDef fixDef; fixDef. shape = & shape; fixDef. isSensor = true; mBody-> CreateFixture (& fixDef);} void Coin: destroy () {if (mBody) {mWorld-> DestroyBody (mBody );} mSprite-> removeFromParent ();}

The rock is similar to this, so it will not be pasted. I used CCSpriteBatchNode to add gold coins and rocks, which can reduce rendering batches. However, when I enable the debug mode of box2d, the rendering batches become more than 100. If I turn it off, it will only be around 8. It took me a long time to find the debugdraw problem.

Now, you can add gold coins and rocks. If you add them directly to PlayScene, you still need a piece of scattered code to reclaim the coins that people encounter and remove the rocks on the map. Does not comply with object-oriented specifications. So I made a management class ObjectManager, which is a singleton class. I think this use case is better. Management classes always exist, and only one can exist. Otherwise, many management classes will be messy.

////  ObjectManager.h//  Parkour////  Created by lerry on 3/26/14.////#ifndef __Parkour__ObjectManager__#define __Parkour__ObjectManager__#include "cocos2d.h"#include "Box2D/Box2D.h"#include "Coin.h"#include "Rock.h"USING_NS_CC;class ObjectManager : public CCObject{    CCArray* mCoins;        CCArray* mRocks;        CCSpriteBatchNode* mBatchNode;        b2World* mWorld;        int mCoinCount;    private:    ObjectManager();    public:    ~ObjectManager();        static ObjectManager* sharedObjectManager();        void initManager(CCSpriteBatchNode* spriteSheet, b2World* world);        void setObjectToMap(int mapIndex, float mapWidth);        void setObject(CCSize size);        void recycleObjectOfMap(int mapIndex);        void pureObjects();};#endif /* defined(__Parkour__ObjectManager__) */

//// ObjectManager. cpp // Parkour /// Created by lerry on 3/26/14. //// # include "ObjectManager. h "# include" Runner. h "static ObjectManager * mOMInstance = NULL; ObjectManager: ObjectManager (): mBatchNode (NULL), mWorld (NULL), mCoinCount (7) {CCAssert (mOMInstance = NULL, "Attempted to allocate a second instance of a singleton. "); // For CCArray to be persistent, you need to retain mCoins = CCArray: create (); mCoins-> retain (); mRocks = C CArray: create (); mRocks-> retain ();} ObjectManager ::~ ObjectManager () {mCoins-> release (); mRocks-> release ();} ObjectManager * ObjectManager: Export dobjectmanager () {if (! MOMInstance) {mOMInstance = new ObjectManager ();} return mOMInstance;} void ObjectManager: initManager (CCSpriteBatchNode * spriteSheet, b2World * world) {mBatchNode = spriteSheet; mWorld = world; pureObjects ();}/** test code */void ObjectManager: setObject (CCSize size) {srand (time (NULL); for (int I = 0; I! = MCoinCount; ++ I) {Coin: create (mBatchNode, mWorld, ccp (CCRANDOM_0_1 () * size. width, CCRANDOM_0_1 () * size. height) ;}}/** add rock and gold coins */void ObjectManager: setObjectToMap (int mapIndex, float mapWidth) {float coinPositionY = Coin: getCoinSize (). height + GROUND_HEIGHT; float jumpRockPositionY = Runner: getCrouchSize (). height + GROUND_HEIGHT; // this random factor, which has an implicit conversion. Values: 1, 2, 3 srand (time (NULL); int randomCoinFac Tor = (CCRANDOM_0_1 () * 2 + 1); // value: 0, 2, 3 int randomRockFactor = CCRANDOM_0_1 () * (CCRANDOM_0_1 () * 2 + 1); float jumpRockFactor = 0; float coinOriginX = mapWidth/4 * randomCoinFactor + mapWidth * mapIndex; float rockOriginX INX = mapWidth/4 * randomRockFactor + mapWidth * mapIndex; float coinWidth = Coin: getCoinSize (). width; float rockWidth = Rock: getRockSize (). width; float rockHeight = R Ock: getRockSize (). height; float startX = coinOriginX-coinWidth/2*11; float coinIncrement = coinWidth * 1.5; // Add a rock Rock * rock = Rock: create (mBatchNode, mWorld, ccp (rockOriginX, GROUND_HEIGHT + rockHeight/2); rock-> setMap (mapIndex); mRocks-> addObject (rock); // Add coins, if the x coordinate of the gold coin and the rock are in a step, place the gold coin on the rock for (int I = 0; I! = MCoinCount; ++ I) {Coin * coin = NULL; if (startX + I * coinIncrement> rockOriginX INX-rockWidth/2) & (startX + I * coinIncrement <rockorigwidth + rockWidth/2) {coin = Coin: create (mBatchNode, mWorld, ccp (startX + I * coincrement, coinPositionY + rockHeight);} else {coin = Coin: create (mBatchNode, mWorld, ccp (startX + I * coincrement, coinPositionY ));} coin-> setMap (mapIndex); mCoins-> ad DObject (coin) ;}for (int I = 0; I <4; I ++) {if (I! = RandomCoinFactor) & (I! = RandomRockFactor) {jumpRockFactor = I ;}// add jump rockfloat JumpRockOriginX = mapWidth/4 * jumpRockFactor + mapWidth * mapIndex; Rock * jumpRock = Rock: create (mBatchNode, mWorld, ccp (JumpRockOriginX INX, jumpRockPositionY + rockHeight/2 + 5); // 10 corrected the collision region jumpRock-> setMap (mapIndex); mRocks-> addObject (jumpRock );} void ObjectManager: recycleObjectOfMap (int mapIndex) {CCArray * tempCoins = CCArray: create (); CCArray * tempRocks = CCArray: create (); CCObject * itor; // you cannot add or delete a CCArray traversal. Otherwise, an error occurs. // This is done in two steps, the object to be deleted is saved to a temporary CCArray. // The second step traverses the temporary CCArray, deletes the object from the source number group, and finally clears the temporary array CCLog ("count % d ", mCoins-> count (); CCARRAY_FOREACH (mCoins, itor) {Coin * coin = dynamic_cast
 
  
(Itor); if (coin! = NULL) & (coin-> getMap () = mapIndex) {tempCoins-> addObject (coin); coin-> destroy () ;}} CCARRAY_FOREACH (tempCoins, itor) {mCoins-> fastRemoveObject (itor);} CCARRAY_FOREACH (mRocks, itor) {Rock * rock = dynamic_cast
  
   
(Itor); if (rock! = NULL) & (rock-> getMap () = mapIndex) {tempRocks-> addObject (rock); rock-> destroy () ;}} CCARRAY_FOREACH (tempRocks, itor) {mRocks-> fastRemoveObject (itor);} tempRocks-> removeAllObjects (); tempCoins-> removeAllObjects ();}/** clears the array and calls it during initialization, make sure that the group is empty when the game starts */void ObjectManager: pureObjects () {mCoins-> removeAllObjects (); mRocks-> removeAllObjects ();}
  
 

Okay, these classes are designed, and the Assembly is finished.

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.