资源: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;
}
}
在上一节确定了触摸按下,调度的是大炮转向,及大炮的升级和降级
所以触摸抬起手指时,调度大炮 发射子弹
到此本节内容介绍完毕。
运行效果描述:超触摸点发射子弹,不同型号大炮发射不同型号的子弹,子弹型号与大炮型号绑定