《简单的飞机大战》事实上不简单

Posted wzzkaifa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《简单的飞机大战》事实上不简单相关的知识,希望对你有一定的参考价值。

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"><span style="white-space:pre">	</span>这是一个很easy的《经典飞机大战》游戏。实现的基本功能:包含Boss的随机生成,击中销毁;分数依据击毁Boss的数量添加。

附加功能有:道具的不定时产生,当英雄飞机碰撞到道具产生该道具的道具效果。</span>

</pre><pre name="code" class="cpp">

这里仅仅实现最基本功能。

环境搭配:

1.操作系统;Win7

2.cocos2d-x版本号:3.2

3.VS版本号:VS2013


一、首先确定飞机基类

1.在这里,因为节点的getBoundingBox()的到的矩形比实际要检測碰撞的矩形大效果不好,另一些英雄飞、和Boss飞机和子弹的同样的功能。首先写出一个公共基类:

class BoxTest :public cocos2d::Sprite
{
public:
	//CREATE_FUNC(BoxTest);
	//virtual bool init();

	cocos2d::Rect getBox();

	virtual void setStep(int step){ _step = step; }
	//是否爆炸
	virtual void setIsbomb(bool bomb) { _isbomb = bomb; }
	virtual bool getIsbomb() const { return _isbomb; }

	//被击中后降低最多击中次数
	virtual void reduceHP(){ ; };
	virtual int getHP() const { return _HP; };
	virtual void setHP(int hp){ _HP = hp; }
	virtual void setIsRemove(bool isremove){ _isremove = isremove; }
	virtual bool getIsRemove() const { return _isremove; }

	//击中动画
	virtual Animate *animateHit(){ return nullptr; };
	//爆炸动画
	virtual Animate *animateBomb(){ return nullptr; };

protected:
	float Minx;
	float Miny;

	//移动步数 速度
	int _step;
	//是否爆炸
	bool _isbomb;
	//最多被击中次数,为0时爆炸
	int _HP;

	bool _isremove;


};


2.实现该类的部分方法:

Rect BoxTest::getBox()
{
	Minx = this->getPosition().x - this->getContentSize().width / 2 * 0.5;
	Miny = this->getPosition().y - this->getContentSize().height / 2 * 0.5;

	return Rect(Minx, Miny, this->getContentSize().width * 0.5, this->getContentSize().height * 0.5);
}
二、创建英雄飞机和Boss飞机

1.继承上述公共基类:

class Boss1 :public BoxTest
{
public:
	CREATE_FUNC(Boss1);
	virtual bool init();

	virtual void update(float dt);

	//击中时降低挤肿次数
	virtual void reduceHP();

	//击中动画
	virtual Animate *animateHit();
	//爆炸动画
	virtual Animate *animateBomb();
	
};
class Boss2 :public BoxTest
{
public:
	CREATE_FUNC(Boss2);
	virtual bool init();

	virtual void update(float dt);

	//击中时降低挤肿次数
	virtual void reduceHP();

	//击中动画
	virtual Animate *animateHit();
	//爆炸动画
	virtual Animate *animateBomb();

};
//最牛逼的飞机
class Boss3 :public BoxTest
{
public:
	CREATE_FUNC(Boss3);
	virtual bool init();

	virtual void update(float dt);

	//击中时降低挤肿次数
	virtual void reduceHP();
	void actionMove();
	Animate *animateMove();
	//击中动画
	virtual Animate *animateHit();
	//爆炸动画
	virtual Animate *animateBomb();

};
//英雄飞机
class Plane :public BoxTest
{
public:
	CREATE_FUNC(Plane);
	virtual bool init();
	virtual	void update(float dt);
};


class Bullet :public BoxTest
{
public:
	CREATE_FUNC(Bullet);
	virtual bool init();

	virtual void update(float dt);
};
2.实现继承方法:

bool Plane::init()
{
	if (Sprite::initWithSpriteFrameName("hero1.png") == false)
		return false;
	//log("1%f    %f", this->getContentSize().width, this->getContentSize().height);
	//this->setContentSize(Size(this->getContentSize().width * 0.7f, this->getContentSize().height * 0.7f));
	//this->setScale(0.7f);
	//log("2%f    %f", this->getContentSize().width, this->getContentSize().height);
	this->scheduleUpdate();
	return true;
}

void Plane::update(float dt)
{
	auto VisbelSize = Director::getInstance()->getVisibleSize();
	if ((this->getPosition().x > (VisbelSize.width - this->getContentSize().width / 2)))
	{
		this->setPositionX(VisbelSize.width - this->getContentSize().width / 2 - 6);
	}
	else if ((this->getPosition().x < this->getContentSize().width / 2))
	{
		this->setPositionX(this->getContentSize().width / 2 - 6);
	}
	else if ((this->getPosition().y >(VisbelSize.height - this->getContentSize().height / 2)))
	{
		this->setPositionY(VisbelSize.height - this->getContentSize().height / 2);
	}
	else if ((this->getPosition().y < this->getContentSize().height / 2))
	{
		this->setPositionY(this->getContentSize().height / 2);
	}
}

//最小的Boss
bool Boss1::init()
{
	if (Sprite::initWithSpriteFrameName("enemy1.png") == false)
		return false;

	//移动速度
	this->_step = 3;
	this->_HP = 0;
	this->_isbomb = false;


	this->scheduleUpdate();
	return true;
}

void Boss1::reduceHP()
{
	if (_HP > 0)
	{
		this->runAction(this->animateHit());
		_HP--;
	}
	else
	{
		setIsbomb(true);
	}
}


Animate *Boss1::animateHit()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_hit.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2.png");
	frameVec.pushBack(frame);


	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.2f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}


Animate *Boss1::animateBomb()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	int frameNum = 4;
	for (int i = 0; i < frameNum; i++)
	{
		frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("enemy1_down%d.png", i + 1).c_str());
		frameVec.pushBack(frame);
	}

	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.1f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}


void Boss1::update(float dt)
{
	this->setPositionY(this->getPositionY() - _step);
	if (this->getPositionY() < 0)
	{
		this->setIsRemove(true);
		this->removeFromParent();
	}
	else if (_isbomb == true)
	{
		this->setPositionY(this->getPositionY() - _step);
		if (this->getPositionY() < 0)
		{
			this->setIsRemove(true);
			this->removeFromParent();
		}
		else if (_isbomb == true)
		{
			auto callfunc = [this](){
				this->setIsRemove(true);
				this->removeFromParent();
			};
			//先停住
			_step = 0;
			//爆炸
			this->unscheduleUpdate();
			//this->runAction(animateBomb());
			this->runAction(Sequence::create(animateBomb(), CallFunc::create(callfunc), nullptr));
		}
	}

}




//中间Boss
bool Boss2::init()
{
	if (Sprite::initWithSpriteFrameName("enemy2.png") == false)
		return false;

	//移动速度
	this->_step = 2;
	this->_HP = 1;
	this->_isbomb = false;


	this->scheduleUpdate();
	return true;
}

void Boss2::reduceHP()
{
	if (_HP > 0)
	{
		this->runAction(animateHit());
		_HP--;
	}
	else
	{
		setIsbomb(true);
	}
}


Animate *Boss2::animateHit()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2_hit.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy2.png");
	frameVec.pushBack(frame);


	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.1f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}


Animate *Boss2::animateBomb()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	int frameNum = 4;
	for (int i = 0; i < frameNum; i++)
	{
		frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("enemy2_down%d.png", i + 1).c_str());
		frameVec.pushBack(frame);
	}

	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.1f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}

void Boss2::update(float dt)
{
	this->setPositionY(this->getPositionY() - _step);
	if (this->getPositionY() < 0)
	{
		this->setIsRemove(true);
		this->removeFromParent();
	}
	else if (_isbomb == true)
	{
		this->setPositionY(this->getPositionY() - _step);
		if (this->getPositionY() < 0)
			this->setIsRemove(true);
		else if (_isbomb == true)
		{
			auto callfunc = [this](){
				this->setIsRemove(true);
				this->removeFromParent();
			};
			//先停住
			_step = 0;
			//爆炸
			this->unscheduleUpdate();
			//this->runAction(animateBomb());
			this->runAction(Sequence::create(animateBomb(), CallFunc::create(callfunc), nullptr));
		}
	}
		
}
 

//


bool Boss3::init()
{
	if (Sprite::initWithSpriteFrameName("enemy3_n1.png") == false)
		return false;

	//移动速度
	this->_step = 1;
	this->_HP = 2;
	this->_isbomb = false;

	actionMove();
	this->scheduleUpdate();
	return true;
}
void Boss3::actionMove()
{
	this->runAction(RepeatForever::create(animateMove()));
}
//
void Boss3::reduceHP()
{
	if (_HP > 0)
	{
		this->stopAllActions();
		this->runAction(Sequence::create(animateHit(), RepeatForever::create(animateMove()), nullptr));//animateHit());
		log("%d", _HP);
		_HP--;
	}
	else
	{
		setIsbomb(true);
	}
}
Animate *Boss3::animateMove()
{
	Animate * animate = nullptr;
	
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	int frameNum = 2;
	for (int i = 0; i < frameNum; i++)
	{
		frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("enemy3_n%d.png", i + 1).c_str());
		frameVec.pushBack(frame);
	}

	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.4f);//设置帧间隔
	animate = Animate::create(animation);

	return animate;
}


Animate *Boss3::animateHit()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_n1.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_n2.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_hit.png");
	frameVec.pushBack(frame);
	frame = SpriteFrameCache::getInstance()->getSpriteFrameByName("enemy3_n1.png");
	frameVec.pushBack(frame);

	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.1f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}


Animate *Boss3::animateBomb()
{
	SpriteFrame *frame = nullptr;
	Vector<SpriteFrame *> frameVec;


	int frameNum = 6;
	for (int i = 0; i < frameNum; i++)
	{
		frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("enemy3_down%d.png", i + 1).c_str());
		frameVec.pushBack(frame);
	}

	Animation *animation = Animation::createWithSpriteFrames(frameVec);
	animation->setLoops(1);//设置次数
	animation->setDelayPerUnit(0.1f);//设置帧间隔
	Animate *animate = Animate::create(animation);

	return animate;
}
//
//void Boss3::SelfToRemove()
//{
//	this->removeFromParent();
//}
//

void Boss3::update(float dt)
{
	this->setPositionY(this->getPositionY() - _step);
	if (this->getPositionY() < 0)
	{
		this->setIsRemove(true);
		this->removeFromParent();
	}
	else if (_isbomb == true)
	{
		auto callfunc = [this](){
			this->setIsRemove(true);
			this->removeFromParent();
		};
		//先停住
		_step = 0;
		//爆炸
		this->unscheduleUpdate();
		this->stopAllActions();
		//this->runAction(animateBomb());
		this->runAction(Sequence::create(animateBomb(), CallFunc::create(callfunc), nullptr));
	}

}
//
//void Boss3::setStep(int step)
//{
//	_step = step;
//}
//
//


bool Bullet::init()
{
	if (Sprite::initWithSpriteFrameName("bullet1.png") == false)
		return false;

	this->setStep(20);
	this->scheduleUpdate();
	return true;
}

void Bullet::update(float dt)
{
	this->setPositionY(getPositionY() + _step);
	if (getIsbomb() == true)
	{
		this->setIsRemove(true);
		this->removeFromParent();
	}
	else if (this->getPositionY() > (Director::getInstance()->getVisibleSize().height + getContentSize().height / 2))
	
		this->setIsRemove(true);
		this->removeFromParent();
	}
}
三、实现基本游戏场景的基本功能

1.在场景的init()方法中生成英雄飞机和一定数量的Boss飞机。初始化英雄飞机的触摸时间(依据触摸点移动英雄飞机,生成子弹)。

bool GameScene::init()
{
	Layer::init();
	SpriteFrameCache::getInstance()->addSpriteFramesWithFile("shoot.plist", "shoot.png");
	VisbelSize = Director::getInstance()->getVisibleSize();

	initHero();
	initListener();
	initBoss();
	initaddBoss();

	this->scheduleUpdate();
	return true;
}

2.在定时随机产生Boss飞机和检測子弹、英雄飞机对Boss的碰撞:

//产生Boss
void GameScene::addBoss(float dt)
{
	int number = 0;
	for (int i = 0; i < 1; i++)
	{
		number = rand() % 10;
		//log("%d", number);
		if (number < 1)
		{
			auto boss = Boss3::create();
			auto x = boss->getContentSize().width / 2 + rand() % (int)(VisbelSize.width - boss->getContentSize().width * 2);
			boss->setPosition(Vec2(x, VisbelSize.height + boss->getContentSize().height / 2));
			this->addChild(boss);

			_bosses.pushBack(boss);;
		}
		else if (number > 2 && number < 4)
		{
			auto boss = Boss2::create();
			auto x = boss->getContentSize().width / 2 + rand() % (int)(VisbelSize.width - boss->getContentSize().width * 2);
			boss->setPosition(Vec2(x, VisbelSize.height + boss->getContentSize().height / 2));
			this->addChild(boss);

			_bosses.pushBack(boss);
		}
		else
		{
			auto boss = Boss1::create();
			auto x = boss->getContentSize().width / 2 + rand() % (int)(VisbelSize.width - boss->getContentSize().width * 2);
			boss->setPosition(Vec2(x, VisbelSize.height + boss->getContentSize().height / 2));
			this->addChild(boss);

			_bosses.pushBack(boss);
		}

	}
}


这里通过两个Vector管理子弹和Boss飞机的碰撞检測和销毁,这里有个bug,是有时候碰撞检測不准确。

望高手指点。


void GameScene::update(float dt)
{
	for (auto ieBoss = _bosses.begin(); ieBoss != _bosses.end(); ieBoss++)
	{
		//log("%d", _bosses.size());
		if ((*ieBoss)->getBox().intersectsRect(_hero->getBox()))
		{
			(*ieBoss)->setIsbomb(true);
		}
		for (auto ieBullet = _bullets.begin(); ieBullet != _bullets.end(); ieBullet++)
		{
			if ((*ieBoss)->getBoundingBox().intersectsRect((*ieBullet)->getBoundingBox()))
			{
				(*ieBullet)->setIsRemove(true);
				(*ieBoss)->reduceHP();
			}
		}
	}
	for (auto ieBoss = _bosses.begin(); ieBoss != _bosses.end(); ieBoss++)
	{
		if ((*ieBoss)->getIsRemove() == true)
		{
			_bosses.erase(ieBoss);
			break;
		}
	}

	for (auto ieBoss = _bullets.begin(); ieBoss != _bullets.end(); ieBoss++)
	{
		if ((*ieBoss)->getIsRemove() == true)
		{
			_bullets.erase(ieBoss);
			break;
		}
	}
}


源代码和资源下载:

http://download.csdn.net/detail/shinhwalin/8886755



以上是关于《简单的飞机大战》事实上不简单的主要内容,如果未能解决你的问题,请参考以下文章

C/C++游戏项目教程:看完只会说“编译飞机大战太简单了吧”

简单的飞机大战

一个简单的 rust 项目 飞机大战

python步骤四 第二课实现飞机大战

飞机大战的操作指南

基于Java的飞机大战的课程设计与实现