cocos2d-x-3.16 实例开发之StickHero

引擎版本:cocos2d-x-3.16

开发工具:vs2015

游戏介绍

StickHero也叫英雄难过棍子关,游戏玩法简单难度却不小,游戏中玩家会成为一位一直前进的勇者,但是在前进的道路上有很多陷阱在阻拦你,这是就需要我们的智慧,靠着游戏中唯一的道具我们手中的那根棍子不断的前进了。

 

一、玩法介绍

    游戏的操作方法很简单,点击屏幕和松开屏幕,当点击屏幕后在游戏人物站立的地方会伸出一根棍子,如果点击屏幕而不松手棍子会一直变长,当松开手指棍子就会停止,然后棍子会向右边倾倒,游戏人物就可以依靠这根棍子通过陷阱。但是棍子只能变长而不能变短,所以需要玩家控制好棍子的长度。

 

二、游戏资源

链接: https://pan.baidu.com/s/1kU-ey4VwbDiU4kUzTMi3iQ 密码: rpqn

代码托管在github:https://github.com/smiger/StickHero

 

欢迎界面

欢迎界面主要有背景、标题、开始按钮、平台、英雄,实现在BackgroundLayer层

QQ截图20180313165738.png

一、背景

资源中有五张背景图片,每次加载时随机选择一张图片作为背景

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

Size MyWinSize = Director::getInstance()->getVisibleSize();

int RandomNumber = CCRANDOM_0_1()*1000;

int BGI_Number = RandomNumber%5;

stage_number = 1;

NowStage = stage_number  == 0 ? 2:stage_number-1;

LastStage = NowStage ==0 ? 2:(NowStage-1);

NextStage = NowStage == 2 ? 0:(NowStage+1);

// 随机选择游戏欢迎界面时的背景图片

switch(BGI_Number){

case 0:

    Image_One = Sprite::create("image/bg/bg1.jpg");

    Image_Two = Sprite::create("image/bg/bg1.jpg");

    break;

case 1:

    Image_One = Sprite::create("image/bg/bg2.jpg");

    Image_Two = Sprite::create("image/bg/bg2.jpg");

    break;

case 2:

    Image_One = Sprite::create("image/bg/bg3.jpg");

    Image_Two = Sprite::create("image/bg/bg3.jpg");

    break;

case 3:

    Image_One = Sprite::create("image/bg/bg4.jpg");

    Image_Two = Sprite::create("image/bg/bg4.jpg");

    break;

case 4:

    Image_One = Sprite::create("image/bg/bg5.jpg");

    Image_Two = Sprite::create("image/bg/bg5.jpg");

    break;

default:

    break;

}

Image_One->setPosition(MyWinSize.width/2,MyWinSize.height/2);

Image_Two->setPosition(MyWinSize.width/2 + Image_Two->getContentSize().width,MyWinSize.height/2);

this->addChild(Image_One,1);

this->addChild(Image_Two,1);

二、开始按钮

开始菜单会上下浮动,用到RepeatForever重复播放动作

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//开始菜单

StartBtn = MenuItemSprite::create(

    Sprite::create("image/uires_2.png"),

    Sprite::create("image/uires_2.png"),

    NULL,this ,menu_selector(BackgroundLayer::Start));

StartBtn->setPosition(MyWinSize.width/2,MyWinSize.height/2+8);

MoveTo* StartBtnMoveDown = MoveTo::create(2,Vec2(MyWinSize.width/2,MyWinSize.height/2-8));

MoveTo* StartBtnMoveUp = MoveTo::create(2,Vec2(MyWinSize.width/2,MyWinSize.height/2+5));

auto StartMoveSeq = Sequence::create(StartBtnMoveDown,StartBtnMoveUp,NULL);

auto StartMoveRepeat = RepeatForever::create(StartMoveSeq);

StartBtn->runAction(StartMoveRepeat);

menu = Menu::create(StartBtn,NULL);

menu->setPosition(0,0);

this->addChild(menu,2);

用MenuItemSprite创建的菜单回调函数menu_selector(BackgroundLayer::Start)实现点击后的逻辑

三、平台

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// 对所有平台初始化

for(int i=0;i<3;i++)

{

    stage_sprite[i] = Sprite::create("image/stage1.png");

}

stage_sprite[0]->setScaleX(30);

stage_sprite[0]->setPosition(Vec2(MyWinSize.width/2, stage_sprite[0]->getContentSize().height/4));

// 另两个平台的位置

for(int i = 1;i<3;i++)

{

    stage_sprite[i]->setPosition(Vec2(MyWinSize.width + stage_sprite[i]->getScaleX()*stage_sprite[i]->getContentSize().width, stage_sprite[i]->getContentSize().height/2));

}

 

for(int i = 0;i<3;i++)

{

    this->addChild(stage_sprite[i],3);

}

四、英雄

1

2

3

4

5

//添加英雄

My_Player.init();

My_Player.SetPosition(Vec2(MyWinSize.width/2,stage_sprite[0]->getContentSize().height/4*3));

this->addChild(My_Player.getSprite(),5);

My_Player.Stay();

英雄单独用一个类Player来实现动画和动作,在下一节讲解

 

英雄主角

英雄用一个单独的类Player来实现

一、加载动画

英雄的动画是做成anim1.plist,在WelcomeScene中已经加入到缓存

1

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("image/anim1/anim1.plist");

初始化将停留和行走的动画加到容器中待用

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

_player = Sprite::createWithSpriteFrameName("stay1.png");

_player->setAnchorPoint(Vec2(0.5,0));

//1

Vector<SpriteFrame*> frameVector;

for(int i = 1;i<=5;i++)

{

    char pngName[260] = {0};

    sprintf(pngName, "stay%d.png",i);

    frameVector.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName(pngName));

}

StayAnimation = Animation::createWithSpriteFrames(frameVector, 0.1f);

StayAnimation->setRestoreOriginalFrame(false);

StayAnimation->setLoops(-1);//无限循环

StayAnimate = Animate::create(StayAnimation);

animVector.pushBack(StayAnimate);//将动画装进容器

//2

frameVector.clear();

for(int i = 1;i<=5;i++)

{

    char pngName[260] = {0};

    sprintf(pngName, "walk%d.png",i);

    frameVector.pushBack(SpriteFrameCache::getInstance()->getSpriteFrameByName(pngName));

}

WalkAnimation = Animation::createWithSpriteFrames(frameVector, 1.0f);

WalkAnimation->setRestoreOriginalFrame(false);

WalkAnimation->setLoops(-1);//无限循环

WalkAnimate = Animate::create(WalkAnimation);

animVector.pushBack(WalkAnimate);//将动画装进容器

二、实现方法

英雄主要有停留状态动画、行走动画、移动、停止动画

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

void Player::Stay()

{

    auto animate = animVector.at(0);

    _player->runAction(animate);

}

void Player::Stop()

{

    _player->stopAllActions();

}

void Player::Walk()

{

    auto animate = animVector.at(1);

    _player->runAction(animate);

}

void Player::Start(Vec2 _dec)

{

    MoveTo* move = MoveTo::create(0.2f, _dec);

    _player->runAction(move);

}

 

游戏逻辑

一、开始游戏

在欢迎界面点击开始按钮后,进入游戏状态,平台和主角会移动到指定位置

1

2

3

4

5

6

7

8

9

10

11

12

13

14

void BackgroundLayer::Start(Ref* pSender)

{

    log("1\start");

    //移除按钮、标题

    this->removeChild(menu);

    this->removeChild(GameName);

    MoveTo* stageMove1 = MoveTo::create(0.2,Vec2(STAGE_SCALE,stage_sprite[0]->getContentSize().height/2));

    MoveTo* playerMove = MoveTo::create(0.2,Vec2(STAGE_SCALE+stage_sprite[NowStage]->getContentSize().width*stage_sprite[NowStage]->getScaleX()/2 - My_Player.getSprite()->getContentSize().width/2 - 5,stage_sprite[0]->getContentSize().height));

    stage_sprite[0]->runAction(stageMove1);

    My_Player.getSprite()->runAction(playerMove);

    isStart=true;

    initStick();

    addStage();

}

初始化棍子的位置并添加下一个平台

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

void BackgroundLayer::addStage()

{

    log("2\addStage");

    Size MyWinSize = Director::getInstance()->getVisibleSize();

    stage_sprite[stage_number]->setScaleX(10+CCRANDOM_0_1()*40);

    stage_sprite[stage_number]->setPosition(Vec2(MyWinSize.width + stage_sprite[stage_number]->getScaleX()*stage_sprite[stage_number]->getContentSize().width, stage_sprite[stage_number]->getContentSize().height/2));

    MoveTo* stageMove = MoveTo::create(0.2, Vec2(MyWinSize.width/2 + CCRANDOM_0_1()*MyWinSize.width/3, stage_sprite[stage_number]->getContentSize().height/2));

    stage_sprite[stage_number]->runAction(stageMove);

    log("stage_number=%d",stage_number);

    if(stage_number+1<=2)

    {

        stage_number+=1;

    }

    else

    {

        stage_number = 0;

    }

    //NowStage的编号是[0,2]对应stage_number的编号是[1,3]

    NowStage = stage_number  == 0 ? 2:stage_number-1;

    LastStage = NowStage ==0 ? 2:(NowStage-1);

    NextStage = NowStage == 2 ? 0:(NowStage+1);

}

二、游戏中

1、游戏是通过触摸屏幕进行交互的,所以在初始化时添加单点触摸事件

1

2

3

4

5

6

7

8

// 单点触摸事件

touch_listener = EventListenerTouchOneByOne::create();

touch_listener->setSwallowTouches(true);

touch_listener->onTouchBegan = CC_CALLBACK_2(BackgroundLayer::onTouchBegan,this);

touch_listener->onTouchMoved = CC_CALLBACK_2(BackgroundLayer::onTouchMoved,this);

touch_listener->onTouchEnded = CC_CALLBACK_2(BackgroundLayer::onTouchEnded,this);

touch_listener->onTouchCancelled = CC_CALLBACK_2(BackgroundLayer::onTouchCancelled, this);

_eventDispatcher->addEventListenerWithSceneGraphPriority(touch_listener, this);

    触摸开始时,使棍子变长,触摸结束时停止

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

bool BackgroundLayer::onTouchBegan(Touch* pTouch, Event* pEvent)

{

    log("4\onTouchBegan");

    if(isStart){

        addStick();

    }else{

        return false;

    }

    isStart = false;

    return true;

}

void BackgroundLayer::onTouchEnded(Touch* pTouch, Event* pEvent)

{

    log("5\onTouchEnded");

    StopStick();

    RotateStickAndGo();

}

2、棍子变长使用了schedule定时器,触摸开始棍子一直变长直到触摸结束

1

2

3

4

5

6

7

8

9

10

11

void BackgroundLayer::addStick()

{

    log("6\addStick");

    // 棍子设置在平台的右上角那个点上

    stick->setPosition(StickPoint);

    this->schedule(schedule_selector(BackgroundLayer::StickLength));

}

void BackgroundLayer::StickLength(float)

{

    stick->setScaleY(stick->getScaleY()+5);

}

    当结束触摸时,记录下棍子的长度并结束定时器

1

2

3

4

5

6

void BackgroundLayer::StopStick()

{

    // 存储棍子的长度

    TouchLength = stick->getContentSize().height*stick->getScaleY();

    this->unschedule(schedule_selector(BackgroundLayer::StickLength));

}

3、判断是否成功到下一个平台还是掉落失败

只要棍子末端在下个平台之上则进入下个平台,否则游戏结束

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

void BackgroundLayer::RotateStickAndGo()

{

    log("7\RotateStickAndGo");

    // 算出棍子到下个平台的最小距离、最大距离

    DestLengthMin = abs(stage_sprite[LastStage]->getPositionX() - stage_sprite[NowStage]->getPositionX()) - stage_sprite[LastStage]->getContentSize().width*stage_sprite[LastStage]->getScaleX()/2 - stage_sprite[NowStage]->getContentSize().width*stage_sprite[NowStage]->getScaleX()/2;

    DestLengthMax = DestLengthMin + stage_sprite[NowStage]->getContentSize().width*stage_sprite[NowStage]->getScaleX();

 

    CallFunc* MoveToNext = CallFunc::create(CC_CALLBACK_0(BackgroundLayer::PlayerMoveToNextStage, this));

    RotateTo* Ro_Stick = RotateTo::create(0.5, 90); //旋转90度

    Sequence* GOGO = Sequence::create(Ro_Stick,MoveToNext, NULL);

 

    CallFunc* GoCallBack = CallFunc::create(CC_CALLBACK_0(BackgroundLayer::PlayerMove, this));

    Sequence* StickDown = Sequence::create(Ro_Stick,GoCallBack,NULL);

    log("TouchLength=%d,DestLengthMin=%d,DestLengthMax=%d", TouchLength,DestLengthMin,DestLengthMax);

    log("LastStage=%d,NowStage=%d", LastStage,NowStage);

    // 判断计算出的棍子长度是不是在我们最大距离和最小距离之间

    if(TouchLength<DestLengthMin || TouchLength > DestLengthMax)

    {

        stick->runAction(StickDown);

    }

    else if(TouchLength >= DestLengthMin && TouchLength <=DestLengthMax)

    {

        stick->runAction(GOGO);

    }

 

}

    安全到达下个平台,英雄动画变为行走状态移动到下个平台

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

void BackgroundLayer::StageAndPlayerMove()

{

    log("8\StageAndPlayerMove");

    Vec2 dest;

    dest.x = stage_sprite[NowStage]->getPosition().x + stage_sprite[NowStage]->getContentSize().width*stage_sprite[NowStage]->getScaleX()/2 - My_Player.getSprite()->getContentSize().width/2 - 5;

    dest.y = stage_sprite[NowStage]->getContentSize().height;

    float dist = dest.x - My_Player.getSprite()->getPosition().x;

    log("dist=%f", dist);

    MoveTo* playermove = MoveTo::create(dist / MOVE_SPEED, dest);

    My_Player.Stop();

    My_Player.Walk();

    CallFunc* moveCallBack = CallFunc::create(CC_CALLBACK_0(BackgroundLayer::stageMove, this));

    CallFunc* moveCallBack1 = CallFunc::create([&]{isStart = true;});

    CallFunc* moveCallBack2 = CallFunc::create([&]{

        My_Player.Stay();

    });

    Sequence* Move = Sequence::create(playermove,moveCallBack,moveCallBack1,moveCallBack2,NULL);

    My_Player.getSprite()->runAction(Move);

 

}

    如果失败,则执行掉落动作,进入游戏结束界面

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

void BackgroundLayer::PlayerDown()

{

    log("11\PlayerDown");

 

    MoveBy* Down = MoveBy::create(0.1,Vec2(0,-800));

    My_Player.getSprite()->runAction(Down);

    RotateTo* Ro_Stick = RotateTo::create(0.5, 180); //旋转180度

    Sequence* StickDown = Sequence::create(Ro_Stick, NULL);

    stick->runAction(StickDown);

    over = GameOverLayer::create();

    this->addChild(over,8);

 

}

void BackgroundLayer::PlayerMove()

{

    log("12\PlayerMove");

    MoveBy* GO = MoveBy::create((float)TouchLength/MOVE_SPEED,Vec2(TouchLength,0));

    CallFunc* DownCallBack = CallFunc::create(CC_CALLBACK_0(BackgroundLayer::PlayerDown, this));

    Sequence* Goon = Sequence::create(GO,DownCallBack,NULL);

    My_Player.getSprite()->runAction(Goon);

}

 

结束语

本实例开发教程到这里就结束了,代码来源于网上,该实例仅供学习参考!

代码托管在github:https://github.com/smiger/StickHero

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值