關(guān)于引擎本身不再多加描述,我也沒(méi)搞明白,但是最近又要用,學(xué)習(xí)ing
首先這次先生成一個(gè)空白窗口,不使用SDK帶的Example。
文件:
MyApplication.h
MyListener.h
main.cpp
首先需要了解一下Ogre程序的基本結(jié)構(gòu),在Ogre里使用一個(gè)叫場(chǎng)景管理器(SceneManager)的類來(lái)管理在屏幕上顯示的各種物體,
這個(gè)類是個(gè)抽象類(class Ogre::SceneManager abstract),只起到定義接口的作用。
不可以直接實(shí)例化這個(gè)類,只能由Root節(jié)點(diǎn)調(diào)用createSceneManager方法來(lái)生成特定類型的SceneManager
OGRE里有很多種場(chǎng)景管理器。有的場(chǎng)景管理器渲染地面,有的場(chǎng)景管理器渲染BSP表等等。
與場(chǎng)景(Scene)相關(guān)的概念:實(shí)體,節(jié)點(diǎn)。
實(shí)體:簡(jiǎn)單的說(shuō)實(shí)體就相當(dāng)于空間中的一個(gè)物體,例如游戲中的一個(gè)角色。
場(chǎng)景節(jié)點(diǎn):要想在場(chǎng)景中使用實(shí)體,必須還要用到節(jié)點(diǎn)(SceneNode),它會(huì)與實(shí)體綁定在一起,當(dāng)控制這個(gè)節(jié)點(diǎn)進(jìn)行各種位移旋轉(zhuǎn)操作時(shí)
其對(duì)應(yīng)的實(shí)體也就跟著相應(yīng)的進(jìn)行操作。
##注:
根據(jù)以前玩游戲的經(jīng)驗(yàn),在游戲(比如飛行射擊)中判斷一個(gè)物體是否被打中也都是以圓點(diǎn)為中心的一個(gè)區(qū)域而非物體(飛機(jī))本身
外殼的形狀可能也是由于這個(gè)原因。
##
接下來(lái)再來(lái)了解一下一個(gè)重要的函數(shù)void MyApplication::go()
這是一個(gè)入口函數(shù),這一次在我的main方法里就只有兩行代碼:
MyApplication app;
app.go();
現(xiàn)在來(lái)看看go里有做了些什么事情。
void go()
{
//step 1 to 3 should be in this order
CreateRoot();
SetupRenderSystem();
CreateRenderWindow();
SetupInputSystem();
CreateFrameListener();
StartRenderLoop();
}
前面的三步需要按特定的順序來(lái)進(jìn)行,后面的則不一定。各個(gè)函數(shù)的功能由函數(shù)名自說(shuō)明了,內(nèi)容也很簡(jiǎn)單。
調(diào)用go后,首先需要?jiǎng)?chuàng)建根節(jié)點(diǎn)m_pRoot = new Root()這是整個(gè)引擎中最核心的一個(gè)對(duì)象,在做其它事情前必須要首先創(chuàng)建它。
接下來(lái)設(shè)置渲染系統(tǒng)SetupRenderSystem() :
if(!m_pRoot->showConfigDialog())
exit(0);
Ogre有個(gè)默認(rèn)的設(shè)置對(duì)話框,直接調(diào)用它就可以了,如果用戶取消這一步,那么直接退出程序就好。
創(chuàng)建窗口這一步,可以有多種選擇,因?yàn)椴糠謨?nèi)容跟具體的操作系統(tǒng)相關(guān),可以使用Windows SDK或者M(jìn)FC生成窗口,也可以使用
Ogre默認(rèn)的窗口系統(tǒng),為了簡(jiǎn)便,這里使用Ogre默認(rèn)窗口
m_pRoot->initialise(true, "MyApplication Rendering Window");
由于是空的窗口,所以不需要生成場(chǎng)景及做相關(guān)的工作。在這次的程序中,將要監(jiān)聽(tīng)一個(gè)鍵盤(pán)事件,按下ESC的時(shí)候退出程序。
這部分工作在接下的兩個(gè)函數(shù)SetupInputSystem和CreateFrameListener中完成。
FrameListener是一個(gè)幀監(jiān)聽(tīng)器,顯示器上的圖像都是一幀一幀的顯示出來(lái)的,我們可以在這切換這些幀的時(shí)候做一些處理工作,
比如,獲取和處理鍵盤(pán)事件。在Ogre的主循環(huán)中大概可能會(huì)是這個(gè)樣子:
- Root object調(diào)用frameStarted方法在所有已經(jīng)注冊(cè)的FrameListeners中。
- Root object渲染一幀。
- Root object調(diào)用frameEnded方法在所有已經(jīng)注冊(cè)的FrameListeners中。
在這里添加一個(gè)MyListener類用來(lái)做這件事情。
class CombatListener : public FrameListener
{
public:
CombatListener(OIS::Keyboard *pkeyboard)
: m_pKeyboard(pkeyboard)
{
}
bool frameStarted(const FrameEvent& evt)
{
m_pKeyboard->capture();
return !(m_pKeyboard->isKeyDown(OIS::KC_ESCAPE));
}
private:
OIS::Keyboard *m_pKeyboard;
};
同樣的,Ogre也已經(jīng)準(zhǔn)備好了一個(gè)基類,只需要繼承再稍加修改就可以了,其中OIS是
Object Oriented Input System,
它本身不屬于Ogre,是一個(gè)簡(jiǎn)單易用的跨平臺(tái)開(kāi)源系統(tǒng),可以用它來(lái)處理鍵盤(pán)鼠標(biāo)和游戲手柄等設(shè)備。
這里我在每一幀開(kāi)始的時(shí)候獲取鍵盤(pán)狀態(tài),當(dāng)ESC鍵按下時(shí),返回false,這將導(dǎo)致程序正常退出。
OIS使用一個(gè)統(tǒng)一的InputManager,它比較難配置,但一旦正確地創(chuàng)建之后,非常好使用。
首先在SetupInputSystem方法中加入
size_t windowHnd = 0;
std::ostringstream windowHndStr;
OIS::ParamList pl;
RenderWindow *win = m_pRoot->getAutoCreatedWindow();
win->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr<<windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
m_pInputManager = OIS::InputManager::createInputSystem(pl);
說(shuō)明一點(diǎn),getCustomAttribute方法的功能是用來(lái)獲取特定平臺(tái)的信息,在API上用一個(gè)詞Horrid來(lái)形容這個(gè)方法,哈哈,無(wú)奈D3D需要這些信息。
下面再把下面的代碼回到SetupInputSystem方法中就OK了。
try
{
m_pKeyboard = static_cast<OIS::Keyboard*>(
m_pInputManager->createInputObject(OIS::OISKeyboard, false));
}
catch(const OIS::Exception &e)
{
throw Exception(42, e.eText, "MyApplication::SetupInputSystem()");
}
InputSystem設(shè)置好了,就可以使用幀監(jiān)聽(tīng)器了,在創(chuàng)建幀監(jiān)聽(tīng)器的方法中:
m_pListener = new MyListener(m_pKeyboard);
m_pRoot->addFrameListener(m_pListener);
好,到這里程序基本上完成了,剩下只需要啟動(dòng)渲染循環(huán)(StartRenderLoop)就可以讓程序跑起來(lái)了
m_pRoot->startRendering();