cocos2d-xFinalProject踩坑记录(cocosStudio控件获取,角色移动及动画,碰撞检测,背景音乐与场景)

cocos2d-xFinalProject踩坑记录数组

不得不吐槽在先,cocos总体框架十分强悍,可是不少细节的东西写得不够人性化,并且官方的文档也没有跟上,致使浪费大量的时间在一些没必要要的坑上,实在是不划算,记录一下此次期末项目用cocos2d-x3.10开发泡泡堂踩到的坑吧!app

1.cocosStudio导出的csb文件组件获取框架

auto rootNode = CSLoader::createNode("LoginScene/LoginScene.csb");//获取csb
Layout* background = (Layout*)rootNode->getChildByName("background");//获取csb上的层
Button* btnMenu = (Button*)Helper::seekWidgetByName(background, "menubutton");//获取层上的button

注意的是子控件名称只能使用小写,若是用大写的话获取不到,还不会报错(Orz,真不知道当时攻城狮是怎么想的,单步调了好久看地址才发现)函数

坑爹指数:★★★★动画

2.cocosStudio Button控件的Touch检测this

范围是按照你Button图片来的,因此若是是圆形按钮,想作得准确,得把圆抠出来设计

坑爹质数:★调试

3.角色移动和动画播放code

这个打算暑假抽空写个详细的专题,角色的位置移动是采用的默认调度器+键盘监听器,每一帧都会检测按键并作出相应的移动,而角色的动画则是在init里面另写了一个函数+键盘监听器,最开始没想这么多,二者是合在一块儿的,可是发现采用调度器放动画或者函数控制移动都会出现动做不连贯或配合失真,因此无可奈何只能把两个东西分开写,再分开调速度,终于实现了。对象

角色位置移动:

//调度器
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);
    }
}

........
  //对应的移动函数
  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;
    }
  //建立MoveBy对象并执行移动的动做
    auto move = CCMoveBy::create(0.01f, moveByPosition);
    role1.role->runAction(move);
}

角色移动时的动画

//这些是在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;
    }
};    


.......
  //对应的动画函数,walkAnimation是以前弄的四个方向序列帧动画数组
  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]);
}

坑爹指数:★★

4.采用调度器碰撞检测的注意

个人碰撞检测的思路是把相关函数在调度器里每一帧调用一次(实际上和位置移动函数写在一块儿的,非法就不会执行移动),保证检测的及时性,可是却意外发现单步调试时就没有问题,一旦运行起来就会出现“惯性过大”冲出碰撞区域后卡住的状况(此时的坐标已经非法了,因此移动不了),耗了几个小时都没有检测出逻辑错误,次日睡一觉后忽然发现,个人MoveBy设置的duration是0.28f,也就是说我每一帧的移动动做须要0.28秒来完成,然而我每一秒有60帧,也就是说我若是摁住移动键,完成这一秒的移动动做须要60*0.28s,这是不可能了,因此系统可能在执行下一次时直接中断了上一次duration的过程,形成了碰撞检测失效,为了验证这一猜测,我把每一帧调用的默认调度器scheduleUpdate换成了能够设置时间间隔的调度器,不废话,上代码

//如今调度器就能够设置时间间隔了
this->schedule(schedule_selector(MapOfGame::update), 0.05f);
//碰撞检测部分的代码,和以前贴的移动位置代码是一个函数
    //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);

我把调度器的时间间隔设置了>MoveBy的时间间隔,也就是每一次调度键盘监听和碰撞检测都能保证上一次移动的过程已经完成,果真,个人角色没有再出现“惯性过大”冲入非法区域卡住的状况。

坑爹指数:★★★★★★

5.不一样场景下背景音乐的切换

在完成碰撞检测后的上午,我满心欢喜的觉得提早完成了计划,想顺手牵羊把音效给加上去,在个人设想下一个游戏引擎放几个背景音乐应该是再容易不过的事情,然而,cocos蛋疼的设计却让这一简单的设想实现起来变得困难重重。

我采用的是cocos2d-x自带的音频组件#include "SimpleAudioEngine.h",而后在每一个场景中调用对应函数播放背景音乐,坑爹的地方来了,好比说个人Scene1和Scene2打算使用不一样的背景音乐,从前者切换到后者后,背景音乐的播放会中止,后者的音乐只能放几秒就卡住,在查阅了网上大量的资料后,发现这是cocos2d-x场景切换的特性所致,具体见关东升的博文:

场景切换与背景音乐

特别须要注意,在这种状况下,除了须要本身重写一遍场景生命周期函数外

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();
}

还要把对应的切换方式设置为 pushScene,采用repeatScene的话系统会自动调动音乐中止函数,再怎么弄后面的Scene也出不了声

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;
    }
}

坑爹指数:★★★★★(真乃神坑,花了我一天就弄一个背景音乐Orz……是我太菜)

相关文章
相关标签/搜索