第四天:开火!

出自Ogre3D开放资源地带

跳转到: 导航, 搜索

目录

前言

经历了前面三天的学习,证明了你确实有毅力,但是不知道你有没有去论坛上面讨论一下bbs.ogre3d.cn。别害羞,提出意见或者问题我们都会来认真的回答和探讨(目前论坛冷冷清清啊~)。如果你之前看过类似的游戏源代码,你会发现我们教程中的过分简单,这是我们刻意保留的特点,尽量做到精简和直观。但如果你希望做一个漂亮和复杂的游戏,仍然有许多工作要做。所以希望你可以亲自参与到教程中来,对我们现在的原形进行一些修改和在加工,如果你心情不错的话更希望你发表在我们的论坛上。你会得到大家的赞许以及积极的反馈。

正文

好了,敌人——那个Ogre3D的头颅在我们上空盘旋。当我们正准备展开反击,却发现:我们忘带枪了,汗。

好吧没有枪炮,我们自己造。

Bullets.h

这里我们写了两个类,一个是子弹:

//3子弹类型
 class Bullet
 {
 public:	
 	Bullet(Ogre::SceneManager * sm);
 	~Bullet(void);	
 	//3更新子弹
 	void update(void);
	//3检查子弹是否被使用,返回true就是正在被使用中
	bool active(void);
	//3开火,第一个参数表示开火位置,第二个参数表明开火时的力量
	void fire(const Ogre::Vector3 & pos, 
		const Ogre::Vector3 & force);		
	//3检查子弹是否射中物体
	bool touch(void);
	//3执行爆炸动作
	void burst(void);
	//3检查是否飞行中(激活且没有爆炸)
	bool flying(void);
private:
	Ogre::Vector3 _force;
	Ogre::SceneNode * _node;
	Ogre::Entity * _ent;
	bool _active;
};


在这里,我们认为子弹有几个不同状态,未激活(在弹夹中)和激活状态,其中激活状态分为飞行中以及爆炸中。

//3子弹管理器
class BulletManager
{
	typedef boost::shared_ptr<Bullet> BulletPtr;
	typedef std::vector<BulletPtr> BulletPtrList;
public:
	BulletManager(Ogre::SceneManager * sm, int n);
	//3更新所有激活子弹
	void update(void);
	//3检查是否击中物体,如果击中,自动爆炸。
	Bullet * touch(void);
	~BulletManager(void);	
	//3开火,从已有子弹列表中选择一个没有激活的子弹,
	//调用其fire函数,第一个参数表示开火位置,第二个参数表明开火时的力量
	bool fire(const Ogre::Vector3 & pos, const Ogre::Vector3 & force);
private:
	//子弹队列
	BulletPtrList _bullets;
};

我们再提供一个子弹管理器(就当作弹夹的概念好了),在开始的时候里面放置n多没有被激活的子弹,当飞机调用fire时候,会在这些子弹中找到没有激活的子弹发射出去。

Bullets.cpp

Bullet::Bullet(Ogre::SceneManager * sm):
_force(),
_node(NULL),
_ent(NULL),
_active(false)
{
	static int i = 0;
	//3创建节点
	_node = sm->getRootSceneNode()->createChildSceneNode();
	//3这里临时用一个球体作为子弹模型,以后再美化
	_ent = sm->createEntity(std::string("bullet") + 
		boost::lexical_cast<std::string>(i++), "sphere.mesh");
	//3挂接模型实体
	_node->attachObject(_ent);
	//3缩放一下
	_node->setScale(0.1f, 0.1f, 0.1f);
	//3先隐藏着 备用
	_ent->setVisible(false);
}

这里做了一些初始化操作,并把子弹的模型先隐藏了。


void Bullet::update(void)
{
	//3进行一个位移,不是正确的物理模型,把力量当速度
	_node->translate(_force);
}

每次更新的时候(仅当被激活时调用),子弹都匀速移动一个位移,我们可以根据游戏的不同修改这个函数,比如加入跟踪轨迹或者变速运动。

void Bullet::fire(const Ogre::Vector3 & pos, const Ogre::Vector3 & force)
{
	_node->setPosition(pos);
	_force = force;
	_node->setVisible(true);
	_active = true;
}

开火的时候我们给出两个向量:发射位置、发射力度。并把子弹状态设置为激活。


后面还有一些关于子弹管理器的代码:

BulletManager::BulletManager(Ogre::SceneManager * sm, int n)
{
	//3先放置n个子弹
	for(int i = 0; i< n; ++i)
	{
		_bullets.push_back(BulletPtr(new Bullet(sm)));
	}
}

在构造函数里面,我们根据传入的数量构造n个子弹对象。


void BulletManager::update(void)
{
	//3更新所有激活的子弹(包括飞行核爆炸)
	for(BulletPtrList::iterator it = _bullets.begin();
		it != _bullets.end(); 
		++it)
	{
		if((*it)->active())
			(*it)->update();
	}
}

每次更新的时候,我们遍历所有子弹,只更新那些激活的实例。


Bullet * BulletManager::touch(void)
{
	//3遍历所有 飞行的子弹,看看有没有击中的
	for(BulletPtrList::iterator it = _bullets.begin();
		it != _bullets.end();
		++it)
	{
		if((*it)->flying())
			if((*it)->touch())
			{
				(*it)->burst();
				return (*it).get();
			}
	}
	return NULL;
}

我们提供了一个方法给我们的主角战斗机使用,就是检查所有飞行的子弹,看看是否击中敌人,如果击中就返回子弹对象实例的指针。否则返回空指针。



bool BulletManager::fire(const Ogre::Vector3 & pos,
				const Ogre::Vector3 & force)
{
	//3开火,在没有激活的子弹中选择一个。如果没有子弹可用就返回false;
	for(BulletPtrList::iterator it = _bullets.begin();
		it != _bullets.end(); ++it)
	{
		if(!(*it)->active())
		{
			(*it)->fire(pos, force);
			return true;
		}
	}
	return false;
}

最后这里提供一个“开火”函数,从没有激活的子弹中选取一个发射。

没想到这么制造抢和子弹的代码这么平凡,害得我没办法多讲一些,不过还好,代码和注释就是最好的教程。

现在我们把枪支放置在战斗机上面吧。

其他文件修改

和战斗机对象以及敌人对象不同,我们现在的子弹类型是归属于战斗机拥有管理的。所以它需要修改下面两个战斗机相关的文件:

BattlePlane.h

//3子弹管理器
BulletManager _bulletManager;

在这里我们把子弹管理器对象实例直接作为成员变量使用。


BattlePlane.cpp

void BattlePlane::onKeyReleased(const KeyEvent & evt)
{
	//这里省略前面的代码
	if(evt.getKey() == KC_SPACE)//3如果释放空格键 发射子弹
		_bulletManager.fire(
			_node->getPosition(),
			Ogre::Vector3(0.0f, 10.0f, 0.0f));
}

在释放键盘空格案件的时候,我们在飞机节点位置发射一颗子弹,其初始速度为(0,10,0)——既向y轴正方向10速度发射。

void BattlePlane::update(void)
{
	//3更新子弹
	_bulletManager.update();
	//这里省略之前的代码
}

别忘了在每一frame中更新子弹位置。

好啦现在编译运行,你就能看到我们的勇猛的战斗机向敌人发射子弹。什么?打不到敌人?哦,我们还没有检测碰撞。没错,要检测子弹是否击中敌人。不过这需要一定量的工作。我们留给下一课吧。

课程结语

你别说我偷懒,把碰撞拿到下一课来实现。我告诉你,现在我偷偷送你一些好东西,咱们不告诉别人。

BattlePlane.h以及BattlePlane.cpp中我们还有一些没有讲到的Ogre相关的代码。没错,这个就厉害了,他就是我们战斗机的喷射器。 不卖关子了,这是粒子系统。Ogre3D中巴粒子系统已经实现个八九不离十,我们只需要布置一下就好了。不过Ogre3D的讲解不是本教程的主要内容,所以就麻烦大家去ogre3d.cn看看,有什么问题也可以到bbs.ogre3d.cn去讨论。我们就不再这里废话了。

好的好的,今天课程到这里就结束了,虽然可能你仍然意犹未尽,但是我也要睡觉了,最近时间很紧张,你还是自己去看看粒子系统方面的文章吧。

个人工具