Cocos2dx游戏开发系列笔记11:解刨《战神传说》完结篇

两点:

1 感谢 net19880504 同学,在上篇提到:想让骨头继续写《战神传说》的解刨篇,因为有人在关注而开心。

2 感谢 kanhai 同学,骨头加的哲哲链接虽然是AD性质,但不像一般的AD那样影响阅读,而且骨头也很喜欢这些可爱的介绍,谢谢理解


今晚继续:解刨《战神传说》完结篇


上篇骨头学习了开始菜单和动画,接下来看看其他的类:

———————————————————————————————————————————————— 

设置类 Options.cpp:

先贴背景图

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CCSprite *sp = CCSprite::create(s_loading);  
  2.   sp->setAnchorPoint(CCPointZero);  
  3.   addChild(sp, 0, 1);  

出现了一个新的控件,开关控件 CCMenuItemToggle:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CCMenuItemToggle *toggle = CCMenuItemToggle::createWithTarget(this, menu_selector(Options::setOptions), CCMenuItemFont::create("On"),CCMenuItemFont::create("Off"), NULL);  
  2.   
  3. int selectId = Config::sharedConfig()->getAudioState()? 0 : 1;  
  4. toggle->setSelectedIndex(selectId);  

在setOptions方法里处理声音开关,全局的背景音乐和音效控制方法:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Options::setOptions(CCObject* pSender)  
  2. {  
  3.     bool tmpSound = Config::sharedConfig()->getAudioState();  
  4.     Config::sharedConfig()->updateAudioState(!tmpSound);  
  5.       
  6.     if (Config::sharedConfig()->getAudioState()) {  
  7.         SimpleAudioEngine::sharedEngine()->resumeAllEffects();  
  8.         SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();  
  9.     }else{  
  10.         SimpleAudioEngine::sharedEngine()->pauseAllEffects();  
  11.         SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();  
  12.     }  
  13. }  
还有用指定字体生成label的方法:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CCLabelBMFont *backLb = CCLabelBMFont::create("Go Back", s_font);  
  2. CCMenuItemLabel *goBack = CCMenuItemLabel::create(backLb, this, menu_selector(About::goBack));  
Goback 一直在闪,是通过 一个CCRepeatForever的action来实现的,即一直重复模式
 
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. goBack->runAction(CCRepeatForever::create((CCActionInterval*)seq));  

————————————————————————————————————————————————

关于页面 About.cpp

这个页面很简单,只有一个长文本需要注意一下:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CCLabelTTF *about = CCLabelTTF::create("   I recode ....ginal. \n     ... ""Arial", 18, CCSizeMake(winSize.width * 0.85, 320), kCCTextAlignmentLeft);  
  2. about = CCLabelTTF::create("   I recode thistion""Arial", 18, CCSizeMake(winSize.width * 0.85, 320), kCCTextAlignmentLeft);  
  3.  about->setPosition(ccp(winSize.width / 2, winSize.height / 2 - 20));  
  4.  about->setAnchorPoint(ccp(0.5, 0.5));  
  5.  addChild(about);  
1 文本中 \n 是有效的

2 长文本区域 CCSizeMake(winSize.width * 0.85, 320) 

3  对其方式 kCCTextAlignmentLeft

————————————————————————————————————————————————

游戏开始:



————————————————————————————————————————————————

主角类:Ship.cpp


Ship.cpp的父类是UnitSprite.cpp,这个父类里只在h文件里声明了一个返回键代理,和四个需要子类实现虚方法。

所有的主角飞机,敌机,子弹,的父类都是它。

这四个虚方法分别是:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. virtual void destroy() = 0;  
  2. virtual void hurt() = 0 ;  
  3. virtual CCRect collideRect() = 0;  
  4. virtual bool isActive() = 0;  

下面是主角飞机的初始化和动画:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // init life  
  2. CCTexture2D * shipTextureCache = CCTextureCache::sharedTextureCache()->addImage(s_ship01);  
  3. CCRect rec = CCRectMake(0, 0, 60, 38);  
  4. this->initWithTexture(shipTextureCache,  rec);  
  5.   
  6. this->setPosition(m_appearPosition);  
  7.   
  8. // set frame  
  9. CCSpriteFrame *frame0 = CCSpriteFrame::createWithTexture(shipTextureCache, CCRectMake(0, 0, 60, 38));  
  10. CCSpriteFrame *frame1 = CCSpriteFrame::createWithTexture(shipTextureCache, CCRectMake(60, 0, 60, 38));  
  11.   
  12. CCArray *animFrames = CCArray::create();  
  13. animFrames->addObject(frame0);  
  14. animFrames->addObject(frame1);  
  15.   
  16. // ship animate  
  17. // 这个方法有差异  
  18. CCAnimation *animation = CCAnimation::createWithSpriteFrames(animFrames, 0.1);  
  19. CCAnimate *animate = CCAnimate::create(animation);  
  20. this->runAction(CCRepeatForever::create(animate));  

根据 shipTextureCache 来创建两帧 CCSpriteFrame 

然后用两帧图片生成 动画,然后播放这个动画,来达到主角飞机一直在闪的效果。

下面这个段代码是幽灵飞机初始化:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // revive effect  
  2. this->m_canBeAttack = false;  
  3. CCSprite *ghostSprite = CCSprite::createWithTexture(shipTextureCache, CCRectMake(0, 45, 60, 38));  
  4. ccBlendFunc cbl = {GL_SRC_ALPHA, GL_ONE};  
  5. ghostSprite->setBlendFunc(cbl);  
  6. ghostSprite->setScale(8);  
  7. ghostSprite->setPosition(ccp(this->getContentSize().width / 2, 12));  
  8. this->addChild(ghostSprite, 3000, 99999);  
  9. ghostSprite->runAction(CCScaleTo::create(0.5, 1, 1));  

何为幽灵飞机呢,就是主角飞机死掉后,一个由大变小的动画,由代码可看出,首先设置为不可攻击,且放大8倍,然后在半秒内回复到正常大小,且可以被攻击。

    ccBlendFunc cbl = {GL_SRC_ALPHA, GL_ONE};

这句代码骨头还不太理解,大意就是用来设置描绘时的颜色混合方案。ccBlendFunc包含了一个src和一个dst,分别表示目标和源的运算因子。

比如   ghostSprite->setBlendFunc(cbl);,这句代码,就是以这个Sprite作为源,Sprite所在位置的其它像素作为目标,进行混合运算.

至于这样做的效果和目的,骨头先mark一下。


受伤方法:很简单,hp减少,颜色改变

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ship::hurt()  
  2. {  
  3.     if (m_canBeAttack) {  
  4.         CCLog("under fire!");  
  5.         m_HP--;  
  6.         this->setColor(ccc3(255, 0, 0));  
  7.     }  
  8. }  
销毁主角飞船方法:也很简单,更新生命值,播放动画特效,然后把自己从parent删除,最后播放音效。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ship::destroy()  
  2. {  
  3.     CCLOG("destroy one ship");  
  4.     Config::sharedConfig()->updateLifeCount();  
  5.     CCLOG("life count is %d",Config::sharedConfig()->getLifeCount());  
  6.     Effect *effect = Effect::create();  
  7.     effect->explode(this->getParent(), this->getPosition());  
  8.     this->removeFromParent();  
  9.     if (Config::sharedConfig()->getAudioState()){  
  10.         CocosDenshion::SimpleAudioEngine::sharedEngine()->playEffect(s_shipDestroyEffect);  
  11.     }  
  12. }  

还有个返回矩形方法:碰撞判断好用的
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. CCRect Ship::collideRect()  
  2. {  
  3.     CCPoint pos = getPosition();  
  4.     CCSize cs = getContentSize();  
  5.     return CCRectMake(pos.x - cs.width / 2 , pos.y - cs.height / 2, cs.width, cs.height / 2);  
  6. }  


最后看看射击方法:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // 子弹发射  
  2.   this->schedule(schedule_selector(Ship::shoot), 0.16);  
每0.16秒调用一下shoot方法:也就是发射子弹的频率。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ship::shoot(float dt)  
  2. {  
  3.     int offset = 13;  
  4.     CCPoint position = this->getPosition();  
  5.     CCSize contentSize = this->getContentSize();  
  6.     Bullet *bullet_a = new Bullet(m_bulletSpeed, "W1.png", 1);  
  7.     if (bullet_a) {  
  8.         bullet_a->autorelease();  
  9.         play_bullet->addObject(bullet_a);  
  10.         this->getParent()->addChild(bullet_a, bullet_a->m_zorder, 901);  
  11.         bullet_a->setPosition(ccp(position.x + offset, position.y + 3 + contentSize.height * 0.3));  
  12.     }else{  
  13.         delete bullet_a;  
  14.         bullet_a = 0;  
  15.     }  
  16.     Bullet *bullet_b = new Bullet(m_bulletSpeed, "W1.png", 1);  
  17.     if (bullet_b) {  
  18.         bullet_b->autorelease();  
  19.         play_bullet->addObject(bullet_b);  
  20.         this->getParent()->addChild(bullet_b, bullet_b->m_zorder, 901);  
  21.         bullet_b->setPosition(ccp(position.x - offset, position.y + 3 + contentSize.height * 0.3));  
  22.     }else{  
  23.         delete bullet_b;  
  24.         bullet_a = 0;  
  25.     }  
  26. }  
这里就是生成两个子弹对象Bullet,一左一右。

骨头以后会在这里大作文章的,比如改成四排子弹,八排子弹,霰弹等等。哈哈哈哈,这是一件相当过瘾的事情!

下面紧接着看看Bullet.cpp 对象:

————————————————————————————————————————————————

子弹类:Bullet.cpp


首先看下构造方法:
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. Bullet::Bullet(int speed, const char *weapon, int attactMode)  
在里面初始化子弹的速度,生命,类型等等。

更新方法:

这里面主要是更新位置,比如dt是0.5秒,即一秒钟更新两次,所以每次位移变化量就应该是速度×dt,并且判断没hp了就设置为不可用。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Bullet::update(float dt)  
  2. {  
  3.     CCPoint position = this->getPosition();  
  4.     position.x -= m_velocityx * dt;  
  5.     position.y -= m_velocityy * dt;  
  6.     setPosition(position);  
  7.     if (m_Hp <= 0) {  
  8.         m_active = false;  
  9.     }  
  10. }  

下面是子弹的销毁方法:

播放特效,然后把当前子弹从子弹列表中删除,然后从父控件删除,最后播放一个放大2倍的动画,和一个渐渐消失的动画。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Bullet::destroy()  
  2. {     
  3.     // 子弹爆炸特效  
  4.     CCSprite *explode = CCSprite::create(s_hit);  
  5.     ccBlendFunc cb = {GL_SRC_ALPHA, GL_ONE };  
  6.     explode->setBlendFunc(cb);  
  7.     explode->setPosition(this->getPosition());  
  8.     explode->setRotation(CCRANDOM_0_1() * 360);  
  9.     explode->setScale(0.75);  
  10.     getParent()->addChild(explode, 9999);  
  11.   
  12.     play_bullet->removeObject(this);  
  13.     enemy_bullet->removeObject(this);  
  14.     this->removeFromParent();  
  15.       
  16.     CCCallFuncN *removeExplode =  CCCallFuncN::create(explode, callfuncN_selector(Bullet::removeExplode));  
  17.     explode->runAction(CCScaleBy::create(0.3, 2, 2));  
  18.     explode->runAction(CCSequence::create(CCFadeOut::create(0.3), removeExplode, NULL));  
  19. }  

————————————————————————————————————————————————

敌机类:Enemy.cpp


敌机类和主角飞机类应该是大同小异。

射击相关:每隔m_delayTime秒发射一次子弹

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. this->schedule(schedule_selector(Enemy::shoot),this->m_delayTime);  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Enemy::shoot(float dt)  
  2. {  
  3.     CCPoint pos = this->getPosition();  
  4.     Bullet *bullet = new Bullet(m_bulletSpeed, "W2.png", m_attackMode);  
  5.     bullet->autorelease();  
  6.     enemy_bullet->addObject(bullet);  
  7.     getParent()->addChild(bullet, m_zOrder, 900);  
  8.     bullet->setPosition(ccp(pos.x, pos.y - getContentSize().height * 0.2));  
  9. }  

销毁方法,见每行注释,跟主角飞机是一样的。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Enemy::destroy()  
  2. {  
  3.     // 更新分数  
  4.     Config::sharedConfig()->setScoreValue(m_scoreValue );  
  5.     // 爆炸特效和闪光特效  
  6.     Effect *effect = Effect::create();  
  7.     effect->explode(this->getParent(), getPosition());  
  8.     effect->spark(this->getPosition(),this->getParent(), 1.2, 0.7);  
  9.     // 敌机爆炸,从敌机数组删除  
  10.     enemy_items->removeObject(this);  
  11.     // 删除精灵  
  12.     this->removeFromParent();  
  13.     // 声音  
  14.     if (Config::sharedConfig()->getAudioState()) {  
  15.             SimpleAudioEngine::sharedEngine()->playEffect(s_explodeEffect);  
  16.     }  
  17. }  

————————————————————————————————————————————————
主要逻辑类:GameLayer.cpp


初始化init方法里:

启动触摸    this->setTouchEnabled(true);

初始化各种数组:play_bullet = CCArray::create(); play_bullet->retain();

游戏状态: m_state = statePlaying;//statePlaying=0  绝大部分游戏都使用这种状态机机制。


在屏幕顶端加上游戏状态:分数和剩余生命

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // ship life  
  2. CCTexture2D *shipTexture = CCTextureCache::sharedTextureCache()->addImage(s_ship01);  
  3. CCSprite *life = CCSprite::createWithTexture(shipTexture, CCRectMake(0, 0, 60, 38));  
  4. life->setScale(0.6);  
  5. life->setPosition(ccp(30,winSize.height-23));  
  6. addChild(life, 1, 5);  
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. <span style="white-space:pre">  </span>加上游戏状态:分数和剩余生命<span style="white-space: pre;">   </span>   // 每秒调一次 scoreCounter函数  
  2.    schedule(schedule_selector(GameLayer::scoreCounter), 1);  
还有根据配置类,来选择是否播放游戏背景音乐
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (Config::sharedConfig()->getAudioState()) {  
  2.     SimpleAudioEngine::sharedEngine()->playBackgroundMusic(s_bgMusic, true);  
  3. }  
初始化方法结束。


碰撞检测方法:判断两个矩形是否相交

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool GameLayer::collide(UnitSprite *a, UnitSprite *b)  
  2. {  
  3.     if(!a || !b)  
  4.     {  
  5.         return false;  
  6.     }  
  7.     CCRect aRect = a->collideRect();  
  8.     CCRect bRect = b->collideRect();  
  9.     if (aRect.intersectsRect(bRect)) {  
  10.         return true;  
  11.     }  
  12.     return false;  
  13. }  

然后使用上面的碰撞检测方法,看看有没有飞机受伤:注释很详细,就是遍历套遍历。碰撞上了就调用hurt(),越界了就destroy掉。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameLayer::checkIsCollide()  
  2. {  
  3.     CCObject *units;  
  4.     CCObject *bullets;  
  5.     CCObject *enemybs;  
  6.     //这里是相对于每个敌人  
  7.     CCARRAY_FOREACH(enemy_items, units)  
  8.     {  
  9.         UnitSprite *enemy = dynamic_cast<UnitSprite*>(units);  
  10.         //这里是相对于主角的子弹  
  11.         CCARRAY_FOREACH(play_bullet, bullets)  
  12.         {  
  13.             UnitSprite *bullet = dynamic_cast<UnitSprite*>(bullets);  
  14.             if (this->collide(enemy, bullet)) {//判断敌人和子弹  
  15.                 enemy->hurt();  
  16.                 bullet->hurt();  
  17.             }  
  18.             //越界删除  
  19.             if (!(m_screenRec.intersectsRect(bullet->boundingBox()))) {  
  20.                 bullet->destroy();  
  21.             }  
  22.         }  
  23.         if (collide(enemy, m_ship)) {//判断敌人和主角  
  24.             if (m_ship->isActive()) {  
  25.                 enemy->hurt();  
  26.                 m_ship->hurt();  
  27.             }  
  28.               
  29.         }  
  30.         if (!(m_screenRec.intersectsRect(enemy->boundingBox()))) {  
  31.             enemy->destroy();  
  32.         }  
  33.     }  
  34.     //相对于每个敌人的子弹  
  35.     CCARRAY_FOREACH(enemy_bullet, enemybs)  
  36.     {  
  37.         UnitSprite *enemyb = dynamic_cast<UnitSprite*>(enemybs);  
  38.         if (enemyb) {  
  39.             if (collide(enemyb, m_ship)) {//判断叠人子弹和主角  
  40.                 if (m_ship->isActive()) {  
  41.                     enemyb->hurt();  
  42.                     m_ship->hurt();  
  43.                 }  
  44.             }  
  45.             if (!m_screenRec.intersectsRect(enemyb->boundingBox())) {  
  46.                 enemyb->destroy();  
  47.             }  
  48.         }  
  49.           
  50.     }  
  51. }  


在updateUI()方法里,主要就是更新顶部的分数和生命值。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameLayer::updateUI()  
  2. {  
  3.     if (m_tempScore < Config::sharedConfig()->getScoreValue()) {  
  4.         m_tempScore += 5;  
  5.     }  
  6.  //   char score[20];  
  7.    // char s[] = "Score:";  
  8.   //  sprintf(score, "%d", m_tempScore);  
  9.   //  m_lbScore->setString(strcat(s, score));  
  10.     char lifecount[2];  
  11.     sprintf(lifecount, "%d",Config::sharedConfig()->getLifeCount());  
  12.     m_lifeCount->setString(lifecount);  
  13. }  

关于触摸事件:在CCScene进入和退出的两个方法里,分别注册和注销系统的触摸事件。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameLayer::onEnter()  
  2. {  
  3.     CCDirector* pDirector = CCDirector::sharedDirector();  
  4.     pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);  
  5.     CCLayer::onEnter();  
  6. }  
  7.   
  8. void GameLayer::onExit()  
  9. {  
  10.     CCDirector* pDirector = CCDirector::sharedDirector();  
  11.     pDirector->getTouchDispatcher()->removeDelegate(this);  
  12.     CCLayer::onExit();  
  13. }  


接下来就可以在 ccTouchMoved()里加逻辑了,主要就是让自己的飞机跟着移动。
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameLayer::ccTouchMoved(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)  
  2. {  
  3.     if ((m_state == statePlaying) && m_ship) {  
  4.     CCPoint pos = touch->getDelta();  
  5.     CCPoint currentPos = m_ship->getPosition();  
  6.     currentPos = ccpAdd(currentPos, pos);  
  7.     currentPos = ccpClamp(currentPos, CCPointZero, ccp(winSize.width, winSize.height));  
  8.     m_ship->setPosition(currentPos);  
  9.     }  
  10. }  
眼前一亮:

发现两个很有用的方法:

ccpAdd:两点相加

ccpCliamp:保证pos点落在两点确定的矩形之间。


暂停游戏方法:框架自带的pause方法,然后手动停止音效,停止特效。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameLayer::doPause(CCObject *pSender)  
  2. {  
  3.     CCDirector::sharedDirector()->pause();  
  4.     SimpleAudioEngine::sharedEngine()->pauseBackgroundMusic();  
  5.     SimpleAudioEngine::sharedEngine()->pauseAllEffects();  
  6.     PauseLayer *pauseLayer = PauseLayer::create();  
  7.     addChild(pauseLayer,9999);  
  8. }  

接下来是这个类里最复杂的方法了:背景滚动

感觉这个demo里,背景滚动的方法弄的有些复杂了。

其实前背景后背景,两个背景使用不同的速度来滚动,一个3秒滚动48像素,一个3秒滚动200像素。然后两个背景对象交替显示。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. // 无限滚动地图,采用两张图循环加载滚动  
  2. void GameLayer::initBackground()  
  3. {  
  4.     m_backSky = CCSprite::create(s_bg01);  
  5.     m_backSky->setAnchorPoint(ccp(0, 0));  
  6.     m_backSkyHeight = m_backSky->getContentSize().height;  
  7.     addChild(m_backSky, -10);  
  8.       
  9.     // Tile map  
  10.     m_backTileMap = CCTMXTiledMap::create(s_level01);  
  11.     addChild(m_backTileMap, -9);  
  12.     m_backTileMapHeight = m_backTileMap->getMapSize().height * m_backTileMap->getTileSize().height;  
  13.       
  14.     m_backSkyHeight -= 48;  
  15.     m_backTileMapHeight -= 200;  
  16.     m_backSky->runAction(CCMoveBy::create(3, ccp(0, -48)));  
  17.     m_backTileMap->runAction(CCMoveBy::create(3, ccp(0, -200)));  
  18.       
  19.     schedule(schedule_selector(GameLayer:: movingBackground),3);  
  20. }  
  21.   
  22. // 这里就是视差背景了  
  23. void GameLayer::movingBackground(float dt)  
  24. {  
  25.     m_backSky->runAction(CCMoveBy::create(3, ccp(0, -48)));  
  26.     m_backTileMap->runAction(CCMoveBy::create(3, ccp(0, -200)));  
  27.     // 每次移动48  
  28.     m_backSkyHeight -= 48;  
  29.     // 每次移动200  
  30.     m_backTileMapHeight -= 200;  
  31.     // 图的顶部到达屏幕顶部时  
  32.     if (m_backSkyHeight <= winSize.height) {  
  33.         if (!m_isBackSkyReload) {  
  34.             // 如果另一张图还没加载则create一个  
  35.             m_backSkyRe = CCSprite::create(s_bg01);  
  36.             m_backSkyRe->setAnchorPoint(ccp(0, 0));  
  37.             addChild(m_backSkyRe, -10);  
  38.             m_backSkyRe->setPosition(ccp(0, winSize.height));  
  39.             // 反转标志位  
  40.             m_isBackSkyReload = true;  
  41.         }  
  42.         // 第二张图紧接着第一张图滚动  
  43.         m_backSkyRe->runAction(CCMoveBy::create(3, ccp(0, -48)));  
  44.     }  
  45.     // 第一张图完全经过屏幕  
  46.     if (m_backSkyHeight <= 0) {  
  47.         m_backSkyHeight = m_backSky->getContentSize().height;  
  48.         // 移除第一张的精灵  
  49.         this->removeChild(m_backSky, true);  
  50.         // 指向第二张图的精灵  
  51.         m_backSky = m_backSkyRe;  
  52.         // 第二张的精灵指针置空  
  53.         m_backSkyRe = NULL;  
  54.         // 反转标志位  
  55.         m_isBackSkyReload = false;  
  56.     }  
  57.     if (m_backTileMapHeight <= winSize.height) {  
  58.         if (!m_isBackTileReload) {  
  59.             m_backTileMapRe = CCTMXTiledMap::create(s_level01);  
  60.             this->addChild(m_backTileMapRe, -9);  
  61.             m_backTileMapRe->setPosition(0, winSize.height);  
  62.             m_isBackTileReload = true;  
  63.         }  
  64.         m_backTileMapRe->runAction(CCMoveBy::create(3, ccp(0, -200)));  
  65.     }  
  66.     if (m_backTileMapHeight <= 0) {  
  67.         m_backTileMapHeight = m_backTileMap->getMapSize().height * m_backTileMap->getTileSize().height;  
  68.         this->removeChild(m_backTileMap, true);  
  69.         m_backTileMap = m_backTileMapRe;  
  70.         m_backTileMapRe = NULL;  
  71.         m_isBackTileReload = false;  
  72.     }  
  73. }  


————————————————————————————————————————————————

游戏结束类:GameOver.cpp

很简单,init里贴点文本、图片,然后一个重新开始按钮
[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void GameOver::playAgain(CCObject* pSender)  
  2. {  
  3.     CCScene *scene = CCScene::create();  
  4.     scene->addChild(GameLayer::create());  
  5.     CCDirector::sharedDirector()->replaceScene(CCTransitionFade::create(1.2, scene));  
  6. }  


————————————————————————————————————————————————
游戏暂停类:PauseLayer.cpp

就是一个大的全屏按钮,点击暂停按钮后,游戏暂停,此按钮开始监听,任意触摸屏幕后,游戏继续,无他。

注意,demo里的代码有问题,点击不能重开游戏,只需要注释掉 if 即可。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. bool PauseLayer::ccTouchBegan(cocos2d::CCTouch *touch, cocos2d::CCEvent *event)  
  2. {  
  3.     // 因为回调调不到了,所以resume写在了这里  
  4.     CCRect rect =  menu->getChildByTag(10)->boundingBox();  
  5.    // if (rect.containsPoint(touch->getLocation())) {  
  6.         CCLog("touch play");  
  7.         CCDirector::sharedDirector()->resume();  
  8.         SimpleAudioEngine::sharedEngine()->resumeAllEffects();  
  9.         SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();  
  10.         removeFromParent();  
  11.  //   }  
  12.     return true;  
  13. }  


————————————————————————————————————————————————

配置类:Config.cpp

全局配置,比如各种不同的敌机的参数初始化。

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. EnemyType enemyType;  
  2.    enemyType.type = 0;  
  3.    enemyType.textureName = "E0.png";  
  4.    enemyType.bulletType = "W2.png";  
  5.    enemyType.hp = 1;  
  6.    enemyType.moveType = 0;  
  7.    enemyType.scoreValue = 15;  
  8.    m_enemyTypes.push_back(enemyType);  
  9.      
  10.    enemyType.type = 1;  
  11.    enemyType.textureName = "E1.png";  
  12.    enemyType.bulletType = "W2.png";  
  13.    enemyType.hp = 2;  
  14.    enemyType.moveType = 0;  
  15.    enemyType.scoreValue = 40;  
  16.    m_enemyTypes.push_back(enemyType);  

————————————————————————————————————————————————

最后,来点过瘾的。

把Ship.cpp里的设计方法void Ship::shoot(float dt) 加个for循环: 

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. void Ship::shoot(float dt)  
  2. {  
  3.     int offset = 13;  
  4.     CCPoint position = this->getPosition();  
  5.     CCSize contentSize = this->getContentSize();  
  6.     for(int i=1;i<10;i++){//--------------新增  
  7.         Bullet *bullet_a = new Bullet(m_bulletSpeed, "W1.png", 1);  
  8.         if (bullet_a) {  
  9.             bullet_a->autorelease();  
  10.             play_bullet->addObject(bullet_a);  
  11.             this->getParent()->addChild(bullet_a, bullet_a->m_zorder, 901);  
  12.             //-------------修改offset*i  
  13.             bullet_a->setPosition(ccp(position.x + offset*i, position.y + 3 + contentSize.height * 0.3));  
  14.         }else{  
  15.             delete bullet_a;  
  16.             bullet_a = 0;  
  17.         }  
  18.         Bullet *bullet_b = new Bullet(m_bulletSpeed, "W1.png", 1);  
  19.         if (bullet_b) {  
  20.             bullet_b->autorelease();  
  21.             play_bullet->addObject(bullet_b);  
  22.             this->getParent()->addChild(bullet_b, bullet_b->m_zorder, 901);  
  23.             //-------------修改offset*i  
  24.             bullet_b->setPosition(ccp(position.x - offset*i, position.y + 3 + contentSize.height * 0.3));  
  25.         }else{  
  26.             delete bullet_b;  
  27.             bullet_a = 0;  
  28.         }  
  29.     }//-------------新增  
  30. }  

看效果


爽吧 哈哈哈


————————————————————————————————————————————————

大体就这么多,真正消化掉这些东西的话,还要自己动手敲。

身体要紧,得休息了。

晚安:)


------------------- 飞船起飞--------------------    

Cocos2dx游戏开发系列笔记11:解刨《战神传说》完结篇

Cocos2dx游戏开发系列笔记10:解刨《战神传说》

Cocos2dx游戏开发系列笔记9:android手机上运行《战神传说》,并解决横竖屏即分辨率自适应问题

Cocos2dx游戏开发系列笔记8:开搞一个射击游戏《战神传说》//就个打飞机的

Cocos2dx游戏开发系列笔记7:一个简单的跑酷游戏《萝莉快跑》的消化(附下载)

Cocos2dx游戏开发系列笔记6:怎样让《萝莉快跑》的例子运行在vs和手机上

Cocos2dx游戏开发系列笔记5:继续润色《忍者飞镖射幽灵》

Cocos2dx游戏开发系列笔记4:怎样新加一个Scene类?

Cocos2dx游戏开发系列笔记3:牛刀小试->忍者飞镖射幽灵的Demo

Cocos2dx游戏开发系列笔记2:一个刚创建的cocos2dx中的demo里都有什么

Cocos2dx游戏开发系列笔记1:一个崭新的开始,cocos2dx2.2+ndkr9+Cygwin+vs2012游戏开发环境搭建

-------------------- 飞船降落-------------------- 


最后,骨头介绍一下陪在身边的哲哲(右边就是低调的哲哲)

哲哲,小名 YIYI ,手工爱好者,文艺范,手艺人,《YiYiの妙舍》创始人,很有自己想法。

 

转载于:https://my.oschina.net/kaiyuan/blog/182871

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值