标签:c++ cocos2d 设计 fly_bird 物理刚体
这个小的游戏代码可以使我们理解常见的cocos的概念,从场景,精灵,图层,到导演,回调函数,更新函数,再到设置物理世界,设置精灵刚体。不得不说cocos博大精深,不过有个大家一直在意的问题,就是cocos版本更新太快,有些东西不能使用或者使用错误。个人建议去看cocos官网的版本更新信息和去官网论坛提问或者加群讨论,这样更利于大家提高! 上代码!代码大部分都有注释,如有问题可以提问!
游戏由三个场景构成,HelloWorldScene,GameScene,GameOver。
HelloWorldScene是初始场景
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" //#include "Land.h" USING_NS_CC; class HelloWorld : public cocos2d::Layer { void scrollLand(float dt); Sprite* land1; Sprite* land2; public: // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); //virtual void update(float delta); void myupdate(float delta); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuCloseCallback(cocos2d::Ref* pSender); //void scrollLand(float dt); // implement the "static create()" method manually CREATE_FUNC(HelloWorld); }; #endif // __HELLOWORLD_SCENE_H__ #include "HelloWorldScene.h" #include "SceneOne.h" #include"GameScene.h" #include "SimpleAudioEngine.h" USING_NS_CC; using namespace CocosDenshion; Scene* HelloWorld::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); SimpleAudioEngine::getInstance()->preloadEffect("die.mp3"); SimpleAudioEngine::getInstance()->preloadEffect("hit.mp3"); SimpleAudioEngine::getInstance()->preloadEffect("point.mp3"); SimpleAudioEngine::getInstance()->preloadEffect("swooshing.mp3"); SimpleAudioEngine::getInstance()->preloadEffect("wing.mp3"); ///////////////////////////// // 2. add a menu item with "X" image, which is clicked to quit the program // you may modify it. // add a "close" icon to exit the progress. it's an autorelease object ///////////////////////////// // 3. add your codes below... // add a label shows "Hello World" // create and initialize a label auto label = Label::createWithTTF("Start_Scene", "fonts/Marker Felt.ttf", 24); // position the label on the center of the screen label->setPosition(Vec2(origin.x + visibleSize.width/2, origin.y + visibleSize.height - label->getContentSize().height)); // add the label as a child to this layer // this->addChild(label, 1); // add "HelloWorld" splash screen" SpriteFrameCache::getInstance()->addSpriteFramesWithFile("game.plist"); auto background = Sprite::createWithSpriteFrameName("bg.png"); // position the sprite on the center of the screen background->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); // add the sprite as a child to this layer this->addChild(background, 0); auto bird = Sprite::createWithSpriteFrameName("bird1.png"); auto animation = Animation::create(); for (int i = 1; i <= 3; ++i) { char szName[100] = { 0 }; sprintf(szName, "bird%d.png", i); auto _sprite = Sprite::createWithSpriteFrameName(szName); animation->addSpriteFrame(_sprite->getSpriteFrame()); } animation->setDelayPerUnit(1.5f / 14.0f); animation->setRestoreOriginalFrame(true); auto action = Animate::create(animation); auto swing = MoveBy::create( 0.5f,Vec2(0, 10)); bird->runAction(RepeatForever::create(action)); bird->runAction(RepeatForever::create(Sequence::create(swing,swing->reverse(),NULL))); bird->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); this->addChild(bird, 10); auto flappybird = Sprite::createWithSpriteFrameName("bird_logo.png"); flappybird->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y+3*flappybird->getContentSize().height)); this->addChild(flappybird, 100); /*auto land1 = Sprite::createWithSpriteFrameName("land.png"); land1->setPosition(Vec2(visibleSize.width / 2 + origin.x,visibleSize.height/2-background->getPositionY()+land1->getContentSize().height)); this->addChild(land1, 100); auto land1move = MoveBy::create(3.0f, Vect(land1->getContentSize().width, 0)); auto land2 = Sprite::createWithSpriteFrameName("land.png"); land2->setPosition(Vec2(visibleSize.width / 2 + origin.x-land1->getContentSize().width, visibleSize.height / 2 - background->getPositionY() + land1->getContentSize().height)); this->addChild(land2, 100); auto land2move = MoveBy::create(3.0f, Vect(land2->getContentSize().width, 0)); land1->runAction(land1move); land2->runAction(land2move);*/ land1 = Sprite::createWithSpriteFrameName("land.png"); land1->setAnchorPoint(Point::ZERO); land1->setPosition(Point::ZERO); this->addChild(land1, 10); //置于最顶层 land2 = Sprite::createWithSpriteFrameName("land.png"); land2->setAnchorPoint(Point::ZERO); land2->setPosition(Point::ZERO); this->addChild(land2, 10); //this->schedule(schedule_selector(HelloWorld::scrollLand), 0.01f); //land = Land::create(); //land->setPosition(Vec2(visibleSize.width, visibleSize.height)); //this->addChild(land, 100); auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png"); auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png"); auto closeItem = MenuItemSprite::create( start_bt, pressed_bt, CC_CALLBACK_1(HelloWorld::menuCloseCallback, this)); closeItem->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 - background->getPositionY() +3* closeItem->getContentSize().height)); // create menu, it's an autorelease object auto menu = Menu::create(closeItem, NULL); menu->setPosition(Vec2::ZERO); this->addChild(menu, 101); //this->scheduleUpdate();//使用update()函数来更新 this->schedule(schedule_selector(HelloWorld::myupdate));//使用自定义函数来更新 return true; } void HelloWorld::menuCloseCallback(Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert"); return; #endif auto scene = GameScene::createScene(); auto transition = TransitionFade::create(1, scene); // run Director::getInstance()->replaceScene(transition); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } /*void HelloWorld::scrollLand(float dt) { this->land1->setPositionX(this->land1->getPositionX() - 2.0f); this->land2->setPositionX(this->land1->getPositionX() + this->land1->getContentSize().width - 2.0f); if (this->land2->getPositionX() == 0) { this->land1->setPositionX(0); } } void HelloWorld::update(float delta) { int posLand1 = land1->getPositionX(); int posLand2 = land2->getPositionX(); int speed = 1; posLand1 -= speed; posLand2 -= speed; auto landsize = land2->getContentSize(); if (posLand1 < -landsize.width / 2+142) { posLand2 = landsize.width / 2; posLand1 = landsize.width + landsize.width / 2; } if (posLand2 < -landsize.width / 2+142) { posLand1 = landsize.width / 2; posLand2 = landsize.width + landsize.width / 2; } land1->setPositionX(posLand1); land2->setPositionX(posLand2); }*/ void HelloWorld::myupdate(float delta) { int posLand1 = land1->getPositionX(); int posLand2 = land2->getPositionX(); int speed = 1; posLand1 -= speed; posLand2 -= speed; auto landsize = land2->getContentSize(); if (posLand1 < -landsize.width / 2 + 142) { posLand2 = 0; posLand1 = landsize.width + 0; } if (posLand2 < -landsize.width / 2 + 142) { posLand1 = 0; posLand2 = landsize.width + 0; } land1->setPositionX(posLand1); land2->setPositionX(posLand2); }
#pragma once #include "cocos2d.h" //一些全局常量 const int BIRD_RADIUS = 15; //小鸟半径 const int PIPE_HEIGHT = 320;//半根管道长度 const int PIPE_WIDTH = 52; //管道宽度 const int PIPE_SPACE = 100; //上下管之间的缝隙 const int PIPE_INTERVAL = 170;//横向两根管子之间的间距,288/2+52/2 const int WAIT_DISTANCE = 380;//等待距离 enum GAME_STATUS //游戏状态,准备,开始,结束 { GAME_READY, GAME_START, GAME_OVER }; class GameScene :public cocos2d::Layer { public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(GameScene); void update(float dt); void scrollLand(float dt); void setPhysicWorld(cocos2d::PhysicsWorld *world); virtual bool onContactBegin(const cocos2d::PhysicsContact& contact); virtual bool onTouchBegan(cocos2d::Touch *touch, cocos2d::Event *event); virtual void onTouchEnded(cocos2d::Touch *touch, cocos2d::Event *event); void createPipes(); int getRandomHeight(); void gameStart(); void gameOver(); void gameRetart(Ref *sender); void gamePanelAppear(); private: cocos2d::Sprite *birdSprite; //小鸟 cocos2d::RepeatForever *swingAction; //小鸟的晃动动画 cocos2d::LabelTTF *scoreLabel; //计分 cocos2d::Sprite *land1, *land2; //地板 cocos2d::Vector<cocos2d::Node*> pipes; //管道,用容器装起来 cocos2d::PhysicsWorld *m_physicWorld; //游戏层物理世界 GAME_STATUS gameStatus; //游戏状态变量 int score, bestScore; //游戏当前分数和最好分数 int touchX; //触摸点横坐标 }; #include "GameScene.h" #include "SimpleAudioEngine.h" #include "HelloWorldScene.h" #include "GameOver.h" USING_NS_CC; using namespace CocosDenshion; Scene* GameScene::createScene() { //创建游戏场景 auto gameScene = Scene::createWithPhysics(); //用物理世界初始化场景 gameScene->getPhysicsWorld()->setGravity(Vec2(0, -700)); //设置重力场,重力加速度可以根据手感改小点 //添加主游戏层 auto gameLayer = GameScene::create(); gameLayer->setPhysicWorld(gameScene->getPhysicsWorld()); //绑定物理世界 gameScene->addChild(gameLayer); return gameScene; } bool GameScene::init() { if (!Layer::init()) return false; Size visibleSize = Director::getInstance()->getVisibleSize(); Point visibleOrigin = Director::getInstance()->getVisibleOrigin(); //初始化游戏状态 gameStatus = GAME_READY; score = 0; //添加游戏背景 Sprite *backGround = Sprite::createWithSpriteFrameName("bg.png"); backGround->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2); this->addChild(backGround); //logo auto gameLogo = Sprite::createWithSpriteFrameName("bird_logo.png"); gameLogo->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2 + 100); gameLogo->setName("logo"); this->addChild(gameLogo); //添加管子 createPipes(); //小鸟 birdSprite = Sprite::create(); birdSprite->setPosition(visibleOrigin.x + visibleSize.width / 3, visibleOrigin.y + visibleSize.height / 2); this->addChild(birdSprite); auto birdAnimation = Animation::create(); birdAnimation->setDelayPerUnit(0.2f); birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird1.png")); birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird2.png")); birdAnimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("bird3.png")); auto birdAnim = Animate::create( birdAnimation); birdSprite->runAction(RepeatForever::create(birdAnim)); //挥翅动画 auto up = MoveBy::create(0.4f, Point(0, 8)); auto upBack = up->reverse(); if (gameStatus == GAME_READY) { swingAction = RepeatForever::create(Sequence::create(up, upBack, NULL)); birdSprite->runAction(swingAction); //上下晃动动画 } //小鸟绑定刚体 auto birdBody = PhysicsBody::createCircle(BIRD_RADIUS); //将小鸟当成一个圆,懒得弄精确的轮廓线了 birdBody->setDynamic(true); //设置为可以被物理场所作用而动作 birdBody->setContactTestBitmask(1); //必须设置这项为1才能检测到不同的物体碰撞 birdBody->setGravityEnable(false); //设置是否被重力影响,准备画面中不受重力影响 birdSprite->setPhysicsBody(birdBody); //为小鸟设置刚体 //添加两个land land1 = Sprite::createWithSpriteFrameName("land.png"); land1->setAnchorPoint(Point::ZERO); land1->setPosition(Point::ZERO); this->addChild(land1, 10); //置于最顶层 land2 = Sprite::createWithSpriteFrameName("land.png"); land2->setAnchorPoint(Point::ZERO); land2->setPosition(Point::ZERO); this->addChild(land2, 10); //设置地板刚体 Node *groundNode = Node::create(); auto groundBody = PhysicsBody::createBox(Size(visibleSize.width, land1->getContentSize().height)); groundBody->setDynamic(false); groundBody->setContactTestBitmask(1); groundNode->setAnchorPoint(Vec2::ANCHOR_MIDDLE); //物理引擎中的刚体只允许结点锚点设置为中心 groundNode->setPhysicsBody(groundBody); groundNode->setPosition(visibleOrigin.x + visibleSize.width / 2, land1->getContentSize().height / 2); this->addChild(groundNode); //设置界面顶部刚体 Node * UpgroundNode = Node::create(); auto UpgroudBody = PhysicsBody::createBox(Size(visibleSize.width, 1)); UpgroudBody->setDynamic(false); UpgroudBody->setCategoryBitmask(1); UpgroundNode->setAnchorPoint(Vec2::ANCHOR_MIDDLE); UpgroundNode->setPhysicsBody(UpgroudBody); UpgroundNode->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleSize.height+0.5f); this->addChild(UpgroundNode); //记分牌,在最外层,这里懒得弄图片文字了^_^ scoreLabel = LabelTTF::create("0", "Felt", 35); scoreLabel->setPosition(visibleOrigin.x + visibleSize.width / 2, visibleOrigin.y + visibleSize.height / 2 + 200); scoreLabel->setVisible(false); //一开始隐藏 this->addChild(scoreLabel); //添加碰撞监测 auto contactListener = EventListenerPhysicsContact::create(); contactListener->onContactBegin = CC_CALLBACK_1(GameScene::onContactBegin, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(contactListener, this); //添加触摸监听 auto touchListener = EventListenerTouchOneByOne::create(); touchListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this); touchListener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this); _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this); return true; } //设置层的物理世界 void GameScene::setPhysicWorld(PhysicsWorld *world) { m_physicWorld = world; } //游戏开始 void GameScene::gameStart() { gameStatus = GAME_START; score = 0;//重置分数 scoreLabel->setString(String::createWithFormat("%d", score)->getCString()); this->getChildByName("logo")->setVisible(false); //logo消失 scoreLabel->setVisible(true); //计分开始 this->scheduleUpdate();//启动默认更新 this->schedule(schedule_selector(GameScene::scrollLand), 0.01f); //启动管子和地板滚动 birdSprite->stopAction(swingAction); //游戏开始后停止上下浮动 birdSprite->getPhysicsBody()->setGravityEnable(true); //开始受重力作用 } //游戏结束 void GameScene::gameOver() { gameStatus = GAME_OVER; //获取历史数据 bestScore = UserDefault::getInstance()->getIntegerForKey("BEST"); if (score > bestScore) { bestScore = score; //更新最好分数 UserDefault::getInstance()->setIntegerForKey("BEST", bestScore); } SimpleAudioEngine::getInstance()->playEffect("hit.mp3"); //游戏结束后停止地板和管道的滚动 this->unschedule(schedule_selector(GameScene::scrollLand)); } //碰撞监测 bool GameScene::onContactBegin(const PhysicsContact& contact) { if (gameStatus == GAME_OVER) //当游戏结束后不再监控碰撞 return false; gameOver();//如果游戏状态不是GAMEOVER就调用gameOver函数来设置碰撞后游戏结束的信息 return true; } //触摸监听 bool GameScene::onTouchBegan(Touch *touch, Event *event) { switch (gameStatus) { case GAME_OVER: break; case GAME_READY: { gameStart(); birdSprite->getPhysicsBody()->setVelocity(Vec2(0, 100)); //给一个向上的初速度 SimpleAudioEngine::getInstance()->playEffect("wing.mp3"); //这里也要写,不然touchx的值是未知值,负无穷,导致bug touchX = touch->getLocation().x; } break; case GAME_START: { auto curVelocity = birdSprite->getPhysicsBody()->getVelocity(); birdSprite->getPhysicsBody()->setVelocity(Vec2(0, 100 > (curVelocity.y + 500) ? (curVelocity.y + 500) : 100)); //向上的速度受下降影响 SimpleAudioEngine::getInstance()->playEffect("wing.mp3"); //开上帝视角,留个后门,嘿嘿 touchX = touch->getLocation().x; } break; default: break; } return true; } void GameScene::onTouchEnded(Touch *touch, Event *event) { //当触摸点滑动超过100,分数瞬间涨100 if (touch->getLocation().x - touchX > 100) { score += 100; scoreLabel->setString(String::createWithFormat("%d", score)->getCString()); SimpleAudioEngine::getInstance()->playEffect("point.mp3"); } } //地板滚动自定义计时器回调 void GameScene::scrollLand(float dt) { Size visibleSize = Director::getInstance()->getVisibleSize(); //两个图片循环移动 land1->setPositionX(land1->getPositionX() - 1.0f); land2->setPositionX(land1->getPositionX() + land1->getContentSize().width - 2.0f); if (land2->getPositionX() <= 0) land1->setPosition(Point::ZERO); //管子滚动 for (auto &singlePipe : pipes) { singlePipe->setPositionX(singlePipe->getPositionX() - 1.0f);//每次向左移动一个单位 if (singlePipe->getPositionX() < -PIPE_WIDTH / 2)//如果管子完全移除了界面 { singlePipe->setPositionX(visibleSize.width + PIPE_WIDTH / 2);//设置管子从界面右侧进入 singlePipe->setPositionY(getRandomHeight());//Y的位置设置为随机值 singlePipe->setName("newPipe"); //每次重设一根管子,标为new } } } //获取随机高度,用于管道 int GameScene::getRandomHeight() { auto size = Director::getInstance()->getVisibleSize(); //使得单根管子纵向坐标在屏幕中心点-(40~270)中间随机波动,这个是自己试出来的 return size.height / 2 - 40 - CCRANDOM_0_1() * (270 - 40); } //创建管道 void GameScene::createPipes() { //同屏幕出现的只有两根管子,放到容器里面,上下绑定为一根 for (int i = 0; i < 2; i++) { auto visibleSize = Director::getInstance()->getVisibleSize(); Sprite *pipeUp = Sprite::createWithSpriteFrameName("pipe_up.png"); Sprite *pipeDown = Sprite::createWithSpriteFrameName("pipe_down.png"); Node *singlePipe = Node::create(); //给上管绑定刚体 auto pipeUpBody = PhysicsBody::createBox(pipeUp->getContentSize()); pipeUpBody->setDynamic(false); pipeUpBody->setContactTestBitmask(1); pipeUp->setAnchorPoint(Vec2::ANCHOR_MIDDLE); pipeUp->setPhysicsBody(pipeUpBody); //给两个管子分开设置刚体,可以留出中间的空隙使得小鸟通过 //给下管绑定刚体 auto pipeDownBody = PhysicsBody::createBox(pipeDown->getContentSize()); pipeDownBody->setDynamic(false); pipeDownBody->setContactTestBitmask(1); pipeDown->setAnchorPoint(Vec2::ANCHOR_MIDDLE); pipeDown->setPhysicsBody(pipeDownBody); pipeUp->setPosition(0, PIPE_HEIGHT + PIPE_SPACE);//上面管子设置在Y为管子的高度和管子空隙高度之和(相对于父节点,也就是singlePipe) singlePipe->addChild(pipeUp); //下面管子pipeDown没有设置位置,就是设置在默认位置(0,0) singlePipe->addChild(pipeDown); //pipeDown默认加到(0,0),上下合并,此时singlePipe以下面的管子中心为锚点,此时singlePipe由两个管子组合而成 singlePipe->setPosition(i*PIPE_INTERVAL + WAIT_DISTANCE, getRandomHeight()); //设置初始位置,X方向为等待距离和管子间隔之和,Y设置为随机位置 singlePipe->setName("newPipe"); this->addChild(singlePipe); //把两个管子都加入到层 pipes.pushBack(singlePipe); //两个管子先后添加到容器 } } //默认的更新函数 void GameScene::update(float dt) { //当游戏开始时,判断得分,这个其实也可以写在其他地方,比如管子滚动的更新函数里面或者触摸监测里面 if (gameStatus == GAME_START) { for (auto &pipe : pipes) { if (pipe->getName() == "newPipe") //新来一根管子就判断 { if (pipe->getPositionX() < birdSprite->getPositionX()) { score++; scoreLabel->setString(String::createWithFormat("%d", score)->getCString()); SimpleAudioEngine::getInstance()->playEffect("point.mp3"); pipe->setName("passed"); //标记已经过掉的管子 } } } } //小鸟的旋转 auto curVelocity = birdSprite->getPhysicsBody()->getVelocity(); birdSprite->setRotation(-curVelocity.y*0.1 - 20); //根据竖直方向的速度算出旋转角度,逆时针为负 auto visibleSize = Director::getInstance()->getVisibleSize(); if (birdSprite->getPositionY() <= land1->getContentSize().height + BIRD_RADIUS ) { birdSprite->stopAllActions(); //小鸟挂了就不能再扇翅了 birdSprite->setRotation(70); //设置为嘴朝下,顺时针70度旋转 birdSprite->getPhysicsBody()->setDynamic(false); //设置为不动了 SimpleAudioEngine::getInstance()->playEffect("die.mp3"); this->unscheduleUpdate(); //在小鸟掉到地面上再停止默认更新 gamePanelAppear(); //弹出记分牌 } } //加入记分板和重玩菜单 void GameScene::gamePanelAppear() { Size size = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); //用node将gameoverlogo和记分板绑在一起 Node *gameOverPanelNode = Node::create(); auto gameOverLabel = Sprite::createWithSpriteFrameName("gameover.png"); gameOverPanelNode->addChild(gameOverLabel); auto panel = Sprite::createWithSpriteFrameName("board.PNG");//注意这里是大写PNG,原图片用什么后缀这里就用什么,区分大小写 gameOverLabel->setPositionY(panel->getContentSize().height); //设置一下坐标 gameOverPanelNode->addChild(panel); //记分板上添加两个分数 auto curScoreTTF = LabelTTF::create(String::createWithFormat("%d", score)->getCString(), "Arial", 20); curScoreTTF->setPosition(panel->getContentSize().width - 40, panel->getContentSize().height - 45); curScoreTTF->setColor(Color3B(255, 0, 0)); panel->addChild(curScoreTTF); auto bestScoreTTF = LabelTTF::create(String::createWithFormat("%d", bestScore)->getCString(), "Arial", 20); bestScoreTTF->setPosition(panel->getContentSize().width - 40, panel->getContentSize().height - 90); bestScoreTTF->setColor(Color3B(0, 255, 0)); panel->addChild(bestScoreTTF); this->addChild(gameOverPanelNode); gameOverPanelNode->setPosition(origin.x + size.width / 2, origin.y + size.height); //滑入动画 gameOverPanelNode->runAction(MoveTo::create(0.5f, Vec2(origin.x + size.width / 2, origin.y + size.height / 2))); SimpleAudioEngine::getInstance()->playEffect("swooshing.mp3"); //添加菜单 auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png"); auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png"); auto restartItem = MenuItemSprite::create(start_bt, pressed_bt,NULL,this, menu_selector(GameScene::gameRetart));//调用重新开启游戏函数 restartItem->setPosition(Vec2(size.width / 2 + origin.x, size.height / 2 - 1.5* restartItem->getContentSize().height)); auto menu = CCMenu::createWithItem(restartItem); menu->setPosition(Vec2::ZERO); this->addChild(menu,10); } //游戏重新开始 void GameScene::gameRetart(Ref *sender) { //重新回到初始画面 auto gameScene = GameOver::createScene();//切换到GameOver场景 Director::getInstance()->replaceScene(gameScene); }
#ifndef __GAMEOVER_H__ #define __GAMEOVER_H__ //#include "Box2D/Box2D.h" #include "cocos2d.h" USING_NS_CC; class GameOver : public cocos2d::Layer { void scrollLand(float dt); Sprite *land1; Sprite *land2; //b2World *world; public: // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); virtual void update(float delta); void myupdate(float delta); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuReStartCallback(cocos2d::Ref* pSender); void menuGameOverCallback(cocos2d::Ref* pSender); //void scrollLand(float dt); // implement the "static create()" method manually CREATE_FUNC(GameOver); }; #endif // __HELLOWORLD_SCENE_H__ #include "HelloWorldScene.h" #include "SceneOne.h" #include "GameOver.h" #include "GameScene.h" USING_NS_CC; Scene* GameOver::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = GameOver::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } bool GameOver::init() { if (!Layer::init()) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); auto label = Label::createWithTTF("GameOver_Scene", "fonts/Marker Felt.ttf", 24); label->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height - label->getContentSize().height)); //this->addChild(label); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("game.plist");//使用plist文件来加载精灵帧 auto background = Sprite::createWithSpriteFrameName("bg.png");//使用精灵帧名字来初始化背景 background->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 + origin.y)); this->addChild(background, 0); auto gameoverSprite = Sprite::createWithSpriteFrameName("gameover.png");//设置gameover图标 gameoverSprite->setPosition(Vec2(visibleSize.width/2,2*visibleSize.height/3)); this->addChild(gameoverSprite, 1); auto start_bt = Sprite::createWithSpriteFrameName("start_btn.png");//初始化两个按钮精灵 auto pressed_bt = Sprite::createWithSpriteFrameName("start_btn_pressed.png"); //设置菜单精灵,并调用重启游戏回调函数 auto reStartItem = MenuItemSprite::create( start_bt, pressed_bt, CC_CALLBACK_1(GameOver::menuReStartCallback, this)); reStartItem->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 - background->getPositionY() + 3 * reStartItem->getContentSize().height)); auto menu = Menu::create(reStartItem, NULL);//使用菜单精灵创建菜单 menu->setPosition(Vec2::ZERO); this->addChild(menu, 101); auto GameOverlabel = Label::createWithTTF("EXIT", "fonts/arial.ttf", 24);//设置退出菜单,调用退出游戏回掉函数 auto gameOverItem = MenuItemLabel::create(GameOverlabel,CC_CALLBACK_1(GameOver::menuGameOverCallback,this)); gameOverItem->setPosition(Vec2(visibleSize.width / 2 + origin.x, visibleSize.height / 2 - background->getPositionY() + 4 * gameOverItem->getContentSize().height)); auto gameovermenu = Menu::create(gameOverItem, NULL); gameovermenu->setPosition(Vec2::ZERO); this->addChild(gameovermenu, 101); return true; } void GameOver::menuReStartCallback(Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.", "Alert"); return; #endif auto scene = GameScene::createScene();//初始化游戏场景 auto transition = TransitionFade::create(1, scene); // run Director::getInstance()->replaceScene(transition); #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } void GameOver::menuGameOverCallback(cocos2d::Ref* pSender) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.", "Alert"); return; #endif Director::getInstance()->end();//直接退出 #if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) exit(0); #endif } void GameOver::scrollLand(float dt) { this->land1->setPositionX(this->land1->getPositionX() - 2.0f); this->land2->setPositionX(this->land1->getPositionX() + this->land1->getContentSize().width - 2.0f); if (this->land2->getPositionX() == 0) { this->land1->setPositionX(0); } } void GameOver::update(float delta) { int posLand1 = land1->getPositionX(); int posLand2 = land2->getPositionX(); int speed = 1; posLand1 -= speed; posLand2 -= speed; auto landsize = land2->getContentSize(); if (posLand1 < -landsize.width / 2 + 142) { posLand2 = landsize.width / 2; posLand1 = landsize.width + landsize.width / 2; } if (posLand2 < -landsize.width / 2 + 142) { posLand1 = landsize.width / 2; posLand2 = landsize.width + landsize.width / 2; } land1->setPositionX(posLand1); land2->setPositionX(posLand2); } void GameOver::myupdate(float delta) { int posLand1 = land1->getPositionX(); int posLand2 = land2->getPositionX(); int speed = 1; posLand1 -= speed; posLand2 -= speed; auto landsize = land2->getContentSize(); if (posLand1 < -landsize.width / 2 + 142) { posLand2 = landsize.width / 2; posLand1 = landsize.width + landsize.width / 2; } if (posLand2 < -landsize.width / 2 + 142) { posLand1 = landsize.width / 2; posLand2 = landsize.width + landsize.width / 2; } land1->setPositionX(posLand1); land2->setPositionX(posLand2); }
虽然本文很多地方就是使用上文的方法,但是还是要很感谢上文博主,让我学到不少!
源码和APK下次再传!
Cocos2d-x3.5 设计Fly_bird(飞行的小鸟)并打包成APK文件
标签:c++ cocos2d 设计 fly_bird 物理刚体
原文地址:http://blog.csdn.net/shiwazone/article/details/46486015