头文件ShrewMouse.h:
#ifndef __ShrewMouse_H__
#define __ShrewMouse_H__
#include <Ogre.h>
class ShrewMouse
{
public:
//地鼠的三种状态
enum State
{
Alive,//生存(出洞穴且未被击中)
Dead,//死亡(已经被击中)
Sleep//休眠(在洞中不需要更新逻辑)
};
//构造函数,参数为 地鼠实例的名称,场景管理器,地鼠在三维空间的位置。
ShrewMouse(const std::string & name, Ogre::SceneManager * sm, Ogre::Vector3 & pos);
~ShrewMouse(void);
//更新函数,用于让地鼠做相应的动作。参数为两次调用的时间间隔。
void update(float interval);
//启动,换句话说让地鼠从洞里面钻出来
void enable(void);
//检查地鼠的状态
State getState(void);
//打击地鼠
bool hit(void);
private:
//地鼠的状态
State _state;
//地鼠的实体
Ogre::Entity * _ent;
//一个时间值,当这个时间为零的时候地鼠回洞里面。
float _time;
//添加一个地鼠的动画。AnimationState是动画状态的句柄
Ogre::AnimationState* _animState;
};
#endif
头文件ShrewMouseApplication.h:
#ifndef __ShrewMouseApplication_H__
#define __ShrewMouseApplication_H__
#include "ExampleApplication.h"
class ShrewMouseManager;
class ShrewMouseApplication : public ExampleApplication
{
public:
ShrewMouseApplication(void);
~ShrewMouseApplication(void);
protected:
//用于系统回调来创建场景
void createScene(void);
//用于提供框架所需要的FrameListener类型。
virtual void createFrameListener(void);
private:
//这里提供一个管理器,用于协调所有的地鼠。
ShrewMouseManager * _miceManager;
};
#endif
头文件ShrewMouseFrameListener.h:
#ifndef __ShrewMouseFrameListener_H__
#define __ShrewMouseFrameListener_H__
#include "ExampleFrameListener.h"
#include "ShrewMouseManager.h"
#include <sstream>
class ShrewMouseFrameListener: public ExampleFrameListener, public OIS::KeyListener
{
private:
//这里提供一个管理器,用于协调所有的地鼠。
ShrewMouseManager * _miceManager;
bool _exit;
public:
ShrewMouseFrameListener(ShrewMouseManager * miceManager, RenderWindow* win, Camera* cam, bool bufferedKeys, bool bufferedMouse,
bool bufferedJoy ):ExampleFrameListener(win, cam, bufferedKeys, bufferedMouse, bufferedJoy),_miceManager(miceManager)
{
_exit = false;
mKeyboard->setEventCallback(this);
}
bool keyPressed( const OIS::KeyEvent &arg )
{
int who = -1;
switch(arg.key)
{
case OIS::KC_1:
who = 1;
break;
case OIS::KC_2:
who = 2;
break;
case OIS::KC_3:
who = 3;
break;
case OIS::KC_4:
who = 4;
break;
case OIS::KC_5:
who = 5;
break;
case OIS::KC_6:
who = 6;
break;
case OIS::KC_7:
who = 7;
break;
case OIS::KC_8:
who = 8;
break;
case OIS::KC_9:
who = 9;
break;
}
// 如果映射成功,通知管理器攻击哪个地 鼠
if(who != -1)
return _miceManager->hit(who-1);
return false;
}
bool keyReleased( const OIS::KeyEvent &arg )
{
//当释放键时检查释放的键是否为 Esc或者字母 Q键,如果是则让程序在下—帧结束时退出。
if(arg.key == OIS::KC_ESCAPE || arg.key == (OIS::KC_Q) )
_exit =true;
return true;
}
bool frameEnded(const FrameEvent& evt)
{
ExampleFrameListener::frameEnded(evt);
if(_miceManager)
_miceManager->update(evt.timeSinceLastFrame);
return !_exit;
}
};
#endif
头文件ShrewMouseFrameListener.h:
#ifndef __ShrewMouseManager_H__
#define __ShrewMouseManager_H__
#include <Ogre.h>
class ShrewMouse;
class ShrewMouseManager
{
public:
ShrewMouseManager(Ogre::SceneManager *sm) ;
~ShrewMouseManager(void);
void update(float interval);
bool hit(int num);
protected:
Ogre::SceneManager * _sm;
ShrewMouse* _mice[9];
float _time;
};
#endif
源文件main.cpp:
#include "ShrewMouseApplication.h"
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
#else
int main(int argc, char **argv)
#endif
{
// Create application object
ShrewMouseApplication app;
try {
app.go();
} catch( Exception& e ) {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
#else
std::cerr << "An exception has occured: " << e.getFullDescription();
#endif
}
return 0;
}
#ifdef __cplusplus
}
#endif
源文件ShrewMouse.cpp:
#include "ShrewMouse.h"
//在构造函数中创建场景节点和模型
ShrewMouse::ShrewMouse(const std::string & name, Ogre::SceneManager * sm, Ogre::Vector3 & pos):_time(0.f),_state(Sleep)
{
using namespace Ogre;
//通过名称和模型作为参数,创建一个地鼠实体
_ent = sm->createEntity(name, "ogrehead.mesh");
//声明动画
Ogre::Animation * anim;
Ogre::NodeAnimationTrack * track;
//从场景的跟节点上创建一个子节点
Ogre::SceneNode * sn = sm->getRootSceneNode()->createChildSceneNode(pos);
//把地鼠实体挂接到这个节点上面
sn->attachObject(_ent);
//暂时让这个地鼠实体缩小(在地洞里面)
sn->setScale(Ogre::Vector3(0.5f, 0.5f, 0.5f));
//Animation是一个完整的动画组,其中可以包含一系列动画来完成一组动作
// 通过场景管理器创建,第1个参数代表动画名称,第2个参数代表总播放时间
anim = sm->createAnimation(name.c_str(), 3.f);
// 设置动画差值类型为样条插值
anim->setInterpolationMode(Animation::IM_SPLINE);
// 创建一个轨迹动画,第1个参数是id索引,第2个是代表其作用的场景节点
track = anim->createNodeTrack(0, sn);
// 设置动画关键帧
TransformKeyFrame* key;
//在第0秒,物体缩放为整个物体的1/2,为固定位置
key = track->createNodeKeyFrame(0);
key->setScale(Ogre::Vector3(0.5f, 0.5f, 0.5f));
key->setTranslate(pos);
//在1秒钟时,物体变为为原始大小
key = track->createNodeKeyFrame(1.f);
key->setScale(Ogre::Vector3(1.f, 1.f, 1.f));
key->setTranslate(pos);
//在2秒钟时,物体仍然为原始大小
key = track->createNodeKeyFrame(2.f);
key->setScale(Ogre::Vector3(1.f, 1.f, 1.f));
key->setTranslate(pos);
// 在第3秒动画结束时,物体缩小为1/2
key = track->createNodeKeyFrame(3.f);
key->setScale(Ogre::Vector3(0.5f, 0.5f, 0.5f));
key->setTranslate(pos);
// 最后我们通过上面定义的动画来创建动画状态实例
_animState = sm->createAnimationState(name.c_str());
// 初期动画关闭
_animState->setEnabled(false);
// 设置为循环播放
_animState->setLoop(true);
}
//更新函数,我们在这里倒计时,当倒计时为0的时候让实体隐藏
void ShrewMouse::update(float interval)
{
//每次调用的时候
_time-=interval;
//每次刷新更新动画
_animState->setTimePosition(3.f- _time);
//当倒计时小于等于0的时候
if(_time <=0.f)
{
_ent->getSubEntity(0)->setMaterialName("Ogre/Eyes");
_ent->getSubEntity(1)->setMaterialName("Ogre/Skin");
_ent->getSubEntity(2)->setMaterialName("Ogre/Earring");
_ent->getSubEntity(3)->setMaterialName("Ogre/Tusks");
_state = Sleep;
}
}
//析构函数
ShrewMouse::~ShrewMouse(void)
{
;
}
//让“地鼠”显示出来,并把地鼠在地面的倒计时设置为1秒
void ShrewMouse::enable(void)
{
if(_state == Sleep)
{
//设置动画为开启
_animState->setEnabled(true);
//把动画时间设置为起点
_animState->setTimePosition(0.f);
//一共需要播放3秒钟
_time = 3.f;
//将状态设为活跃
_state = Alive;
}
}
//返回状态
ShrewMouse::State ShrewMouse::getState(void)
{
return _state;
}
//击中后的状态
bool ShrewMouse::hit(void)
{
if(_state == Alive)
{
_ent->setMaterialName("Examples/SphereMappedRustySteel");
_state = Dead;
return true;
}
return false;
}
源文件ShrewMouseApplication.cpp:
#include "ShrewMouseApplication.h"
#include "ShrewMouseFrameListener.h"
#include "ShrewMouseManager.h"
using namespace Ogre;
ShrewMouseApplication::ShrewMouseApplication(void):_miceManager(NULL)
{
}
ShrewMouseApplication::~ShrewMouseApplication(void)
{
//最后释放地鼠管理器
if(_miceManager)
delete _miceManager;
}
void ShrewMouseApplication::createScene(void)
{
//设置场景环境光
mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
//创建一个灯光
Light* l = mSceneMgr->createLight("MainLight");
//设置灯光位置
l->setPosition(20,80,50);
//设置摄像机位置
mCamera->setPosition(100.0f, 200.0f, 400.0f);
//设置摄像机角度
mCamera->setOrientation(Ogre::Quaternion(Degree(-35),Vector3::UNIT_X));
//创建一个地鼠管理器,并把Ogre3D引擎中场景管理器作为参数提供。
_miceManager = new ShrewMouseManager(mSceneMgr);
}
void ShrewMouseApplication::createFrameListener(void)
{
//把我们自己的FrameListener派生类型提供给Ogre3D图形引擎,将键盘、鼠标及手柄的模式设置为缓冲。
//在框架默认的非缓冲模式中需要不停地检查输入设备信息来确定按键是否按下或者释放以及鼠标是否移动
//如果检测不够快速,某一些动作可能就发现不了。
//而在缓冲模式的情况下,OIS会记录所有输入设备的变化,并把它们通过消息告知应用程序。
//在缓冲模式下不需要检查输入设备的状态,只需要处理OIS发送的消息。
mFrameListener= new ShrewMouseFrameListener(_miceManager, mWindow, mCamera,true,true,true);
mRoot->addFrameListener(mFrameListener);
}
源文件ShrewMouseFrameListener.cpp:
#include "ShrewMouseFrameListener.h"
#include "ShrewMouseManager.h"
源文件ShrewMouseManager.cpp:
#include "ShrewMouseManager.h"
#include "ShrewMouse.h"
ShrewMouseManager::ShrewMouseManager(Ogre::SceneManager * sm):_sm(sm), _time(0.f)
{
using namespace Ogre;
for(int i=0; i<3; ++i)
{
for(int j =0; j<3; ++j)
{
int n = i+j*3;
//新建老鼠实例
_mice[n] = new ShrewMouse("head"+Ogre::StringConverter::toString(i+j*3), _sm, Ogre::Vector3(100 *i, 0, 100 *j));
}
}
}
//析构函数
ShrewMouseManager::~ShrewMouseManager(void)
{
for(int i=0; i<9; ++i)
{
if(_mice[i])
{
delete _mice[i];
_mice[i] = NULL;
}
}
}
//每间隔一秒钟,一个地鼠随机从洞里钻出,参数是两帧之间的间隔,一直刷新
void ShrewMouseManager::update(float interval)
{
//累计时间值,_time的值为剩余的累计时间
_time+=interval;
//检验累计时间有多少个1秒
while(_time >= 1.f)
{
//从累计时间中减去1秒
_time -= 1.f;
//每秒随机启动一个地鼠类型
_mice[rand()%9]->enable();
}
//在这里更新九个地鼠的动作
for(int i=0; i<9; ++i)
{
//如果老鼠现在是活的
if(_mice[i]->getState() != ShrewMouse::Sleep)
{
//只要地鼠不在睡眠状下就需要更新其逻辑
_mice[i]->update(interval);
}
}
}
//负责通知哪个地鼠被击中了
bool ShrewMouseManager::hit(int num)
{
return _mice[num]->hit();
}
运行效果截图: