__orxCPP__会被自动定义))编译器下都工作良好。
现在看下我们的StandAlone类,包含orx Init()、Run()和Exit()回调函数。
class StandAlone { public: static orxSTATUS orxFASTCALL EventHandler(const orxEVENT *_pstEvent); static orxSTATUS orxFASTCALL Init(); static void orxFASTCALL Exit(); static orxSTATUS orxFASTCALL Run(); void SelectNextLanguage(); StandAlone() : m_poLogo(NULL), s32LanguageIndex(0) {}; ~StandAlone() {}; private: orxSTATUS InitGame(); Logo *m_poLogo; orxS32 s32LanguageIndex; };所有的回调函数实际上都可以定义在任何类之外。这里这么做只是演示当你需要的时候你可以这么做。我们看到StandAlone类也包含了我们的logo对象和一个当前选中的语言的索引。
现在看一下Logo类的定义:
class Logo { private: orxOBJECT *m_pstObject; orxOBJECT *m_pstLegend; public: Logo(); ~Logo(); };这里没有什么特别的,我们用指针指向一个orxOBJECT作为我们的logo,另一个用来指向显示的本地化说明。如你所见,我们在这个可执行文件里将不会使用这个可执行文件的所有引用,我们只是保持它们以便显示在销毁Logo对象时被正确地清理。如果我们不手动做,在退出的时候orx会替我们搞定。 现在让我们看一下它的构造函数:
Logo::Logo() { m_pstObject = orxObject_CreateFromConfig("Logo"); orxObject_SetUserData(m_pstObject, this); m_pstLegend = orxObject_CreateFromConfig("Legend"); }用前面的教程中讲的方法,我们创建了两个对象(Logo和 Legend)并且我们通过 orxObject_SetUserData() 把Logo C++对象链接到它对应的orx对象上。
Logo::~Logo() { orxObject_Delete(m_pstObject); orxObject_Delete(m_pstLegend); }这里只是简单的删除了我们的两个对象。
现在看看我们的main函数:
int main(int argc, char **argv) { orx_Execute(argc, argv, StandAlone::Init, StandAlone::Run, StandAlone::Exit); return EXIT_SUCCESS; }正如我们看见的,我们使用 orx_Execute() 辅助函数来初始化和执行orx。 这样我们需要提供我们的可执行文件名称和命令行参数和三个回调函数:Init()、 Run() 和Exit()。
只有当orx退出时我们才从这个辅助函数退出。 我们快速浏览一下windows的无命令行版本。
#ifdef __orxMSVC__ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // Inits and executes orx orx_WinExecute(StandAlone::Init, StandAlone::Run, StandAlone::Exit); // Done! return EXIT_SUCCESS; } #endif和旧的main() 版本一样除了我们使用orx_WinExecute()辅助函数来计算正确的命令行参数并使用它(注释4,这些给出的参数并没有包含我们需要的用来决定主配置文件名的可执行文件的名字)。 这只能在一个无命令行(终端)的windows 游戏下工作。(注释5,使用WinMain()替代main()) 现在看看我们的Init() 代码是怎么样的:
orxSTATUS StandAlone::Init() { orxLOG("10_StandAlone Init() called!"); return soMyStandAloneGame.InitGame(); }我们简单地用StandAlone实例中的 InitGame()方法来初始化。
让我们看看它的内容:
orxEvent_AddHandler(orxEVENT_TYPE_LOCALE, EventHandler); m_poLogo = new Logo(); std::cout << "The available languages are:" << std::endl; for(orxS32 i = 0; i < orxLocale_GetLanguageCounter(); i++) { std::cout << " - " << orxLocale_GetLanguage(i) << std::endl; } orxViewport_CreateFromConfig("Viewport");我们简单地注册了一个捕捉所有orxEVENT_TYPE_LOCALE事件的回调函数。
然后实例化所有在配置文件中定义的可用语言。我们通常可以用orxLOG() 宏来记录(在屏幕上和文件里),但是我们这里用C++的方式来实现以表示多样性。
我们通过创建一个视口来结束,就像我们在之前所有教程中做的那样。
现在看下我们的Exit()回调函数:
void StandAlone::Exit() { delete soMyStandAloneGame.m_poLogo; soMyStandAloneGame.m_poLogo = NULL; orxLOG("10_StandAlone Exit() called!"); }没有什么特别的,简单地在这里销毁了Logo对象。
让我们看下Run()回调函数:
orxSTATUS StandAlone::Run() { orxSTATUS eResult = orxSTATUS_SUCCESS; if(orxInput_IsActive("CycleLanguage") && orxInput_HasNewStatus("CycleLanguage")) { soMyStandAloneGame.SelectNextLanguage(); } if(orxInput_IsActive("Quit")) { orxLOG("Quit action triggered, exiting!"); eResult = orxSTATUS_FAILURE; } return eResult; }这里完成了两件事情。
首先我们当CycleLanguage被激活时,我们切换到下一个可用的语言,其次如果Quit被激活,我们简单地返回orxSTATUS_FAILURE。
当Run()回调函数返回orxSTATUS_FAILURE时 orx(使用orx_Execute()辅助函数)将会退出。
让我们快速的浏览一下 SelectNextLanguage() 方法。
void StandAlone::SelectNextLanguage() { s32LanguageIndex = (s32LanguageIndex == orxLocale_GetLanguageCounter() - 1) ? 0 : s32LanguageIndex + 1; orxLocale_SelectLanguage(orxLocale_GetLanguage(s32LanguageIndex)); }基本上我们只是移动到下一个可用的语言(如果到最后一个则循环到列表的开头)并通过orxLocale_SelectLanguage() 函数选择它。
当我们这么做时,如果使用一个本地化字符串的已创建orxTEXT对象将会被自动更新。我们会在下面的配置描述中看到如何实现。
我们可以在EventHandler回调函数中做捕捉任意语言的选择事件。
orxSTATUS orxFASTCALL StandAlone::EventHandler(const orxEVENT *_pstEvent) { switch(_pstEvent->eID) { case orxLOCALE_EVENT_SELECT_LANGUAGE: orxLOCALE_EVENT_PAYLOAD *pstPayload; pstPayload = (orxLOCALE_EVENT_PAYLOAD *)_pstEvent->pstPayload; orxLOG("Switching to '%s'.", pstPayload->zLanguage); break; default: break; } return orxSTATUS_FAILURE; }如你所见,我们只跟踪orxLOCALE_EVENT_SELECT_LANGUAGE 事件来显示新选择的语言。
现在我们完成了本教程代码的部分。让我们看看配置吧。
首先,正如你已经见到的,我们使用对不同的平台使用不同的文件夹。
换而言之,Mac OS X的教程放在 /mac文件夹,Linux的教程放在/linux,以此类推。默认的情况下,orx会查找当前目录下的主配置文件。
为了避免在不同的平台下都有重复的配置文件,我们创建了一个简单地配置文件包含了父文件夹中配置文件的全部信息。
@../10_StandAlone.ini@
所有的内容如上。就像你在 配置文件语法说明中看到的,我们可以通过@path/to/FileToInclude@ 在一个配置文件中包含其他的配置文件。(译注:这里怀疑是作者的问题,template files实际是想链接到WIKI的配置的说明上去)
现在我们看看父文件夹中存储的配置文件(ie. ../10_StandAlone.ini).
首先定义我们的display配置段:[Display] ScreenWidth = 800 ScreenHeight = 600 Title = Stand Alone/Locale Tutorial如你所见,我们将要创建一个分辨率为800×600的窗口,并且定义了他的标题。
现在我们要提供视口(viewport)和摄像头(camera)配置段的信息:
[Viewport] Camera = Camera BackgroundColor = (20, 10, 10) [Camera] FrustumWidth = @Display.ScreenWidth FrustumHeight = @Display.ScreenHeight FrustumFar = 2.0 Position = (0.0, 0.0, -1.0)与我们在 视口教程中提到的没有任何区别。
现在看看输入(inputs)是怎么定义的
[Input] SetList = MainInput [MainInput] KEY_ESCAPE = Quit KEY_SPACE = CycleLanguage MOUSE_LEFT = CycleLanguage在Input配置段,我们定义我们所有的输入集合。本教程中我们只会用到一个叫做MainInput的集合,但我们也定义其他任意想要使用的集合(例如,主菜单一个,游戏中一个,等等)。 MainInput集合包括3个映射:
- KEY_ESCAPE 会触发名为Quit的输入
- KEY_SPACE 和 MOUSE_LEFT 都会触发名为CycleLanguage的输入
现在让我们看看怎么定义将要被 orxLOCALE模块使用的语言。
[Locale] LanguageList = English#French#Spanish#German#Finnish#Swedish#Norwegian [English] Content = This is orx's logo. Lang = (English) [French] Content = Ceci est le logo d'orx. Lang = (Français) [Spanish] Content = Este es el logotipo de orx. Lang = (Español) [German] Content = Das ist orx Logo. Lang = (Deutsch) [Finnish] Content = Tämä on orx logo. Lang = (Suomi) [Swedish] Content = Detta är orx logotyp. Lang = (Svenska) [Norwegian] Content = Dette er orx logo. Lang = (Norsk)为了定义本地化需要的语言我们要定义一个Locale 配置段和一个包含我们所需要全部的语言的列表。
由于本地化系统是基于orx配置部分,我们可以使用它的继承能力来简化把语言加入列表的过程(例如在另一个外部文件中),甚至也可以完善曾经只被部分定义的语言。
现在看看我们是怎么定义Logo对象:
[LogoGraphic] Texture = ../../data/object/orx.png Pivot = center [Logo] Graphic = LogoGraphic FXList = FadeIn # LoopFX # ColorCycle1 Smoothing = true又一次,所有的内容我们都已经在对象教程(object tutorial)中涵盖了。 如果你对我们定义了哪些FX感到好奇,你可以直接查看10_StandAlone.ini ,但是我们不会在这里讨论它们的细节。
下一个要查看的是:我们的Legend对象:
[Legend] ChildList = Legend1 # Legend2奇怪吧!其实它只是一个我们由两子对象繁衍出来的空对象。
然而我们对它们不会有直接的指针,这意味着我们将不可能直接操作它们。
话虽这么说,对所有非交互/后台对象这却不是一个问题。
同时请注意他们的帧(参考:frame tutorial)会影响ChildList ‘串联’的继承。
好了,现在让我们回到Legend1 和Legend2两个对象。
[Legend1] Graphic = Legend1Graphic Position = (0, 0.25, 0.0) FXList = ColorCycle2 ParentCamera = Camera [Legend2] Graphic = Legend2Graphic Position = (0, 0.3, 0.0) FXList = @Legend1 ParentCamera = @Legend1它们看起来很基本,都是用了相同的 FX(ColorCyle2),它们也都有一个位置并且各自有它们的Graphic。
注意:我们也可以看到我们为它们定义了ParentCamera属性。这意味着最终它们实际的父对象为Camera而不是Legend对象。
然而Legend还将是它们的拥有者,这说明它们将会在Legend被销毁时自动被销毁。
现在让我们看一下它们的Graphic对象作为结束。
[Legend1Text] String = $Content [Legend2Text] String = $Lang [Legend1Graphic] Pivot = center Text = Legend1Text [Legend2Graphic] Pivot = center Text = Legend2Text我们可以看到每一个Graphic都有自己的Text 属性:Legend1Text和Legend2Text。 它们都有不同的String字段。
开头的$字符说明我们不会显示一个原始的文本但内容作为我们将会把内容作为本地化系统的关键字。
所以在最后,Legend1对象会显示该关键字Content的本地化字符串,Legend2会显示关键字Lang的本地化字符串。
每一次我们会切换到另一个语言,所有的orxTEXT对象(例如Legend1Text和 Legend2Text)会根据新选择的语言自动更新它们的内容。:)
正如我们早前看到的,如果需要,我们还可以捕获 orxLOCALE_EVENT_SELECT_LANGUAGE事件来进行特定的处理。
===== 资源 =====
源代码: 10_StandAlone.cpp
配置文件: 10_StandAlone.ini