cocos2d-x高仿捕鱼达人实例分析(二)

何建中
2023-12-01
资源:http://download.csdn.net/detail/hezeping888/5696555

上一节已经实现 主游戏界面的背景加载,大炮加载,主游戏界面接受触摸事件,并调度大炮调整方向 和 动态更换大炮型号 的初步交互。
本节,将实现
GameLayer:加载炮台和子弹,调度炮台开火
Cannon:实现炮台行为:开火(创建Bullet并发射)
Bullet:负责创建一颗子弹,子弹行为:发射(子弹,撒网),销毁自己

首先对子弹类结构分析: Bullet.h
#ifndef FishingJoy_Bullet_h
#define FishingJoy_Bullet_h

#include "cocos2d.h"
class GameLayer;
class Bullet : public cocos2d::CCObject
{
public:
    static Bullet *createWithBulletType(int bulletType, GameLayer *gameLayer, cocos2d::CCSpriteBatchNode *pBatchNodeBullet, cocos2d::CCSpriteBatchNode *pBatchNodeNet);
    
    CC_SYNTHESIZE_READONLY(bool, m_bCaught, Caught);
    //超指定的方向发射子弹
    void shootTo(cocos2d::CCPoint targetDirection);
    //当击中鱼儿时,播放撒网动画
    void showNet();
private:
    CC_SYNTHESIZE(GameLayer *, m_pGameLayer, GameLayer);
    CC_SYNTHESIZE(int, m_nBulletType, BulletType);
    CC_SYNTHESIZE(cocos2d::CCSprite *, m_pSpriteBullet, SpriteBullet);
    CC_SYNTHESIZE(cocos2d::CCSprite *, m_pSpriteNet, SpriteNet);
    //创建子弹实例
    bool initWithBulletType(int bulletType, GameLayer *gameLayer, cocos2d::CCSpriteBatchNode *pBatchNodeBullet, cocos2d::CCSpriteBatchNode *pBatchNodeNet);
    //射击的子弹在超出屏幕后,及撒网动画播放完成后调用,销毁自己。
    void removeSelf();
};
#endif

结构比较简单,下面看看实现细节 Bullet.app:
创建自己createWithBulletType实现如下:
Bullet *Bullet::createWithBulletType(int bulletType, GameLayer *gameLayer, CCSpriteBatchNode *pBatchNodeBullet, CCSpriteBatchNode *pBatchNodeNet)
{
    Bullet *pBullet = new Bullet();
    if(pBullet && pBullet->initWithBulletType(bulletType, gameLayer, pBatchNodeBullet, pBatchNodeNet))
    {
        pBullet->autorelease();
        return pBullet;
    }
    else
    {
        CC_SAFE_DELETE(pBullet);
        return NULL;
    }
}
具体创建动作委托给initWithBulletType方法,而 createWithBulletType 主要负责自身内存管理设置,将自己加入到内存自动释放管理池中。
initWithBulletType方法实现如下:
bool Bullet::initWithBulletType(int bulletType, GameLayer *gameLayer, CCSpriteBatchNode *pBatchNodeBullet, CCSpriteBatchNode *pBatchNodeNet)
{
        //设置初始参数
        m_bCaught = false; 
        this->setBulletType(bulletType);
        this->setGameLayer(gameLayer);
        //创建子弹精灵,子弹类型 bulletType 有大炮决定,此处简单处理与大炮类型绑定的。
        CCString *bulletName = CCString::createWithFormat("bullet0%d.png",   bulletType  );
        this->setSpriteBullet(CCSprite::createWithSpriteFrameName(bulletName->getCString())); 
        m_pSpriteBullet->setPosition(ccp(520, 50));
         //添加到游戏主界面
        pBatchNodeBullet->addChild(m_pSpriteBullet);

        //创建 预备撒开的网 精灵
        CCString *nodenetName = CCString::createWithFormat("net0%d.png", m_nBulletType); 
        this->setSpriteNet(CCSprite::createWithSpriteFrameName(nodenetName->getCString()));
         //默认不见,只有当子弹击中鱼儿的时候,才可以调度它可见
        m_pSpriteNet->setVisible(false);
        pBatchNodeNet->addChild(m_pSpriteNet);
        
        //让游戏主界面持有子弹对象的指针
        m_pGameLayer->getBullets()->addObject(this);    

        return true;
}
现在完成子弹自我创建流程。接下来看看发射子弹(shootTo方法)是怎么实现的。
void Bullet::shootTo(CCPoint targetDirection)
{
    CCPoint ptFrom = m_pSpriteBullet->getPosition();
    CCPoint ptTo = targetDirection;
    //利用三角函数计算ptTo与ptFrom连线与引擎坐标系X轴所成角,atan2f返回弧度值
    float angle = atan2f(ptTo.y - ptFrom.y, ptTo.x - ptFrom.x);
    //将弧度值转换为角度值
    float rotation = angle / M_PI * 180.0f;
    //图片资源中子弹的朝向默认与引擎坐标系X轴垂直90度,通过90.0f-rotation计算子弹还需旋转的角度
    m_pSpriteBullet->setRotation(90.0f - rotation);
    
    CCSize size = CCDirector::sharedDirector()->getWinSize(); 
    float distance =fmaxf(size.width, size.height); 
    //通过前面角度,计算子弹发射的目的地坐标
    CCPoint targetPt = ccp(ptFrom.x + distance * cosf(angle), ptFrom.y + distance * sinf(angle));
    //通过移动动作实现子弹发射,第一个参数指移动到目的地需要的时间,第二个参数指目的地坐标
    CCFiniteTimeAction *moveto = CCMoveTo::create(1.0f, targetPt);
    //定义子弹发射动作执行完成后的回调函数
    CCFiniteTimeAction *callFunc = CCCallFunc::create(this, callfunc_selector(Bullet::removeSelf));
    //构造有序动画,最后一个参数NULL表示动画序列结束
    CCFiniteTimeAction *sequence = CCSequence::create(moveto, callFunc, NULL);
    //子弹精灵启动动作
    m_pSpriteBullet->runAction(sequence);
}
发射子弹主要逻辑就是初始子弹发射时的方向,计算发射到目的地,启用移动动作实现发射。

若子弹击中鱼儿,则会播放撒网动画,来看其实现吧。
void Bullet::showNet()
{
    //标记子弹击中鱼儿
    m_bCaught = true;
    //停止子弹所有动作效果
    m_pSpriteBullet->stopAllActions();
    //击中鱼儿的子弹不可见
    m_pSpriteBullet->setVisible(false);
    //在子弹消失的位置显示渔网
    m_pSpriteNet->setPosition(m_pSpriteBullet->getPosition());
    m_pSpriteNet->setVisible(true);
     
    //使用缩放动作实现撒网捕鱼,第一个参数指定动作执行时间,第二个参数指定放大比例
    CCScaleTo *scale = CCScaleTo::create(0.3f, 1.25f);
    CCFiniteTimeAction *callFunc = CCCallFunc::create(this, callfunc_selector(Bullet::removeSelf));
    CCFiniteTimeAction *sequence = CCSequence::create(scale, callFunc, NULL);
    m_pSpriteNet->runAction(sequence);
    
    //在播放撒网时,播放放射泡泡的粒子效果,表示被击中
    CCParticleSystem *particle = CCParticleSystemQuad::create("netparticle.plist");
    particle->setPosition(m_pSpriteNet->getPosition());
    //参数指定粒子播放时附着在粒子发射时的位置上,在指定位置播放
    particle->setPositionType(kCCPositionTypeGrouped);
    //指定粒子效果播放完成后自动释放的属性
    particle->setAutoRemoveOnFinish(true);
    //将粒子效果添加到游戏世界,进行播放
    m_pGameLayer->addChild(particle, 100);
}

最后来看看子弹自我销毁的实现:
void Bullet::removeSelf()
{
    CCLOG("remove bullet");
    //游戏主界面中持有当前子弹的指针,用于子弹与鱼儿的碰撞检测,
    //此处表示将子弹自己的指针从游戏主界面中移除
    this->getGameLayer()->getBullets()->removeObject(this);
    //从主界面中移除并销毁子弹精灵
    m_pSpriteBullet->removeFromParentAndCleanup(true);
    //从游戏主界面中移除并销毁 网 精灵
    m_pSpriteNet->removeFromParentAndCleanup(true);
}

==============================================================

子弹对象的实现已经完成,接下来看看它是怎样被大炮调用的吧,Cannon.app中对fire方法的实现:
void Cannon::fire(){
    //创建发射子弹的大炮动画帧,这里动态构建对于类型大炮的帧名称
    CCString *pFireStartFrameName=CCString::createWithFormat("actor_cannon1_%d1.png",this->m_nCannonType);
    CCString *pFireEndFrameName=CCString::createWithFormat("actor_cannon1_%d2.png",this->m_nCannonType);
    //创建发射子弹的大炮动画帧
    CCSpriteFrame *pFireStartFrame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(pFireStartFrameName->getCString());
    CCSpriteFrame *pFireEndFrame=CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(pFireEndFrameName->getCString());
    //通过发射子弹的大炮动画帧构建帧动画
    CCAnimation *pAnimationFire=CCAnimation::createWithSpriteFrames(CCArray::create(pFireStartFrame,pFireEndFrame,NULL),0.1f);
    //播放完毕后恢复原始状态
    pAnimationFire->setRestoreOriginalFrame(true);
    //创建动画动作
    CCFiniteTimeAction *pAction=CCAnimate::create(pAnimationFire);
    //大炮精灵 播放 发射子弹的大炮动画
    this->m_pSprite->runAction(pAction);
    //在播放动画的时候 创建 一颗子弹,子弹型号与大炮型号绑定
    Bullet *pBullet = Bullet::createWithBulletType(m_nCannonType, this->m_pGameLayer, this->m_pGameLayer->getBatchNodeFish2AndBullets(), this->m_pGameLayer->getBatchNodeFish3AndNets());
    //朝向指定方向发射子弹
    pBullet->shootTo(this->m_pDirection);
}
大炮 与子弹结合 开火的行为 已经实现,接下来 看看 主界面是怎么调度的吧
===============================================================
在GameLayer.app中的触摸事件中调度实现:
void GameLayer::ccTouchesEnded(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent){
    CCSetIterator it = pTouches->begin();
    while (it!=pTouches->end()) {
        //调度 大炮 开火
        this->m_pCannon->fire();
        //跳出循环,保证开火只执行一次
        break;
    }
}
在上一节确定了触摸按下,调度的是大炮转向,及大炮的升级和降级
所以触摸抬起手指时,调度大炮 发射子弹

到此本节内容介绍完毕。

运行效果描述:超触摸点发射子弹,不同型号大炮发射不同型号的子弹,子弹型号与大炮型号绑定

 

 类似资料: