cocos2d-x-3.16 实例开发之ParkourBall

游戏介绍

引擎版本:cocos2d-x-3.16

开发工具:vs2015

重返色の星球是一款休闲益智游戏,星球的史莱特因为一次意外坠落地球,失去了超能力而无法驾驶UFO,只有进行变色训练才能重获超能力,你能帮助它吗?

风格清新,玩法独特,甚至还有点虐心,手残党的亲们要慎重哦!游戏的操控很简单,史莱特会根据你点击的按键颜色而变色,当落到对应颜色的圆盖上就会继续跳跃,这是一个节奏游戏,你必须很好的配合节奏来玩,当100%完成进度就算通关。

 

游戏项目托管在github:https://github.com/smiger/ParkourBall

关卡选择

关卡选择场景MainScene

游戏共有6个关卡可供选择,当然,最开始游戏只能选择第一关,只有通过该关卡就能解锁下一关卡

一、物理场景

1、创建

1

2

3

4

5

6

7

8

//创建一个物理场景

_scene = Scene::createWithPhysics();

//_scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

//设置物理世界的重力

_scene->getPhysicsWorld()->setGravity(Vect(0, -1000));

//添加层到物理世界中

MainScene *layer = MainScene::create();

_scene->addChild(layer);

2、在进入MainScene时设置碰撞监听事件,碰撞后做球的自旋转动作

1

2

3

4

5

6

7

void MainScene::onEnter(){

    Layer::onEnter();

    //碰撞事件监听

    auto contactListenner = EventListenerPhysicsContact::create();

    contactListenner->onContactBegin = CC_CALLBACK_1(MainScene::onContactBegin, this);

    _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListenner, this);

}

1

2

3

4

bool MainScene::onContactBegin(PhysicsContact& contact){

    ball->rotateAction();

    return true;

}

3、初始化时还创建一个静态的线状刚体,让球落下来与该刚体发生碰撞弹起

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

void MainScene::initPhysicWorld(){

    auto visibleSize = Director::getInstance()->getVisibleSize();

    auto origin = Director::getInstance()->getVisibleOrigin();

    //创建一个静态的线状刚体

    auto body = PhysicsBody::createEdgeSegment(origin, Point(visibleSize.width, 0), PHYSICSBODY_MATERIAL_DEFAULT, 1);

    //设置弹性  1-完全

    body->getShape(0)->setRestitution(1);

    //设置body是否受引力影响

    body->setGravityEnable(false);

    //类别标示掩码

    body->setCategoryBitmask(0x01);

    //碰撞掩码

    body->setCollisionBitmask(0x01);

    //接触测试掩码,表示哪些类别的物体“接触”时,会产生消息

    body->setContactTestBitmask(0x01);

    auto edgeNode = Node::create();

    edgeNode->setPosition(0, visibleSize.height/5);

    edgeNode->setPhysicsBody(body);

    this->addChild(edgeNode, 2);

}

4、禁用一个物理世界的auto step,然后通过设定PhysicsWorld::step(time)来手动刷新PhysicsWorld

1

2

_scene->getPhysicsWorld()->setAutoStep(false);

scheduleUpdate();

1

2

3

4

5

6

7

8

void MainScene::update(float t){

    int steps = 3;

    float dt = CCDirector::getInstance()->getAnimationInterval() / (float)steps;

    PhysicsWorld* s = getScene()->getPhysicsWorld();

    for (int i = 0; i<steps; i++){

        s->step(dt);

    }

}

 

二、按钮、关卡界面

1、开始、声音按钮

1

2

3

4

5

6

7

auto *menu = Menu::create();

menu->setPosition(zeroPos);

//开始按钮

auto * menuItemPLay = MenuItemSprite::create(Sprite::create(START_NORMAL), Sprite::create(START_PRESS), CC_CALLBACK_1(MainScene::onPlay, this));

menuItemPLay->setPosition(centerPos.x,centerPos.y+30);

menuItemPLay->setTag(0);

menu->addChild(menuItemPLay);

MenuItemToggle可以实现声音按钮的开关两种状态,类似”ON”->”OFF”.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

//声音菜单

auto soundOnMenuItem = MenuItemImage::create(

    SOUND_OPEN,

    SOUND_OPEN);

auto soundOffMenuItem = MenuItemImage::create(

    SOUND_CLOSE,

    SOUND_CLOSE);

auto soundToggleMenuItem = MenuItemToggle::createWithCallback(

    CC_CALLBACK_1(MainScene::onPlay, this),

    soundOnMenuItem,

    soundOffMenuItem,

    NULL);

soundToggleMenuItem->setAnchorPoint(ccp(0.5, 0.5));

soundOnMenuItem->setScale(0.8);

soundOffMenuItem->setScale(0.8);

soundToggleMenuItem->setTag(100);

soundToggleMenuItem->setPosition(

    Point(soundOnMenuItem->getContentSize().width / 2, soundOnMenuItem->getContentSize().height / 2));

menu->addChild(soundToggleMenuItem);

2、关卡选择

用循环将六个关卡展示出来,如果还未解锁的加锁标志

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

//显示关卡

int num = CHECK_POINT_NUM + 1;

for (int i = 1; i < num; i++){

    auto * menuCheckPoint = MenuItemSprite::create(Sprite::createWithSpriteFrameName("cylinder.png"), Sprite::createWithSpriteFrameName("cylinder_press.png")

        , CC_CALLBACK_1(MainScene::onPlay, this));

    menuCheckPoint->setTag(i);

    menuCheckPoint->setPosition(Point(size.width / num * i, size.height/5 ));

    menuCheckPoint->setScale(0.8);

    menu->addChild(menuCheckPoint);

    //数字

    String *str = String::createWithFormat("checkPoint%i.png", i);

    Sprite *sprite = Sprite::createWithSpriteFrameName(str->getCString());

    sprite->setPosition(Point(size.width / num * i, size.height/5  - sprite->getContentSize().height / 2 - menuCheckPoint->getContentSize().height / 2));

    this->addChild(sprite);

 

    //不可选择关卡加锁标志

    String *c_str = String::createWithFormat("checkPoint%i",i);

    if (i != 1 && !CCUserDefault::sharedUserDefault()->getBoolForKey(c_str->getCString(), false) ){

        Sprite *lockSprite = Sprite::createWithSpriteFrameName("lock.png");

        lockSprite->setPosition(Point(size.width / num * i, size.height/5 + lockSprite->getContentSize().height / 2 + menuCheckPoint->getContentSize().height / 2));

        this->addChild(lockSprite);

    }

}

 

球和圆盘

一、基类

球和圆盘继承Base基类,我们先看下基类有哪些方法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

class Base : public Node

{

public:

    Base();

    //虚析构函数

    virtual ~Base();

    //继承自Node的虚函数 不同派生类定义自己的版本

    virtual bool init();

    //绑定刚体  不同派生类自己定义不同的刚体

    virtual void initBody();

    //设置精灵

    void setSprite(Sprite* sprite);

    //获取精灵

    Sprite * getSprite();

    //获取精灵大小

    Size getConSize();

 

private:

    Sprite * sprite;

    ParticleSystem *_emitter;

};

二、球

1、初始化中先绑定精灵、刚体,球的碰撞掩码要与线状刚体的类别标识掩码逻辑与不为0,如果body->setCollisionBitmask(0x02);球将直接掉落

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

void Ball::initBody(){

    //创建一个方形body

    auto body = PhysicsBody::createCircle(getConSize().width / 2); 

    body->getShape(0)->setRestitution(1);

    //你可以定义哪些物理刚体相互作用并且你的游戏何时接受这些相互作用的通知

    body->setCategoryBitmask(0x01);

    //这个刚体的碰撞掩码和另一个刚体的分类掩码进行逻辑与运算比较。如果结果是一个非零值,这个刚体会发生碰撞。

    body->setCollisionBitmask(0x01);

    //通过设置接触测试掩码,你可以决定发生碰撞后,回调函数是否有响应

    body->setContactTestBitmask(0x01);

    //无摩擦

    body->getShape(0)->setFriction(0);

    //让物理引擎对象和精灵对象关联起来

    getSprite()->setPhysicsBody(body);

}

2、球还有设置不同颜色、获取颜色、游戏一开始施加跳跃的速度、自旋等方法

1

2

3

4

void doAction(const char* actionName);//自旋

void jump();//跳跃

void setBallColor(CylinderColor color);//设置颜色

CylinderColor getBallColor();//获取颜色,CylinderColor是枚举变量

三、圆盘

圆盘类主要有设置颜色、获取颜色方法,没有用到绑定刚体,而是在场景中圆盘的y轴位置创建一个静态的线状刚体,来实现与球的碰撞,球弹起的效果

圆盘管理类

圆盘管理类:BaseManager

1、游戏开始会创建25个圆盘,前5个是红色,其余20个颜色则是随机产生,产生的圆盘会加入cylinderList列表中

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

void BaseManager::createCylinder(){

    auto size = Director::getInstance()->getVisibleSize();

    Cylinder *cylinder = NULL;

    for (int i = 1; i <= cylinderNum; ++i){

        cylinder = Cylinder::create();

        cylinder->setVisible(true);

        cylinder->setPosition(size.width/4 + cylinder->getConSize().width * (i - 1), size.height/2 );

        if (i > 5){

            int num = 2;

            switch (checkPoint)

            {

            case 1:

            case 2:

                num = CCRANDOM_0_1() * 10;

                if (num <= 5){

                    cylinder->setCylinderColor(red);

                }

                else{

                    cylinder->setCylinderColor(green);

                }

            break;

            case 3:

            case 4:

                num = CCRANDOM_0_1() * 30;

                if (num <= 10){

                    cylinder->setCylinderColor(red);

                }

                else if (num <= 20){

                    cylinder->setCylinderColor(green);

                }

                else if (num <= 30){

                    cylinder->setCylinderColor(blue);

                }

             

                break;

            case 5:

            case 6:

                num = CCRANDOM_0_1() * 40;

                if (num <= 10){

                    cylinder->setCylinderColor(red);

                }

                else if (num <= 20){

                    cylinder->setCylinderColor(green);

                }

                else if (num <= 30){

                    cylinder->setCylinderColor(blue);

                }

                else if (num <= 40){

                    cylinder->setCylinderColor(yellow);

                }

                break;

            default:

                break;

            }

        }

        else{

            //设置为红色

            cylinder->setCylinderColor(red);

        }

        this->addChild(cylinder);

        cylinderList.push_back(cylinder);

    }

}

可以看到第一个圆盘的横坐标位置是size.width/4,这与球的开始位置是一致的

2、当球与圆盘(其实碰撞的不是圆盘,而是一条在圆盘位置的线状刚体)发生碰撞后,会调用BaseManager::update遍历每个圆盘,如果圆盘超出左边的屏幕,则会重新设置位置颜色到最后一个。然后碰撞到的圆盘会有下上的动作并向左移动位置,其他圆盘直接向左移动

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

void BaseManager::update(float dt){

    auto size = Director::getInstance()->getVisibleSize();

    Ref * obj = NULL;

    Cylinder * cylinder = NULL;

    //是否移动到末尾,isMove=false表示到末尾

    if (isMove){

        for (list<Cylinder*>::iterator iter = cylinderList.begin(); iter != cylinderList.end(); iter++){

            cylinder = (Cylinder*)*iter;

            if (cylinder->getPositionX() <= -cylinder->getConSize().width / 2){

                //如果圆盘已经移出左屏幕外,则移到右边最后面

                Cylinder *front = cylinder;

                Cylinder *back = cylinderList.back();

                front->setPosition(back->getPosition().x + back->getConSize().width, back->getPosition().y);

                //重新设置颜色

                int num = 2;

                switch (checkPoint)

                {

                case 1:

                case 2:

                    num = CCRANDOM_0_1() * 10;

                    if (num <= 5){

                        front->setCylinderColor(red);

                    }

                    else{

                        front->setCylinderColor(green);

                    }

                    break;

                case 3:

                case 4:

                    num = CCRANDOM_0_1() * 30;

                    if (num <= 10){

                        front->setCylinderColor(red);

                    }

                    else if (num <= 20){

                        front->setCylinderColor(green);

                    }

                    else if (num <= 30){

                        front->setCylinderColor(blue);

                    }

 

                    break;

 

                case 5:

                case 6:

                    num = CCRANDOM_0_1() * 40;

                    if (num <= 10){

                        front->setCylinderColor(red);

                    }

                    else if (num <= 20){

                        front->setCylinderColor(green);

                    }

                    else if (num <= 30){

                        front->setCylinderColor(blue);

                    }

                    else if (num <= 40){

                        front->setCylinderColor(yellow);

                    }

                    break;

                default:

                    break;

                }

                iter = cylinderList.erase(iter);

                cylinderList.push_back(front);

            }

        }

    }

    else{

        //最后一个设置结束颜色

        Cylinder *back = cylinderList.back();

        back->setCylinderColor(endColor);

    }

     

    for (list<Cylinder*>::iterator iter = cylinderList.begin(); iter != cylinderList.end(); iter++){

        cylinder = (Cylinder*)*iter;

        ActionInterval * moveDown = MoveBy::create(0.05f, Point(0, -10));

        ActionInterval * moveUp = MoveBy::create(0.05f, Point(0, 10));

        ActionInterval * moveBy = MoveBy::create(0.2f, Point(-cylinder->getConSize().width, 0));

        DelayTime * delay = DelayTime::create(0.1);

         

        if (cylinder->getPosition().x == size.width/4){

            //球碰撞的圆盘上下运动并向左移

            cylinder->runAction(Sequence::create(moveDown, moveUp, moveBy, NULL));

        }

        else {

            cylinder->runAction(Sequence::create(delay, moveBy, NULL));

        }

         

    }

 

}

 

游戏主场景

游戏主场景:PlayScene

一、创建物理场景

物理场景跟关卡界面是类似的

1

2

3

4

5

6

7

8

//创建一个物理场景

_scene = Scene::createWithPhysics();

//_scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

//设置物理世界的重力

_scene->getPhysicsWorld()->setGravity(Vect(0, -1300));

//添加层到物理世界中

PlayScene *layer = PlayScene::create();

_scene->addChild(layer);

创建线状刚体

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

void PlayScene::initPhysicWorld(){

    auto visibleSize = Director::getInstance()->getVisibleSize();

    auto origin = Director::getInstance()->getVisibleOrigin();

    //创建一个静态的线状刚体

    auto body = PhysicsBody::createEdgeSegment(origin, Point(visibleSize.width, 0), PHYSICSBODY_MATERIAL_DEFAULT, 1);

    //设置弹性  1-完全

    body->getShape(0)->setRestitution(1);

    //设置摩擦力  

    body->getShape(0)->setFriction(0);

    //设置body是否受引力影响

    body->setGravityEnable(false);

    //类别标示掩码

    body->setCategoryBitmask(0x01);

    body->setCollisionBitmask(0x01);

    body->setContactTestBitmask(0x01);

    auto edgeNode = Node::create();

    edgeNode->setPosition(0, visibleSize.height/2);

    edgeNode->setPhysicsBody(body);

    edgeNode->setTag(edgeNodeTag);

    this->addChild(edgeNode, 2);

}

还有设置碰撞监听等

二、初始界面

1、初始球、圆盘等

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

    //背景

    auto *spriteBG = Sprite::create(PLAY_BG);

    spriteBG->setPosition(centerPos);

    this->addChild(spriteBG,0);

     

    //球

    ball = Ball::create();

     

    //球的初始位置

    ball->setPosition(size.width/4, size.height/2 + ball->getConSize().height / 2);

    this->addChild(ball,2); 

    setBallDefaultColor();

......

    //cylinder管理类

    m_manager = BaseManager::create();

    this->addChild(m_manager,1);

     

    //粒子

    ParticleSystem *_emitter = ParticleRain::create();

    _emitter->setAutoRemoveOnFinish(true);

    _emitter->setPosition(size.width/2,size.height);

    this->addChild(_emitter, 5);

 

    //进度

    labelTTFCardNumber = LabelTTF::create("0""HiraKakuProN-w6", 50);

    labelTTFCardNumber->setColor(Color3B::WHITE);

    labelTTFCardNumber->setPosition(

        Point(size.width / 2, size.height / 2 + labelTTFCardNumber->getContentSize().height + 20));

    this->addChild(labelTTFCardNumber, 2);

    labelTTFCardNumber->setString(

        StringUtils::format("%d%%", 0));

2、游戏方式介绍

根据不同关卡展示不同玩法

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

void PlayScene::createPlayWay(){

    auto size = Director::getInstance()->getVisibleSize();

    auto zeroPos = Director::getInstance()->getVisibleOrigin();

    auto centerPos = Point(size.width / 2, size.height / 2);

    auto *menu = Menu::create();

    menu->setPosition(zeroPos);

    if (checkPoint == 1){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_1), Sprite::create(PLAY_WAY_1), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    else if (checkPoint == 2){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_2), Sprite::create(PLAY_WAY_2), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    else if (checkPoint == 3){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_3), Sprite::create(PLAY_WAY_3), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    else if (checkPoint == 4){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_4), Sprite::create(PLAY_WAY_4), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    else if (checkPoint == 5 ){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_5), Sprite::create(PLAY_WAY_5), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    else if ( checkPoint == 6){

        auto * menuItemPLay = MenuItemSprite::create(Sprite::create(PLAY_WAY_6), Sprite::create(PLAY_WAY_6), CC_CALLBACK_1(PlayScene::onStart, this));

        menuItemPLay->setPosition(centerPos);

        menu->addChild(menuItemPLay);

    }

    menu->setTag(playwayTag);

    this->addChild(menu,10);

}

3、点击游戏玩法响应,游戏正式开始

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

void PlayScene::onStart(cocos2d::Ref* pSender){

    isGameBegin = true;

    //移除介绍游戏方式菜单

    this->removeChildByTag(playwayTag);

    //播放音乐

    playMusicByCheckPoint();

    //设置重力

    setWorldGravity();

    //创建控制按钮

    createControlBtn();

    //给小球速度

    ball->jump();

    //进度更新

    this->schedule(schedule_selector(PlayScene::addTime), 1.0f, kRepeatForever, 1);

}

三、游戏中

游戏开始有给小球速度,由于刚体设置摩擦力为0,完全弹力等因素影响,小球将无限弹起落下到游戏结束。主要逻辑在碰撞监听函数里实现,不同的关卡游戏失败的逻辑有所区别

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

bool PlayScene::onContactBegin(PhysicsContact& contact){

    auto size = Director::getInstance()->getVisibleSize();

    if (!isGameBegin){

        return true;

    }

    //获取碰撞物体

    auto body1 = (Sprite *)contact.getShapeA()->getBody()->getNode();

    auto body2 = (Sprite *)contact.getShapeB()->getBody()->getNode();

    CylinderColor ballColor = normal;

    CylinderColor cylinderColor = normal;

     

    //判断是否为球

    if (body1->getTag() == ballTag){

        ballColor = ball->getBallColor();

    }

    if (body2->getTag() == ballTag){

        ballColor = ball->getBallColor();

    }

 

    //从圆盘列表里获取当前碰撞圆盘的颜色

    list <Cylinder*> cylinderList = m_manager->getCylinderList();

    Cylinder* cylinder;

    for (list<Cylinder*>::iterator iter = cylinderList.begin(); iter != cylinderList.end(); iter++){

        cylinder = (Cylinder*)*iter;

        if (cylinder->getPosition().x == size.width/4){

            cylinderColor = cylinder->getCylinderColor();

            break;

        }

    }

    //关卡

    switch (checkPoint)

    {

    case 1:

        //如果颜色不同且圆盘不是最后一个则游戏结束

        if (cylinderColor != normal && cylinderColor != endColor  && cylinderColor != ballColor){

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

            GameOver();

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(false, percent));

            Director::getInstance()->replaceScene(endLayer);

 

 

            return false;

        }

        else if (cylinderColor == endColor){

            if (CCUserDefault::sharedUserDefault()->getBoolForKey("sound"true)){

                CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(MUSIC_WIN, false);

            }

 

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

 

            //设置下一关卡开启

            String *c_str = String::createWithFormat("checkPoint%i", checkPoint + 1);

            CCUserDefault::sharedUserDefault()->setBoolForKey(c_str->getCString(), true);

            //跳转到游戏成功结束界面

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(true, percent));

            Director::getInstance()->replaceScene(endLayer);

            return true;

        }

        break;

    case 2:

        //关卡2是要求球与圆盘颜色相反,所以如果相同则失败

        if (cylinderColor != normal && cylinderColor != endColor && cylinderColor == ballColor){

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

            GameOver();

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(false, percent));

            Director::getInstance()->replaceScene(endLayer);

            return false;

        }

        else if (cylinderColor != normal && ballColor == normal){

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

            GameOver();

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(false, percent));

            Director::getInstance()->replaceScene(endLayer);

            return false;

        }

        else if (cylinderColor == endColor){

            if (CCUserDefault::sharedUserDefault()->getBoolForKey("sound"true)){

                CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(MUSIC_WIN, false);

            }

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

 

            String *c_str = String::createWithFormat("checkPoint%i", checkPoint + 1);

            CCUserDefault::sharedUserDefault()->setBoolForKey(c_str->getCString(), true);

 

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(true, percent));

            Director::getInstance()->replaceScene(endLayer);

            return true;

        }

        break;

    case 3:

    case 4:

    case 5:

        //

        if (cylinderColor != normal && cylinderColor != endColor  && cylinderColor != ballColor){

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

            GameOver();

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(false, percent));

            Director::getInstance()->replaceScene(endLayer);

            return false;

        }

        else if (cylinderColor == endColor){

            if (CCUserDefault::sharedUserDefault()->getBoolForKey("sound"true)){

                CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(MUSIC_WIN, false);

            }

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

 

            String *c_str = String::createWithFormat("checkPoint%i", checkPoint + 1);

            CCUserDefault::sharedUserDefault()->setBoolForKey(c_str->getCString(), true);

 

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(true, percent));

            Director::getInstance()->replaceScene(endLayer);

            return true;

        }

        break;

    case 6:

        if (cylinderColor != normal && cylinderColor != endColor  && cylinderColor != ballColor){

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

            GameOver();

            auto endLayer = TransitionFade::create(1, EndLayer::createScene(false, percent));

            Director::getInstance()->replaceScene(endLayer);

            return false;

        }

        else if (cylinderColor == endColor){

            if (CCUserDefault::sharedUserDefault()->getBoolForKey("sound"true)){

                CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(MUSIC_WIN, false);

            }

            CocosDenshion::SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();

 

            auto scene = TransitionFade::create(1, LeaveLayer::createScene());

            Director::getInstance()->replaceScene(scene);

            return true;

        }

        break;

    default:

        break;

    }

    //球自旋转

    ball->rotateAction();

    //圆盘管理

    m_manager->update(0);

    return true;

}

 

游戏结束层

游戏结束层:EndLayer

游戏结束层带有两个参数,第一个参数是是否成功,第二个参数完成百分比

1

2

3

4

5

6

Scene * EndLayer::createScene(bool isWin, int percent){

    auto scene = Scene::create();

    EndLayer *layer = new EndLayer( isWin,  percent);

    scene->addChild(layer);

    return scene;

}

无论游戏成功失败都有返回选关主界面的菜单按钮

1

2

3

4

5

6

7

8

9

10

//创建菜单

auto *menu = Menu::create();

menu->setPosition(zeroPos);

//返回选关主界面

auto * menuCheckPoint = MenuItemSprite::create(Sprite::createWithSpriteFrameName("menuNormal.png"), Sprite::createWithSpriteFrameName("menuPress.png")

, CC_CALLBACK_1(EndLayer::menu, this));

menuCheckPoint->setTag(menuTag);

menuCheckPoint->setPosition(Point(centerPos.x - menuCheckPoint->getContentSize().width / 2, size.height / 3));

menuCheckPoint->setScale(0.7);

menu->addChild(menuCheckPoint);

区别在于成功是下一关按钮,失败是重新开始按钮

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

if (isWin){

    //胜利了而且不是最后一关  显示下一关按钮

    if (checkPoint != CHECK_POINT_NUM){

        auto * menuCheckPoint = MenuItemSprite::create(Sprite::createWithSpriteFrameName("nextNormal.png"), Sprite::createWithSpriteFrameName("nextPress.png")

            , CC_CALLBACK_1(EndLayer::next, this));

        menuCheckPoint->setTag(nextTag);

        menuCheckPoint->setPosition(Point(centerPos.x + menuCheckPoint->getContentSize().width / 2, size.height / 3));

        menuCheckPoint->setScale(0.7);

        menu->addChild(menuCheckPoint);

    }

     

}

else{

    //失败了  显示重新开始按钮

    auto * menuCheckPoint = MenuItemSprite::create(Sprite::createWithSpriteFrameName("reStartNormal.png"), Sprite::createWithSpriteFrameName("reStartPress.png")

        , CC_CALLBACK_1(EndLayer::restart, this));

    menuCheckPoint->setTag(restartTag);

    menuCheckPoint->setPosition(Point(centerPos.x + menuCheckPoint->getContentSize().width / 2, size.height / 3));

    menuCheckPoint->setScale(0.7);

    menu->addChild(menuCheckPoint);

}

剩下的就是精灵图层,完成百分比,提示语信息

Android编译

一、准备好adt和ndk(我用的ndk是r14b版本)

1、导入项目,包括libcocos2dx

image.png

2、ParkourGame右键->Properties->Builders

image.png

3、点击New...->选择Program->点击OK

Location这一栏点击Browse File System...选择你存放NDK路径下的nkd-build.cmd

Working Directory这栏点击Browse Workspace...选择ParkourGame

点击OK

image.png

二、修改Android.mk

1、打开ParkourGame\proj.android\jni\Android.mk

image.png

2、新增的部分是遍历Classes目录的所有.cpp文件赋值LOCAL_SRC_FILES,同时所有文件夹路径赋值LOCAL_C_INCLUDES

1

2

3

4

5

6

7

8

9

10

define walk

    $(wildcard $(1)) $(foreach e, $(wildcard $(1)/*), $(call walk, $(e)))

endef

ALLFILES = $(call walk, $(LOCAL_PATH)/../../Classes)

FILE_LIST := hellocpp/main.cpp

FILE_LIST += $(filter %.cpp, $(ALLFILES))

LOCAL_SRC_FILES := $(FILE_LIST:$(LOCAL_PATH)/%=%)

FILE_INCLUDES := $(filter-out %.cpp, $(ALLFILES))

FILE_INCLUDES := $(filter-out %.h, $(FILE_INCLUDES))

LOCAL_C_INCLUDES := $(FILE_INCLUDES)

3、然后就可以编译了

image.png

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值