Cocos 2d-xFinal Project Trampling Record (Cocos Studio Control Acquisition, Character Mobility and Animation, Collision Detection, Background Music and Scene)

Cocos 2d-xFinal Project Trample Record

We have to Tucao first, the overall framework of Cocos is very strong, but many details are not humanized, and the official documents are not keeping up with them. This leads to wasting a lot of time in some unnecessary pits. It is really not cost-effective. Record the end of the project and use cocos2d-x3.10 to develop the pits.

1. Acquisition of csb file components exported by Cocos Studio

auto rootNode = CSLoader::createNode("LoginScene/LoginScene.csb");//Getting csb
Layout* background = (Layout*)rootNode->getChildByName("background");//Getting Layers on csb
Button* btnMenu = (Button*)Helper::seekWidgetByName(background, "menubutton");//Get the button on the layer

Note that the child control name can only be capitalized, if not capitalized, there will be no error (Orz, I really do not know what the siege lion thought at that time, a long step to look at the address found)

Pit daddy index:

2. Touch Detection of Cocos Studio Button Control

The range is based on your Button image, so if it's a circular button, you have to cut out the circle to make it accurate.

Number of Prime Number of Pit Dad:

3. Role Moving and Animation Playing

This plan is to write a detailed topic in the summer vacation. The role's position movement is the default dispatcher + keyboard monitor. Each frame will detect keys and make corresponding movement. The role's animation is written in init with another function + keyboard monitor. At first, I didn't think so much about it. Both of them are combined, but I found that using the dispatcher to play animation or function. Controlling movement will lead to discontinuity of action or distortion of coordination, so we have to write two things separately, and then separate the speed, and finally achieved.

Role Location Mobility:

//Scheduler
void MapOfGame::update(float delta) {
    Node::update(delta);
    role1.loadPositon();
    auto upArrow = EventKeyboard::KeyCode::KEY_UP_ARROW,
        downArrow = EventKeyboard::KeyCode::KEY_DOWN_ARROW,
        leftArrow = EventKeyboard::KeyCode::KEY_LEFT_ARROW,
        rightArrow = EventKeyboard::KeyCode::KEY_RIGHT_ARROW;
    if (isKeyPressed(upArrow)) {
        keyPressedMovement(upArrow);
    }
    else if (isKeyPressed(downArrow)) {
        keyPressedMovement(downArrow);
    }
    else if (isKeyPressed(leftArrow)) {
        keyPressedMovement(leftArrow);
    }
    else if (isKeyPressed(rightArrow)) {
        keyPressedMovement(rightArrow);
    }
}

........
  //Corresponding Moving Function
  void MapOfGame::keyPressedMovement(EventKeyboard::KeyCode keyCode) {
    CCPoint moveByPosition;
    RoleDirection tag;
    //you can set move speed here
    switch (keyCode) {
    case EventKeyboard::KeyCode::KEY_UP_ARROW:
        moveByPosition = ccp(0, role1.getSpeed());
        break;
    case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
        moveByPosition = ccp(0, -role1.getSpeed());
        break;
    case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
        moveByPosition = ccp(-role1.getSpeed(), 0);
        break;
    case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
        moveByPosition = ccp(role1.getSpeed(), 0);
        break;
    default:
        moveByPosition = ccp(0, 0);
        break;
    }
  //Create MoveBy objects and perform mobile actions
    auto move = CCMoveBy::create(0.01f, moveByPosition);
    role1.role->runAction(move);
}

Animation in Character Moving

//These are written in init.
    //add keyboard listener
    auto listener = EventListenerKeyboard::create();
    //call responding animation when realted key is pressed
    listener->onKeyPressed = [=](EventKeyboard::KeyCode keyCode, Event *event) {
        keys[keyCode] = true;
        switch (keyCode){
        case EventKeyboard::KeyCode::KEY_UP_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
            keyPressedAnimation(keyCode);
            break;
        case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
            keyPressedAnimation(keyCode);
            break;
        default:
            break;
    }
};    


.......
  //Corresponding to the animation function, walkAnimation is the animation array of four directional sequence frames previously made.
  void MapOfGame::keyPressedAnimation(EventKeyboard::KeyCode keyCode) {
    RoleDirection tag;
    //you can set move speed here
    switch (keyCode) {
    case EventKeyboard::KeyCode::KEY_UP_ARROW:
        tag = kUp;
        break;
    case EventKeyboard::KeyCode::KEY_DOWN_ARROW:
        tag = kDown;
        break;
    case EventKeyboard::KeyCode::KEY_LEFT_ARROW:
        tag = kLeft;
        break;
    case EventKeyboard::KeyCode::KEY_RIGHT_ARROW:
        tag = kRight;
        break;
    default:
        break;
    }
    animations[tag] = RepeatForever::create(CCAnimate::create(walkAnimations[tag]));
    //animations[tag] = CCAnimate::create(walkAnimations[tag]);
    role1.role->runAction(animations[tag]);
}

Pit daddy index:

4. Attention to Collision Detection Using Scheduler

My idea of collision detection is to call the correlation function once per frame in the dispatcher (in fact, it will not move illegally when it is written with the position moving function) to ensure the timeliness of detection, but it is unexpectedly found that there is no problem when one-step debugging, once it runs, it will appear that the "inertia is too big" to rush out of the collision area and get stuck (coordinates at this time). It's illegal, so I can't move. It took me several hours to detect no logic error. After sleeping the next day, I suddenly found that the duration set by my MoveBy is 0.28f. That is to say, it takes 0.28 seconds to move every frame. However, I have 60 frames per second. That is to say, if I hold the mobile key, it takes 60*0.28s to complete the second movement. This is impossible, so the system may interrupt the last duration process directly when it executes the next time, resulting in collision detection failure. To verify this conjecture, I replace scheduleUpdate, the default scheduler invoked by each frame, with a scheduler that can set the time interval.

//Now the scheduler can set the interval
this->schedule(schedule_selector(MapOfGame::update), 0.05f);
//The code for the collision detection section is a function of the previously posted moving position code.
    //collision check
    CCPoint targetPosition = ccpAdd(role1.role->getPosition(), moveByPosition);
    if (checkCollision(targetPosition, tag) == kWall) {
        setFaceDirection(tag);
        return;
    }
    auto move = CCMoveBy::create(0.01f, moveByPosition);
    role1.role->runAction(move);

I set the time interval of the scheduler to > MoveBy time interval, that is to say, every keyboard monitor and collision detection can ensure that the last movement process has been completed. Sure enough, my role did not appear "inertia too big" into the illegal area of the jam.

Pit daddy index:

5. Switching Background Music in Different Scenes

In the morning after completing the collision detection, I was very happy to think that I had finished the plan ahead of time and wanted to add the sound effects. In my imagination, it would be very easy to put some background music in the next game engine. However, the design of cocos egg pain made it difficult to realize this simple idea.

I used cocos2d-x's audio component # include "Simple Audio Engine. h", and then in each scene called the corresponding function to play background music, Daddy's place came, for example, my Scene1 and Scene2 intend to use different background music, from the former to the latter, the background music will stop playing, the latter music can only play a few seconds, stuck in the consulting network. After a lot of information, it is found that this is due to the characteristics of Cocos 2d-x scene switching. See Guan Dongsheng's blog specifically:

Scene Switching and Background Music

In particular, in this case, you need to rewrite the scenario lifecycle function yourself.

void MapOfGame::onEnter() {
    Layer::onEnter();
}

void MapOfGame::onEnterTransitionDidFinish() {
    Layer::onEnterTransitionDidFinish();
    //play music
    SimpleAudioEngine::getInstance()->playBackgroundMusic("MusicSource/bg/Village.mp3", true);
    SimpleAudioEngine::getInstance()->playEffect("MusicSource/appear.wav");
}

void MapOfGame::onExit() {
    Layer::onExit();
}

void MapOfGame::onExitTransitionDidStart() {
    Layer::onExitTransitionDidStart();
}

void MapOfGame::cleanup() {
    Layer::cleanup();
}

The corresponding switching mode should also be set to push Scene. If repeat Scene is used, the system will automatically transfer the music stopping function. No matter how to make the subsequent Scene silent.

void Login::StartGameTouch(Ref* pSender, Widget::TouchEventType type) {
    switch (type) {
    case Widget::TouchEventType::ENDED:
        auto director = Director::getInstance();
        //transfer to MapScene
        auto scene = MapOfGame::createScene();
        auto transition = TransitionCrossFade::create(1.0f, scene);
        SimpleAudioEngine::getInstance()->stopBackgroundMusic();
        director->pushScene(transition);
        break;
    }
}

The pit daddy index: It's my Tai cuisine.

Keywords: C++ Mobile network

Added by Adarmo on Thu, 27 Jun 2019 03:19:20 +0300