有了敌机接下来要做的就是添加子弹,玩家发射子弹,然后子弹和敌机进行碰撞检测,在碰撞检测之前我们需要先做好子弹的工作,除了有子弹类外,还要有一个子弹和敌机管理器,这个管理器中包含俩个数组,用来存放敌机和子弹,等到碰撞检测的时候从数组中取出元素,先来看看子弹类是如何实现的吧!

#ifndef _BULLET_H_
#define _BULLET_H_
#include "cocos2d.h";

USING_NS_CC;

//子弹类,继承自Sprite
class Bullet : public Sprite
{
public:
	Bullet(void);
	~Bullet(void);
public:
	bool init();
	CREATE_FUNC(Bullet);
	void onEnterTransitionDidFinish();
public:
	//初始化子弹
	void initBullet(std::string name);
	//子弹移动
	void move(float tm);
private:
	//子弹移动的距离
	enum {OFFSET = 35};
};

#endif
#include "Bullet.h";
#include "Manager\Manager.h";

Bullet::Bullet(void)
{
}

Bullet::~Bullet(void)
{
}

bool Bullet::init()
{
	if(!Sprite::init())
		return false;

	return true;
}

void Bullet::onEnterTransitionDidFinish()
{
	Sprite::onEnterTransitionDidFinish();
	//每隔一定时间移动子弹
	this->schedule(SEL_SCHEDULE(&Bullet::move),0.08f);
}

//根据传入的纹理名称来初始化子弹类
void Bullet::initBullet(std::string name)
{
	this->initWithSpriteFrameName(name);
}

//子弹移动
void Bullet::move(float tm)
{
	this->setPositionY(this->getPositionY()+OFFSET);
	//子弹移动出了屏幕
	if(this->getPositionY() > Director::getInstance()->getWinSize().height)
	{
		this->removeFromParentAndCleanup(true);
		//从管理器中移除出去
		auto & vector = Manager::getInstance()->getBulletVector();
		vector.eraseObject(this);
	}
}

有了前边敌机类的基础就不难看懂子弹类,代码很简单就不罗嗦了。在子弹移动的过程中,如果子弹移出了屏幕我们需要从当前的层中去除,同时从管理器中去除,那么管理器是如何实现的呢,接下来就实现一个管理器,这个管理器我采用了单例的设计模式。

#ifndef _MANAGER_H_
#define _MANAGER_H_
#include "cocos2d.h";
//包含敌机和子弹的头文件
#include "Bullet\Bullet.h";
#include "Enemy\EnemyBase.h";

USING_NS_CC;

//子弹和敌机管理器,做成单例
class Manager
{
public:
	static Manager * getInstance();
	static void Manager::freeInstance(void);
private:
	static Manager * m_manager;
	Manager();
	bool init();
public:
	//使用以下的方法定义了俩个容器,并且实现了get方法,一定要注意get的返回值,这个返回的是引用
	//官方建议容器最好不要在堆上分配内存空间,当我们在栈上分配内存空间的时候一定要传递引用,否则就出错了
	Vector<EnemyBase *> & getEnemyVector(){return m_enemyVector;};
	Vector<Bullet *> & getBulletVector(){return m_bulletVector;};
private:
	Vector<EnemyBase *> m_enemyVector;
	Vector<Bullet *> m_bulletVector;
};

#endif
#include "Manager.h"

Manager * Manager::m_manager = NULL;

//在构造函数的初始化列表中初始化数组
Manager::Manager() : m_enemyVector(),m_bulletVector()
{
}

Manager * Manager::getInstance()
{
	if(m_manager == NULL)
	{
		m_manager = new Manager();
	}

	return m_manager;
}

void Manager::freeInstance(void)
{
	if(m_manager != NULL)
	{
		delete m_manager;
		m_manager = NULL;
	}
}

这个管理器就是一个单例设计模式,不难看懂,唯一要注意的是,子弹类的数组和敌机类的数组返回的时候一定要返回引用数据类型,一会接受的时候注意也要用引用数据类型,我在写完管理器测试的时候老是出错,找了近三个小时的原因才发现的,所以这个细节问题一定要注意,否则你返回值的时候就成了值拷贝了,子弹添加到的数组就是一个临时数组,这样的话管理器中的数组大小就是0了,这点很重要。接下来就要看看什么时候去添加子弹了,子弹的位置怎么设置,我们在主场景中添加子弹。

/场景切换完毕调用
void MainGame::onEnterTransitionDidFinish()
{
	//必须先调用父类的函数
	Layer::onEnterTransitionDidFinish();
	//添加敌机,每秒添加一个
	this->schedule(SEL_SCHEDULE(&amp;MainGame::addEnemy),1.0f);
	//添加子弹
	this->schedule(SEL_SCHEDULE(&amp;MainGame::addBullet),0.08f);
	//碰撞检测
	//this->schedule(SEL_SCHEDULE(&amp;MainGame::isHitEnemy));
}

//碰撞检测
void MainGame::isHitEnemy(float tm)
{

}

//添加子弹
void MainGame::addBullet(float tm)
{
	auto bullet = Bullet::create();
	bullet->initBullet("bullet1.png");
	auto point = Point(m_player->getPositionX(),
		m_player->getPositionY()+m_player->getContentSize().height/2+10);
	bullet->setPosition(point);

	this->addChild(bullet);
	//将子弹添加到管理器中
	auto & vector = Manager::getInstance()->getBulletVector();
	vector.pushBack(bullet);
	log("%d",vector.size());
}

每隔0.08秒我们就来添加一颗子弹,子弹位置设置的时候要跟随玩家的飞机,设置方法代码已经体现了。最后比较重要的几点是,我们需要在合适的时机将子弹和敌机添加到管理器中,那么什么时候添加呢,当然是往主场景中添加子弹和敌机的时候添加到管理器中了,什么时候移除呢,目前来看当子弹和敌机移出屏幕的时候我们需要将他们从管理器中移除出去,代码加什么位置不用我说了吧,注意接收数组的时候用引用。敌机爆炸的时候也需要移除,敌机的爆炸需要一定的时间,等动画播放完毕的时候我们将它从屏幕中移除,同时从管理器中移除。最后我们需要在游戏主场景的析构函数中调用管理器的析构,将管理器释放掉。

//敌机爆炸动画,这个类是敌机类的基类,所以敌机的名字和用到的动画帧数是不确定的,需要在参数中传递
void EnemyBase::blowUp()
{
	Vector<SpriteFrame *> vector;
	for(int i=0;i<m_count;i++)
	{
		auto frameName = __String::createWithFormat("_down%d.png",i+1);
		//将传入的字符串和frameName拼接起来,str是最后使用的spriteframe的名字
		std::string str = m_frameName+frameName-&gt;getCString();
		auto spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(str);
		vector.pushBack(spriteFrame);
	}
	//设置动画帧的间隔,同时动画只执行一次
	auto animation = Animation::createWithSpriteFrames(vector,0.2f,1);
	auto animate = Animate::create(animation);
	//移除自己的动作
	auto removeSelf = RemoveSelf::create();
	auto removeFromManager = CallFunc::create(CC_CALLBACK_0(EnemyBase::removeFromManager,this));
	auto sequence = Sequence::create(animate,removeSelf,removeFromManager,NULL);
	this->runAction(sequence);
}

//爆炸完毕从管理器中移除自己
void EnemyBase::removeFromManager()
{
	auto &amp; vector = Manager::getInstance()->getEnemyVector();
	vector.eraseObject(this);
}
MainGame::~MainGame(void)
{
	//移除事件监听器
	Director::getInstance()->getEventDispatcher()->removeEventListener(m_listener);
	Director::getInstance()->getEventDispatcher()->removeEventListener(m_touchListener);
	//释放管理器
	Manager::freeInstance();
}

用3.0实现飞机大战——添加子弹及管理器