Cocos2d-x path ~ Create the first text game (2)

Source: Internet
Author: User

The path to cocos2d-x ~ Make the first text game (1), use the cocos2d-x to display the main interface, each level provides the initial phrase TileView, and the target phrase TargetView. The basic concepts and usage of cocos2d-x are introduced. This blog will basically implement the game logic and complete the main part of the game. Follow these steps:

TileView can be dragged

Capture TileView stop move events

Analyze whether TileView is placed in the correct position

Create a Layer distinguished from the original Layer, and place buttons, menus, and scores.

Add timing and score

Start now, continue to cocos2d-x!


1) drag and drop TileView

In the initWithLetter function of TileView, some work is not completed. To achieve the drag-and-drop effect, you have to let TileView process the gesture event and add the following code at the end of the function.

CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(tile,0,true);

Use the CCDirector class to add TileView as the gesture processing proxy. To process gesture events, TileView also inherits CCTargetedTouchDelegate, as shown in the code.

class TileView: public CCNode, public CCTargetedTouchDelegate

Then add the following variables to the class.

int xOffset;int yOffset;bool isControl;

And rewrite the functions inherited by CCTargetedTouchDelegate.

        bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

CcTouchBegan is the start of clicking, ccTouchMoved is the finger moving on the screen, ccTouchEnded is the finger leaving the screen, and ccTouchCancelled is interrupted by other circumstances

Before implementing these important functions, initialize isControl, and add isControl at the end of initWithLetter.

tile->isControl = false;

The role of this variable will be explained later. First, we will implement very important gesture events.

bool TileView::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){if(!containTouchLocation(pTouch)){return false;}isControl = true;this->setZOrder(999);CCPoint point = pTouch->getLocationInView();CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point);this->xOffset = touchPoint.x - this->getPositionX();this->yOffset = touchPoint.y - this->getPositionY();return true;}void TileView::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent){if(!isControl){return;}CCPoint point = pTouch->getLocationInView();CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point);float x = touchPoint.x - this->xOffset;float y = touchPoint.y - this->yOffset;this->setPosition(ccp(x,y));}void TileView::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){CCPoint point = pTouch->getLocationInView();CCPoint touchPoint = CCDirector::sharedDirector()->convertToGL(point);if(isControl){isControl = false;}}void TileView::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent){ccTouchEnded(pTouch, pEvent);}

In ccTouchBegan, containTouchLocation is used to determine whether the point of the finger falls within the TileView. It is processed only when the point is within the TileView; otherwise, it is returned directly. Set isControl to true, set the dragged TileView to the top, and use xOffset and yOffset to record the offset of the touch point coordinate and TileView coordinate. In each gesture event function, the convertToGL function is used to convert touch coordinates into coordinates in the game world (very important ).

CcTouchMoved is the coordinate of TileView which is constantly changed during the drag process. Remember to subtract the offset.

CcTouchEnded means that the finger leaves the screen and isControl is reset to false. It can be seen that isControl is used to control whether TileView is dragged during the entire gesture process. After ccTouchEnded or ccTouchCancelled, You need to restore it.

Run it. Can I drag it? Amazing.


2) Put down the TileView

After dragging the TileView, there will always be a moment to put it down. When TileView is put down, we need to determine whether it is placed on the correct target TargetView. These judgments need to be processed by MainScene, so we need to create a TileDropDelegate

<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHByZSBjbGFzcz0 = "brush: java;"> class TileDropDelegate {public: virtual void dropToPoint (TileView * tile, cocos2d: CCPoint point) = 0 ;};
Use MainScene to inherit this class

class MainScene : public cocos2d::CCLayer, public TileDropDelegate

Implementation of the dropToPoint Method

void MainScene::dropToPoint(TileView * tile,CCPoint point){TargetView * target = NULL;CCObject * tv;CCARRAY_FOREACH(pTargets,tv){TargetView* pTarget = (TargetView*) tv;if(pTarget->containPoint(point)){target = pTarget;break;}}}

Traverse the pTargets that stores the TargetView and check whether the vertex point is in the TargetView frame. If the TileView is located on the TargetView, you can judge the result and add it at the end of the dropToPoint function.

If (target! = NULL) {if (target-> getLetter () = tile-> getLetter () {// 1 word match} else {/2 words do not match }}
1. Check whether the dragged TileView matches the TargetView letter (invisible ).

2. The two letters do not match and need to be followed up.

After the callback function is implemented, you have to set it to TileView and add the following to the dealRandomAnagram tile-> randomize ();

tile->setTileDropDelegate(this);
Remember to add the setTileDropDelegate function in the TileView class.

Then, after letter matching, TileView must be overwritten on TargetView,

void MainScene::placeTile(TileView * tile,TargetView * target){tile->setMatch(true);target->setMatch(true);tile->removeTouchDelegate();CCActionInterval * actionTo = CCMoveTo::create(0.35,ccp(target->getPositionX(),target->getPositionY()));tile->runAction(actionTo);tile->setRotation(0);target->setVisible(false);}
In the Code, set tile and target to match, remove the drag-and-drop proxy of tile, use CCMoveTo to move the tile to the target location, and correct it.

Add the following statement after 1 word match

placeTile(tile,target);
Add after 2 words do not match

tile->randomize();CCActionInterval * actionTo = CCMoveTo::create(0.35,ccp(tile->getPositionX() + Common::random(-20,20),tile->getPositionY() + Common::random(-20,30)));tile->runAction(actionTo);

The main function is to remove tile from the target, indicating that the two do not match,


With the detection and matching function, you can determine whether the game is successfully completed. Add in MainScene

void MainScene::checkForSuccess(){CCObject * tv;CCARRAY_FOREACH(pTargets,tv){TargetView* pTarget = (TargetView*) tv;if(pTarget->getIsMatch() == false){return;}}CCLog("Game Over!");}

Traverse the target. If all matches, the game is successful. Add

checkForSuccess();
When running the Game, you will find that when all the letters match, you can print the Game Over message.

3) create a HUD Layer

This is a game design concept, that is, separating some game interface items from the HUD layer. The content of this layer is mainly used to assist the game content, such as Countdown, button, and end interface.

First, let's create a countdown. The class name is StopWatchView. the header file is as follows:

class StopWatchView : public CCLabelAtlas{public:StopWatchView(){}static StopWatchView * initView();void setSecond(int seconds);CREATE_FUNC(StopWatchView);};
The subject part is setSecond, which splits the seconds into mm: ss format.

void StopWatchView::setSecond(int second){char strTime[50];float minutes = second / 60;minutes =  (minutes > 0.0) ? floor(minutes + 0.5) : ceil(minutes - 0.5); int minu = (int)minutes;int sec = second % 60;sprintf(strTime," %02d:%02d",minu,sec);this->setString(strTime);}
Create the HUDView file below. The header file is as follows:

class HUDView : public CCLayer{public:    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone    virtual bool init();  // implement the "static node()" method manually    CREATE_FUNC(HUDView);private:StopWatchView * pWatch;CounterPointView * pPointView;CCMenuItemImage * pButton;CCMenu * pMenu;CCLabelTTF * pLabel;public:friend class MainScene;};
Among them, CounterPointView, CCmenuItemImage, CCMenu, and CCLabelTTF will be used later. Friend class MainScene is a member variable that allows MainScene to access the HUDView.

HUDView. cpp has only one function, such

bool HUDView::init(){if(! CCLayer::init()){return false;}pWatch = StopWatchView::initView();pWatch->setSecond(0);pWatch->setPosition(ccp(Common::getCameraWith()*0.5,Common::getCameraHeight() * 0.95));pWatch->setScale(0.7);this->addChild(pWatch);return true;}

Add StopWatchView.

Then you need to add the HUDView to MainScene, so add it in MainScene. h.

HUDView * pHUD;
After this member variable is added, add this-> addChild (bg) to the init function of MainScene.

pHUD = HUDView::create();this->addChild(pHUD);
Run the game and you can see


Use art Fonts

StopWatchView * StopWatchView::initView(){StopWatchView * p = (StopWatchView*)(CCLabelAtlas::create("11","fonts/tuffy_bold_italic-charmap.plist"));return p;}
After the art font is loaded,



4) Add a Level Timer

Add in MainScene. h

int mTimeLeft;
Then add the start timer in MainScene, as shown in figure

void MainScene::startStopWatch(){mTimeLeft = pLevel->mTimeToSovle;pHUD->pWatch->setSecond(mTimeLeft);schedule(schedule_selector(MainScene::downTime),1.0f);}
Use the schedule method to run the downTime every second. With the start time, you have to stop the time.

void MainScene::stopStopWatch(){unschedule(schedule_selector(MainScene::downTime));}
After unschedule, no timing will be performed. The downTime function is implemented below.

void MainScene::downTime(float dt){mTimeLeft --;pHUD->pWatch->setSecond(mTimeLeft);if(mTimeLeft == 0){stopStopWatch();}}
The content is relatively simple, that is, to reduce mTimeLeft and set it to TimeWatchView, and to stop timing when the return value is 0.

In the dealRandomAnagram function, add

startStopWatch();
The countdown starts at the beginning of the game.


Of course, when the game ends, don't forget to stop timing and add it at the end of checkForSuccess.

stopStopWatch();

5) add scoring

Scoring is an important setting in the game. With scoring, you can have a sense of accomplishment. Next we will start to add the scoring function for the game.

Added the Data class to store scores.

class Data : public CCObject{public:Data();virtual ~Data(){}void setPoint(int point);int getPoint();void addPoint(int point);void subtractPoint(int point);private:int mPoints;};
The function implementation is as follows:

Data::Data(){mPoints = 0;}void Data::setPoint(int point){if(point > 0){mPoints = point;}else{mPoints = 0;}}int Data::getPoint(){return mPoints;}void Data::addPoint(int point){mPoints += point;}void Data::subtractPoint(int point){mPoints -= point;}
After the player drag and drop the TileView and place it in the correct position, the score is added. If the score is incorrect, the score is deducted.

Add variable in MainScene. h

Data * pData;

In the init function of MainScene, apply for a variable

pData = new Data();

In dropToPoint, if the match is successful

pData->addPoint(pLevel->mPointPerTile);

If the matching fails, the score is halved.

pData->subtractPoint(pLevel->mPointPerTile / 2);

6) add score display in the HUD Layer

Scores should be displayed to players in real time, and labels must be used for display. Therefore, CounterPointView is added.

class CounterPointView: public CCLabelAtlas{public:static CounterPointView* initWithValue(int v);void countTo(int p, float duration);void updateValueBy(float dt);void setValue(int v);CREATE_FUNC(CounterPointView);private:CounterPointView(){};int value;float mDelta;int mEndValue;float mValueDelta;};

Value refers to the current score value, and mEndValue is the new score value. Next we will initialize it first.

CounterPointView* CounterPointView::initWithValue(int v){CounterPointView * p = (CounterPointView*)(CCLabelAtlas::create("11","fonts/tuffy_bold_italic-charmap.plist"));char strPoint[10];sprintf(strPoint,"%d",v);p->setString(strPoint);p->value = v;p->setScale(0.5);return p;}
The CCLabelAtlas class is a class that can be quickly rendered and is most suitable for changing numbers (the FPS number is the CCLabelAtlas class)

void CounterPointView::setValue(int v){this->value = v;char strPoint[10];sprintf(strPoint,"%d",v);setString(strPoint);}
Set score

void CounterPointView::updateValueBy(float dt){this->value += (int)mValueDelta;if((int)mValueDelta > 0){if(this->value > mEndValue){this->value = mEndValue;return;}}else{if(this->value < mEndValue){this->value = mEndValue;return;}}setValue(value);schedule(schedule_selector(CounterPointView::updateValueBy),mDelta);}

UpdateValueBy is an incremental (or decreasing) score. mValueDelta is added (or subtracted) each time until mEndValue. Otherwise, the schedule function is executed each time.

void CounterPointView::countTo(int to, float duration){this->mDelta = duration / (abs(to - value) + 1);if(mDelta < 0.05) mDelta = (float)0.05;mEndValue = to;unscheduleAllSelectors();if(to - this->value > 0){mValueDelta = 1;updateValueBy(1);}else{mValueDelta = -1;updateValueBy(-1);}}

The countTo function is an external interface to reach the to value during the duration period. First, calculate the mDelta interval, then unscheduleAllSelectors, and then start to increase (or decrease.

Add the CounterPointView variable to the HUDView, and then add it to the init function.

pPointView = CounterPointView::initWithValue(0);pPointView->setColor(ccc3(97,25,9));pPointView->setPosition(ccp(Common::getCameraWith()*0.05,Common::getCameraHeight() * 0.9));this->addChild(pPointView);

Then you can see the score


Return to MainScene. cpp and add the following content in pData-> addPoint (pLevel-> mPointPerTile ).

pHUD->pPointView->countTo(pData->getPoint(),1.5);

In pData-> subtractPoint (pLevel-> mPointPerTile/2), add

pHUD->pPointView->countTo(pData->getPoint(),0.75);

When the placement is correct, the score increases. If the placement is incorrect, the score decreases.


7) Conclusion

This is the end of the second article. because time is not enough, it is very slow to write and very lazy. It is almost a few words (cover your face ). From the perspective of words, this is not a good tutorial, but I think it is the idea of creating a game.

In the development process, we constantly add new things to the main framework and then enrich the entire game. The main game logic has been completed in this article. The rest is about optimization and some dazzling effects.

The use of cocos2d-x development will be very convenient, but also very code feeling, but C ++ is really not easy to control the language, pay attention to the use of pointers and memory. But it will also benefit a lot, at least in terms of code. Finally, put the full version of the AnagramPuzzle code.






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.