Cocos2d-x学习(十一):用cocos2d-x实现MoonWarriors(游戏场景切换和主菜单实现)

特别声明:本文所有图片资源来源于MoonWarriors cocos2d-html 开源项目


在cocos2d-html alpha版推出不久,就有一位大神写了一款飞行射击类游戏,MoonWarrior,MoonWarrior cocos2d-html github地址,是用js写的,代码写的很清晰,虽然不是很懂js,但是都是基于cocos2d架构的,所以还是可以看的懂的,加上最近有看了两本cocos2d的书(《iphone & ipad cocos2d 游戏开发实战》和《Learning Coocs2d》),决定用cocos2d-x重写一遍这个游戏demo,并加入一些从以上两本书中学到的知识以及自己的认识!


1.游戏管理器

在《Learning Cocos2d》这本书中提到了GameManager游戏管理器这个概念,设计模式采用的是单例,其重要用途是管理游戏中的一些全局的属性和操作,比如背景音乐,音效的播放,场景的切换,游戏的设置等等,这种单例设计模式的管理器的好处很多,所以我也在我的项目中加入了这一设计,今天先简单总结一下关于场景切换的实现,GameManager类的定义如下:

[cpp]  view plain copy
  1. <span style="font-size:16px;">class GameManager  
  2. {  
  3.   
  4. private:  
  5.     GameManager();  
  6.     // 初始化数据  
  7.     void init();  
  8.       
  9. public:  
  10.     ~GameManager();  
  11.       
  12. public:  
  13.     static GameManager* sharedGameManager();  
  14.       
  15. public:  
  16.     // 跳转场景  
  17.     void runSceneWithID(SCENE_ID pSceneID);  
  18.       
  19.     // 当前场景  
  20.     CC_SYNTHESIZE_READONLY(SCENE_ID, mCurrentScene, CurrentScene);  
  21.       
  22. };</span>  
切换场景的方法
[cpp]  view plain copy
  1. <span style="font-size:16px;">void GameManager::runSceneWithID(SCENE_ID pSceneID)  
  2. {  
  3.     SCENE_ID oldSceneID = mCurrentScene;  
  4.     mCurrentScene = pSceneID;  
  5.       
  6.     CCScene *sceneToRun = NULL;  
  7.       
  8.     switch (mCurrentScene) {  
  9.         case SCENE_ID_MAINMENU:  
  10.             sceneToRun = MainMenuScene::node();  
  11.             break;  
  12.               
  13.         case SCENE_ID_GAMEPLAY:  
  14.             sceneToRun = GamePlayScene::node();  
  15.             break;  
  16.               
  17.         case SCENE_ID_SETTING:  
  18.             sceneToRun = SettingScene::node();  
  19.             break;  
  20.               
  21.         case SCENE_ID_ABOUT:  
  22.             sceneToRun = AboutScene::node();  
  23.             break;  
  24.               
  25.         default:  
  26.             // 异常  
  27.             CCAssert(0, "Unknown Scene ID");  
  28.             break;  
  29.     }  
  30.       
  31.     if (!sceneToRun) {  
  32.         mCurrentScene = oldSceneID;  
  33.         return;  
  34.     }  
  35.       
  36.     // 判断是否是第一次载入场景  
  37.     if (!CCDirector::sharedDirector()->getRunningScene()) {  
  38.         CCDirector::sharedDirector()->runWithScene(sceneToRun);  
  39.     }  
  40.     else {  
  41.         CCDirector::sharedDirector()->replaceScene(sceneToRun);  
  42.     }  
  43. }</span>  
首先定义一个区分不同场景的枚举ID

[cpp]  view plain copy
  1. <span style="font-size:16px;">// Scene ID  
  2. typedef enum   
  3. {  
  4.     //   
  5.     SCENE_ID_NONE       = -1,  
  6.     // 主菜单场景  
  7.     SCENE_ID_MAINMENU   = 0,  
  8.     // 游戏场景  
  9.     SCENE_ID_GAMEPLAY   = 1,  
  10.     // 游戏设置场景  
  11.     SCENE_ID_SETTING    = 2,  
  12.     // 关于场景  
  13.     SCENE_ID_ABOUT      = 3  
  14. } SCENE_ID;</span>  
然后根据切换场景传入的不同场景ID值,切换到不同的场景

这里需要注意的是,第一次载入场景时需要调用

[cpp]  view plain copy
  1. <span style="font-size:16px;">CCDirector::sharedDirector()->runWithScene(sceneToRun);</span>  
可以通过

[cpp]  view plain copy
  1. <span style="font-size:16px;">CCDirector::sharedDirector()->getRunningScene()</span>  
来判断当前是否有正在运行的场景,如果没有,则是第一次载入了!

这样设计的好处在于不论在程序的哪个地方,只需要一个接口,并且传递要跳转场景的ID值即可,用法如下

[cpp]  view plain copy
  1. <span style="font-size:16px;">GameManager::sharedGameManager()->runSceneWithID(SCENE_ID_MAINMENU);</span>  



2.主菜单的实现

主菜单场景我分为了两层,第一层是背景层,第二层是菜单层,效果如图



(1)背景层

背景层是有底图,Logo和一个移动的飞船组成的

底图和Logo很简单,只是两个图片纹理的精灵而已

为了效果更好,MoonWarriors提供了一个移动的飞船,我也山寨过来了

这里我用到CCImage和CCTexture2D类,我没有像原作那样将飞船的图片资源添加到CCTextureCache中,因为我觉得在其他场景中这个图片资源可能是没有用的,添加到CCTextureCache中是不是没有必要!代码如下:

[cpp]  view plain copy
  1. <span style="font-size:16px;">// 动画飞船  
  2.         // CCImage是由不同平台不同实现的  
  3.         CCImage shipImage;  
  4.         shipImage.initWithImageFile("ship.png");  
  5.         CCTexture2D *shipTexture = new CCTexture2D();  
  6.         shipTexture->initWithImage(&shipImage);  
  7.         CCSprite *shipSprite = CCSprite::spriteWithTexture(shipTexture, CCRectMake(0, 45, 60, 38));  
  8.         shipTexture->release();  
  9.         // 设置在屏幕之外  
  10.         shipSprite->setPosition(ccp(-shipSprite->getContentSize().width, -shipSprite->getContentSize().height));  
  11.         this->addChild(shipSprite);</span>  
飞船移动的动作也很简单

[cpp]  view plain copy
  1. <span style="font-size:16px;">void MainMenuBGLayer::runShipAnim(cocos2d::CCNode *pShip)  
  2. {  
  3.     CCSize winSize = CCDirector::sharedDirector()->getWinSize();  
  4.       
  5.     pShip->setPosition(ccp(CCRANDOM_0_1() * winSize.width, 0));  
  6.     // 从底部移动到顶部,执行回调继续执行移动动作  
  7.     pShip->runAction(CCSequence::actions(CCMoveTo::actionWithDuration(2, ccp(CCRANDOM_0_1() * winSize.width, winSize.height + pShip->getContentSize().height / 2)), CCCallFunc::actionWithTarget(this, callfunc_selector(MainMenuBGLayer::spriteAnimCallback)), NULL));  
  8. }</span>  
这里的位置坐标没什么好纠结的,只是取了一个随机数的宽度而已!


(2)菜单层

菜单项使用的是CCMenuItemSprite,这个通常是用在菜单项选中,未选中已经不可选的状态下显示不同图片的

原作中的菜单图片资源是做在一起的,所以用到了一些坐标,代码如下

[cpp]  view plain copy
  1. <span style="font-size:16px;">// 菜单  
  2.         // 菜单纹理  
  3.         CCImage menuImage;  
  4.         menuImage.initWithImageFile("menu.png");  
  5.         CCTexture2D *menuTexture = new CCTexture2D();  
  6.         menuTexture->initWithImage(&menuImage);  
  7.           
  8.         // 菜单选项  
  9.         CCMenuItemSprite *newGameMenuItem = CCMenuItemSprite::itemFromNormalSprite(CCSprite::spriteWithTexture(menuTexture, CCRectMake(0, 0, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(0, 33, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(0, 33 * 2, 126, 33)), this, menu_selector(MainMenuCtrlLayer::mainMenuCallback));  
  10.         newGameMenuItem->setTag(MAINMENU_ID_NEW_GAME);  
  11.           
  12.         CCMenuItemSprite *settingMenuItem = CCMenuItemSprite::itemFromNormalSprite(CCSprite::spriteWithTexture(menuTexture, CCRectMake(126, 0, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(126, 33, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(126, 33 * 2, 126, 33)), this, menu_selector(MainMenuCtrlLayer::mainMenuCallback));  
  13.         settingMenuItem->setTag(MAINMENU_ID_SETTING);  
  14.           
  15.         CCMenuItemSprite *aboutMenuItem = CCMenuItemSprite::itemFromNormalSprite(CCSprite::spriteWithTexture(menuTexture, CCRectMake(252, 0, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(252, 33, 126, 33)), CCSprite::spriteWithTexture(menuTexture, CCRectMake(252, 33 * 2, 126, 33)), this, menu_selector(MainMenuCtrlLayer::mainMenuCallback));  
  16.         aboutMenuItem->setTag(MAINMENU_ID_ABOUT);  
  17.           
  18.         CCMenu *mainMenu = CCMenu::menuWithItems(newGameMenuItem, settingMenuItem, aboutMenuItem, NULL);  
  19.         mainMenu->alignItemsVerticallyWithPadding(10);  
  20.         mainMenu->setPosition(ccp(winSize.width / 2, winSize.height / 2 - 80));  
  21.         this->addChild(mainMenu);</span>  



项目地址


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
cocos2dx 雷电MoonWarriors_游戏源码 #include "GameLayer.h" #include "SimpleAudioEngine.h" #include "Bullet.h" #include "Resource.h" #include "Config.h" #include "Enemy.h" #include "Effect.h" #include "GameOver.h" #include "PauseLayer.h" using namespace cocos2d; using namespace CocosDenshion; bool isPaused = false; GameLayer::GameLayer():m_state(statePlaying),m_time(0),m_ship(NULL),m_backSky(NULL),m_backSkyHeight(0),m_backSkyRe(NULL),m_backTileMap(NULL),m_backTileMapHeight(0),m_backTileMapRe(NULL),m_isBackSkyReload(false),m_isBackTileReload(false),m_lbScore(NULL),m_lifeCount(NULL), m_tempScore(0) { } GameLayer::~GameLayer() { if (m_levelManager) { delete m_levelManager; } play_bullet->release(); enemy_bullet->release(); enemy_items->release(); } bool GameLayer::init() { if (!CCLayer::init()) { return false; } // 开启触摸 this->setTouchEnabled(true); // 创建数组,需要retain一下 play_bullet = CCArray::create(); play_bullet->retain(); enemy_bullet = CCArray::create(); enemy_bullet->retain(); enemy_items = CCArray::create(); enemy_items->retain(); m_state = statePlaying; Enemy::sharedEnemy(); Effect::sharedExplosion(); Config::sharedConfig()->resetConfig(); winSize = CCDirector::sharedDirector()->getWinSize(); m_levelManager = new LevelManager(this); //初始化背景 initBackground(); m_screenRec = CCRectMake(0, 0, winSize.width, winSize.height + 10); // score m_lbScore = CCLabelBMFont::create("Score:0", s_arial14_fnt); m_lbScore->setAnchorPoint(ccp(1, 0)); m_lbScore->setAlignment(kCCTextAlignmentRight); addChild(m_lbScore, 1000); m_lbScore->setPosition(winSize.width - 5, winSize.height - 30); // ship life CCTexture2D *shipTexture = CCTextureCache::sharedTextureCache()->addImage(s_ship01); CCSprite *life = CCSprite::createWithTexture(shipTexture, CCRectMake(0, 0, 60, 38)); life->setScale(0.6); life->setPosition(ccp(30,winSize.height-23)); addChild(life, 1, 5); // ship life count char lifecount[2]; sprintf(lifecount, "%d",Config::sharedConfig()->getLifeCount()); m_lifeCount = CCLabelTTF::create(lifecount, "Arial", 20); m_lifeCount->setPosition(ccp(60, winSize.height-20)); m_lifeCount->setColor(ccc3(255,0, 0)); addChild(m_lifeCount, 1000); // ship m_ship = Ship::create(); addChild(m_ship, m_ship->getZoder(), 1001); CCMenuItemImage *pause = CCMenuItemImage::create("pause.png", "pause.png", this, menu_selector(GameLayer::doPause)); pause->setAnchorPoint(ccp(1, 0)); pause->setPosition(ccp(winSize.width, 0)); CCMenu *menu = CCMenu::create(pause, NULL); menu->setAnchorPoint(ccp(0, 0)); addChild(menu, 1, 10); menu->setPosition(CCPointZero); // 调 update函数 scheduleUpdate(); // 每秒调一次 scoreCounter函数 schedule(schedule_selector(GameLayer::scoreCounter), 1); if (Config::sharedConfig()->getAudioState()) { SimpleAudioEngine::sharedEngine()->playBackgroundMusic(s_bgMusic, true); } return true; } void GameLayer::update(float dt) { if (m_state == statePlaying) { checkIsCollide(); removeInactiveUnit(dt); checkIsReborn(); updateUI(); } } void GameLayer::scoreCounter() { if (m_state == statePlaying) { m_time++; m_levelManager->loadLevelResource(m_time); } } void GameLayer::checkIsCollide() { CCObject *units; CCObject *bullets; CCObject *enemybs; CCARRAY_FOREACH(enemy_items, units) { UnitSprite *enemy = dynamic_cast<UnitSprite*>(units); CCARRAY_FOREACH(play_bullet, bullets) { UnitSprite *bullet = dynamic_cast<UnitSprite*>(bullets); if (this->collide(enemy, bullet)) { enemy->hurt(); bullet->hurt(); } if (!(m_screenRec.intersectsRect(bullet->boundingBox()))) { bullet->destroy(); } }

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值