Cocos2d-x virtual Joystick Control genie up and down movement ---- game development "Zhao cloud to fight"
This is the first mini-game developed by myself. I have to leave a mailbox for source code and materials. Here, I can use a virtual joystick to control the movements of the genie and change the face orientation of the genie. I have read many people writing virtual joystick before, but I did not write the movements and face orientation of the control genie. So I want to write an article to explain its implementation ideas. Okay. Let's get started.
Directory:
1. Modify the background image and window size
2. Add a virtual joystick
3. Add the genie and use the joystick to control the movements of the genie.
Iv. Summary
1. Modify the background image and window size
Create a new project named HelloCpp. First, modify the window size in main. cpp to improve the effect.
EglView-> setFrameSize (480,320); For eglView-> setFrameSize (640,480 );
Then add the init () function of HelloWorldScene. cpp on the layer we want to display:
// Obtain the window size. CCSize visibleSize = CCDirector: shareddire()-> getVisibleSize (); CCPoint origin = CCDirector: sharedDirector ()-> getVisibleOrigin (); // modify the background image CCSprite * pSprite = CCSprite: create ("background_1.jpg"); pSprite-> setPosition (ccp (visibleSize. width/2 + origin. x, visibleSize. height/2 + origin. y); this-> addChild (pSprite, 0); // The value 0 indicates that it is placed at the bottom layer.
The effect is as follows:
2. Add a virtual joystick
First, put the joystick material in the Resources folder of the Project. Note that you 'd better put all the materials to be used here. The default material of the project is to be searched under this folder.
This is the background image of the joystick, which is hard to find. Without an artist, you can only find some information on the Internet,
This is the button image in the joystick and it can be moved.
Now, let's start adding the joystick to the background. My idea is to encapsulate the joystick into a class and then take care of the inherited CCLayer to respond to the touch event and look at the code, create an HRocker. h header file. Put. cpp and. h In the class folder of the project, and the file cannot be found. The Code is as follows:
# Ifndef _ HROCKER_H __# define _ HROCKER_H __# include "cocos2d. h "using namespace cocos2d; // used to identify the background typedef enum {tag_rocker, tag_rockerBG,} tagForHRocker; // used to identify typedef enum {rocker_stay, rocker_right, rocker_up, rocker_left, rocker_down,} tagDirecton; class HRocker: public CCLayer {public: HRocker (void );~ HRocker (void); // create a joystick (name of the joystick operation question image resource, name of the joystick background image resource, start coordinate) static HRocker * createHRocker (const char * rockerImageName, const char * rockerBGImageName, CCPoint position); // start the joystick (displaying the joystick and listening to the joystick touch screen events) void startRocker (bool _ isStopOther); // stop the joystick (hiding the joystick, cancel touch screen monitoring of the joystick) void stopRocker (); // determines the direction of the control lever, which is used to determine the movement of the int rocketDirection on the top, bottom, left, and right of the genie; // The walking direction of the current character, used to determine the direction of the Genie. The sprite face is either right or left bool rocketRun; CREATE_FUNC (HRocker); private: // custom initialization function void rockerInit (const char * rockerImageName, const char * rockerBGImageName, CCPoint position); // determine whether the joystick bool isCanMove can be operated; // obtain the float getRad (CCPoint pos1, CCPoint pos2) of the current joystick and the user's touch point ); // coordinate CCPoint rockerBGPosition of the joystick background; // float rockerBGR of the radius of the joystick background; // touch screen event virtual bool ccTouchBegan (CCTouch * pTouch, CCEvent * pEvent ); virtual void ccTouchMoved (CCTouch * pTouch, CCEvent * pEvent); virtual void ccTouchEnded (CCTouch * pTouch, CCEvent * pEvent);}; # endif
Create the corresponding implementation of HRocker. cpp. Put. cpp and. h In the class folder of the project, and the file cannot be found. The Code is as follows:
# Include "HRocker. h" const double PI = 3.1415; HRocker: HRocker (void) {rocketRun = false;} HRocker ::~ HRocker (void) {}// create a joystick (name of the joystick operation question image resource, name of the joystick background image resource, start coordinate) HRocker * HRocker: createHRocker (const char * rockerImageName, const char * rockerBGImageName, CCPoint position) {HRocker * layer = HRocker: create (); if (layer) {layer-> rockerInit (rockerImageName, rockerBGImageName, position ); return layer;} CC_SAFE_DELETE (layer); return NULL;} // custom initialization function void HRocker: rockerInit (const char * rockerImageName, const char * rockerBGImageName, CCPoint position) {CCSprite * spRockerBG = CCSprite: create (rockerBGImageName); spRockerBG-> setPosition (position); spRockerBG-> setVisible (false); addChild (spRockerBG, 0, tag_rockerBG ); CCSprite * spRocker = CCSprite: create (rockerImageName); spRocker-> setPosition (position); spRocker-> setVisible (false); addChild (spRocker, 1, tag_rocker ); rockerBGPosition = position; rockerBGR = spRockerBG-> getContentSize (). width * 0.5; // rocketDirection =-1; // indicates that the joystick direction remains unchanged} // start the joystick (display the joystick and listen to the joystick touch screen event) void HRocker :: startRocker (bool _ isStopOther) {CCSprite * rocker = (CCSprite *) this-> getChildByTag (tag_rocker); rocker-> setVisible (true); CCSprite * rockerBG = (CCSprite *) this-> getChildByTag (tag_rockerBG); rockerBG-> setVisible (true); CCDirector: sharedDirector ()-> getTouchDispatcher ()-> addTargetedDelegate (this,-1, _ isStopOther);} // stop the joystick (hide the joystick and cancel the touch screen listening of the joystick) void HRocker: stopRocker () {CCSprite * rocker = (CCSprite *) this-> getChildByTag (tag_rocker); rocker-> setVisible (false); CCSprite * rockerBG = (CCSprite *) this-> getChildByTag (tag_rockerBG); rockerBG-> setVisible (false ); CCDirector: sharedDirector ()-> getTouchDispatcher ()-> removeDelegate (this);} // obtain the float HRocker: getRad (CCPoint pos1, CCPoint pos2) {float px1 = pos1.x; float py1 = pos1.y; float px2 = pos2.x; float py2 = pos2.y; // obtain the float x = px2-px1 from two points; // obtain the float y distance from two points = py1-py2; // calculate the oblique edge length float xie = sqrt (pow (x, 2) + pow (y, 2 )); // obtain the cosine of this angle (in the store in the trigonometric function: angle cosine = oblique side/oblique side) float cosAngle = x/xie; // obtain the radian float rad = acos (cosAngle) of the expiration angle through the arccosine theorem; // Note: When the touch screen is located at Y coordinate
<摇杆的y坐标,我们要去反值-0~-180if (py2 < py1){rad="-rad;}return" rad;}ccpoint getangeleposition(float r,float angle){return ccp(r*cos(angle),r*sin(angle));} 抬起事件bool hrocker::cctouchbegan(cctouch *ptouch, ccevent *pevent){ccpoint point="pTouch-">
GetLocation (); CCSprite * rocker = (CCSprite *) this-> getChildByTag (tag_rocker); if (rocker-> boundingBox (). containsPoint (point) {isCanMove = true; CCLOG ("begin");} return true;} // mobile event void HRocker: ccTouchMoved (CCTouch * pTouch, CCEvent * pEvent) {if (! IsCanMove) {return;} CCPoint point = pTouch-> getLocation (); CCSprite * rocker = (CCSprite *) this-> getChildByTag (tag_rocker ); // obtain the float angle = getRad (rockerBGPosition, point) formed between the joystick and the touch screen ); // determine whether the center distance of the two circles is greater than the radius of the rocker background if (sqrt (pow (rockerBGPosition. x-point. x), 2) + pow (rockerBGPosition. y-point. y), 2)> = rockerBGR) {// guarantee the length of the inner circle movement restriction rocker-> setPosition (ccpAdd (getAngelePosition (rockerBGR, angle), ccp (rockerBGPosition. x, rockerBGPosition. y); // CCLOG ("touch");} else {// if the value does not exceed, move the joystick following the user's touch point to rocker-> setPosition (point ); // CCLOG ("touch");} // determines the direction. if (angle> =-PI/4 & angle
= PI/4 & angle <3 * PI/4) {rocketDirection = rocker_up; CCLOG ("% d", rocketDirection );} else if (angle> = 3 * PI/4 & angle <= PI) | (angle> =-PI & angle <-3 * PI/4 )) {rocketDirection = rocker_left; rocketRun = true; CCLOG ("% d", rocketDirection );} else if (angle >=- 3 * PI/4 & angle <-PI/4) {rocketDirection = rocker_down; CCLOG ("% d", rocketDirection );}} // exit event void HRocker: ccTouchEnded (CCTouch * pTouch, CCEvent * pEvent) {if (! IsCanMove) {return;} CCSprite * rockerBG = (CCSprite *) this-> getChildByTag (tag_rockerBG); CCSprite * rocker = (CCSprite *) this-> getChildByTag (tag_rocker ); rocker-> stopAllActions (); rocker-> runAction (CCMoveTo: create (0.08f, rockerBG-> getPosition (); isCanMove = false; rocketDirection = rocker_stay; CCLOG ("% d", rocketDirection); CCLOG ("end");} void HRocker: update (float dt) {if (isCanMove ){}}
Here's the idea. Let's talk about it later.
Add the header file # include "HRocker. h" in HelloWorldScene. h and add the member variables of the joystick class.
private: HRocker* rocker;
Add the following in the init () function of HelloWorldScene. h:
// Add the joystick rocker = HRocker: createHRocker ("Direction_bt.png", "Direction_bc.png", ccp (); // The button with the first picture as the joystick, the second is the background. this-> addChild (rocker, 2); rocker-> startRocker (true );
The effect is as follows: we can see that you can move the joystick.
The effect is good, very sensitive, and the ball won't jump out.
3. Add the genie and use the joystick to control the movements of the genie.
Here, in order to allow the genie to run, I created a class, Hero, which inherits CCNode and implements animation play and stop.
Zhao Yun's actions are actually a series of images merged together,
In addition, when Zhao Yun does not exercise, the image is
Zhoayun.png. This is the texture image of the sprite when it is not moving,
Here I directly use the tool TexturePacker to package them to generate the corresponding png and plist, the two together can form an animation in the cocos2d-x, relatively easy
The names are run_animation.png and run_animation.plist, and place them in the Resources folder of the project.
To make the code easier to understand, I created a class, Hero, which inherits CCNode and contains the member variable CCSprite * m_HeroSprite; we achieve motion by controlling its animation. It implements playing and stopping the animation. The Code is as follows:
Hero. h
# Ifndef _ HERO_H __# define _ HERO_H __# include "cocos2d. h "# include" cocos-ext.h "using namespace cocos2d; USING_NS_CC_EXT; class Hero: public cocos2d: CCNode {public: Hero (void );~ Hero (void); // create the Hero void InitHeroSprite (char * hero_name) based on the image name; // set the animation. num indicates the number of images, run_directon indicates the sprite face orientation, and false indicates the right direction, name_each is the public name part of each small image in name_png void SetAnimation (const char * name_plist, const char * name_png, const char * name_each, const unsigned int num, bool run_directon ); // stop the animation void StopAnimation (); // judge whether the animation bool IsRunning is running; // the direction of the Hero movement is bool HeroDirecton; CREATE_FUNC (Hero); private: CCSprite * m_HeroSprite; // genie char * Hero_name; // The Name Of The sprite image used to save the initial state}; # endif // _ HERO_H __
Then Hero. cpp
# Include "Hero. h "USING_NS_CC; USING_NS_CC_EXT; Hero: Hero (void) {IsRunning = false; // HeroDirecton = false; // Hero_name = NULL to the right;} Hero :: ~ Hero (void) {} void Hero: InitHeroSprite (char * hero_name) {Hero_name = hero_name; this-> m_HeroSprite = CCSprite: create (hero_name ); this-> addChild (m_HeroSprite);} // animation playback, which can be run, attack, death, injury, etc. void Hero: SetAnimation (const char * name_plist, const char * name_png, const char * name_each, unsigned int num, bool run_directon) {if (HeroDirecton! = Run_directon) {HeroDirecton = run_directon; m_HeroSprite-> setFlipX (run_directon);} if (IsRunning) return; // load the image to the cache pool of the sprite frame. Optional * m_frameCache = cached :: values (); m_frameCache-> values (name_plist, name_png); // save all CCSpriteFrameCache CCArray * frameArray = CCArray: createWithCapacity (num); unsigned int I; for (I = 2; I <= num; I ++) {CCSpriteFrame * fra Me = m_frameCache-> spriteFrameByName (CCString: createWithFormat ("%s0000d.png", name_each, I)-> getCString (); frameArray-> addObject (frame );} // use the list to create an animation object CCAnimation * animation = CCAnimation: createWithSpriteFrames (frameArray); if (HeroDirecton! = Run_directon) {HeroDirecton = run_directon;} animation-> setLoops (-1); // indicates the infinite loop playback of animation-> setDelayPerUnit (0.1f ); // The interval between two images. The smaller the number of images, the smaller the interval. // encapsulate the animation into an action CCAnimate * act = CCAnimate: create (animation ); m_HeroSprite-> runAction (act); IsRunning = true;} void Hero: StopAnimation () {if (! IsRunning) return; m_HeroSprite-> stopAllActions (); // The current genie stops all animations. // restores the original initialization texture of the Genie. this-> removeChild (m_HeroSprite, TRUE ); // Delete the original sprite m_HeroSprite = CCSprite: create (Hero_name); // restore the sprite's original texture m_HeroSprite-> setFlipX (HeroDirecton ); this-> addChild (m_HeroSprite); IsRunning = false ;}
Add the header file # include "Hero. h" in HelloWorldScene. h and add the member variables.
private: Hero* hero;
Add the following in the init () function of HelloWorldScene. h:
// Add the hero = Hero: create (); hero-> InitHeroSprite ("zhoayun.png"); hero-> setPosition (ccp (200,200 )); this-> addChild (hero, 1 );
The effect is as follows:
At this time, the picture is still static. To verify the movement of an genie, let's play a moving animation on it.
hero=Hero::create();hero->InitHeroSprite("zhoayun.png");hero->setPosition(ccp(200,200));this->addChild(hero,1);
Add a sentence
Hero-> SetAnimation ("run_animation.plist", "run_animation.png", 8, false); // 8 indicates the number of images in plist; false indicates the number of faces facing to the right.
Let's take a look at the effect, and the genie will keep moving.
What if we want to change the face orientation of the genie? Simple: Change false to true.
Hero-> SetAnimation ("run_animation.plist", "run_animation.png", 8, true); // 8 indicates the number of images in plist, and false indicates face to right
Effect:
Well, after the verification is correct, we didn't comment out the above sentence, because the genie should have been moved by a joystick.
In fact, it is very easy to control the movement of characters. It is nothing more than moving the genie position while playing the room animation. Of course, here we also need to judge the face orientation of the genie, in the above joystick class HRocker
// Determines the direction of the control lever. It is used to determine the movement of the int rocketDirection on the top, bottom, left, and right of the Genie. // It is used to determine the direction of the sprite, whether the sprite face is right or left bool rocketRun;
We only need to pass these two parameters to Zhao's Hero
// Set the animation. num indicates the number of images, run_directon indicates the sprite face orientation, and false indicates the right direction.
Void SetAnimation (const char * name_plist, const char * name_png, const unsigned int num, bool run_directon );
No. One is the int type and the other is the bool type. So how can we control it. We didn't create two objects in HelloWorldScene.
Private: HRocker * rocker; // joystick Hero * hero; // genie
Is it possible to pass the rocker value to hero? To update each frame, add an event to HelloWorldScene. h.
virtual void update(float delta);
Be sure to add the following content under the init () function of HelloWorldScene. cpp.
// Start the updata event this-> scheduleUpdate ();
Then there is the event.
Void HelloWorld: update (float delta) {// determines whether to press the joystick and its type switch (rocker-> rocketDirection) {case 1: hero-> SetAnimation ("run_animation.plist ", "run_animation.png", "run _", 8, rocker-> rocketRun ); // "run _" indicates the public name of each image in the run_animation.png set. hero-> setPosition (ccp (hero-> getPosition (). x + 1, hero-> getPosition (). y); // break to the right; case 2: hero-> SetAnimation ("run_animation.plist", "run_animation.png", "run _", 8, rocker-> rocketRun ); // "run _" indicates the public name of each image in the run_animation.png set. hero-> setPosition (ccp (hero-> getPosition (). x, hero-> getPosition (). y + 1); // go up to break; case 3: hero-> SetAnimation ("run_animation.plist", "run_animation.png", "run _", 8, rocker-> rocketRun); // "run _" indicates the public name of each image in the run_animation.png set. hero-> setPosition (ccp (hero-> getPosition (). x-1, hero-> getPosition (). y); // take break to the left; case 4: hero-> SetAnimation ("run_animation.plist", "run_animation.png", "run _", 8, rocker-> rocketRun ); // "run _" indicates the public name of each image in the run_animation.png set. hero-> setPosition (ccp (hero-> getPosition (). x, hero-> getPosition (). y-1); // walk down break; default: hero-> StopAnimation (); // stop all animation and motion break ;}}
Okay. Let's see how it works.
The effect is not bad. It's done!
Iv. SummaryIn fact, the idea here is to split the genie classes of the joystick class into different ones. The joystick class can control the movement of buttons and return the current operation type of your joystick, whether it is up or down, yes, face-to-right and left, and then pass these parameters to the hero genie class. Here, the hero should also be animated, then, you can call them at the image layer of the instance that creates two classes, and in the updata () function, you can determine whether the joystick is pressed and in the direction, then set the playing of the mobile animation of the Zhao Yun genie class. This is the way of thinking. Because the project has to be changed all the time, if anyone wants my materials and projects now, leave me an email. I will send it to you.