九天雁翎的博客
如果你想在软件业获得成功,就使用你知道的最强大的语言,用它解决你知道的最难的问题,并且等待竞争对手的经理做出自甘平庸的选择。 -- Paul Graham

【转】【翻译】Orx官方教程:10.独立程序和本地化 stand alone & localization


本文译自 orx tutorials 的
独立程序与本地化教程

(stand alone &
localization),六月流光 译。最新版本见Orx

官方中文Wiki

。 本文转自六月流光的
博客

。原文链接在:
http://yatusiter.blogbus.com/logs/68485225.html

。望有新人能够加入这个翻译者的队伍,早日将
Orx的WIKI页中文化。有兴趣的请加入qq群73063577,并与我取得联系,防止重复翻译。

StandAlone tutorial

独立程序与本地化教程(stand alone
& localization)

Summary

综述

This is our first basic C++ tutorial. It also
shows how to write a stand alone executable using orx and how to use
the localization module (orxLOCALE).

 

这是我们的第一个C++基础教程。它也展示了如何使用orx编写独立的可执行文件和使用本地化模
块(orxLOCALE)。

 

As
we are NOT using the default executable anymore for this tutorial, its
code will be directly compiled into the executable and not into an
external library.

 


于我们在此教程中不再使用默认的可执行文件,它的代码会被直接编译成可执行文件而不是外部库。

 

This implies that we
will NOT have the default hardcoded behavior we had in the previous
tutorials:

 

这暗示了我们不再有前几个教程中的如下默认行
为:(译注:内置于默认可执行文件,同时下面的几点原本也都是否定句式,但与这里的否定矛盾,原意应该是下面这些特性会在StandAlone版本中失
效)

  • F11 will not affect vertical sync toggler
  • Escape
    won't automatically exit
  • F12 won't capture a
    screenshot
  • Backspace won't reload configuration files
  • the
    [Main] section in the config file won't be used to load a plugin
    (“GameFile” key)

 

  • F11 切换垂直同步
  • Escape
    退出
  • F12 截屏
  • 退格键(Backspace)
    重新载入全部配置文件
  • 配置文件中的[Main] 配置段被用于加载一个插件(“GameFile” 键)

A program based
directly on orx

1)

, by default, will
also NOT exit     if  it receives the orxSYSTEM_EVENT_CLOSE event.To do
so, we will either have to use the helper orx_Execute() function (

see below

) or handle it
ourselves.

 

一个直接基于orx的程序(注释1,即不再依靠
ORX 启动器),默认收到orxSYSTEM_EVENT_CLOSE事件后不退出。为了改变这种情况,我们必须使用orx_Execute()
函数(如下link)或者自己处理。

 

See
previous

basic tutorials

for more info about
basic

object creation

,
clock handling

,
frames hierarchy

,
animations

,
cameras &
viewports


,

sounds &
musics


,

FXs

,
physics

and
scrolling

.

 

查看之前关于basic
object creation

,
clock handling

,
frames hierarchy

,
animations

,
cameras &
viewports


,

sounds &
musics


,

FXs

,
physics

and
scrolling

的基础教程以获得更多的信息。

 

As we're on our own
here, we need to write the main function and initialize orx manually.The
good thing is that we can then specify which modules we want to use,
and deactivates display or any other module at will, if needed.

 

我们现在只能靠自己了,所以必须自己写main
函数和手动初始化orx。


处是如果需要,我们可以任意指定要使用哪些模块,停用显示模块或其他模块。

 

If we still want a semi-automated
initialization of orx, we can use the orx_Execute() function.This
tutorial will cover the use of orx with this helper function, but you
can decide not to use it if its behavior doesn't suit your needs.

 

如果我们还是想要半自动初始化orx,我们可以
使用orx_Execute()函数。

本教程将通过这个辅助函数使用orx,但是如果它的行为不符合你的需求也可以不使用。

 

This helper function
will take care of initializing everything correctly and exiting
properly.

It
will also make sure the clock module is constantly ticked (as it's part
of orx's core) and that we exit if the orxSYSTEM_EVENT_CLOSE event is
sent.

This
event is sent when closing the windows, for example, but it can also be
sent under your own criteria (escape key pressed, for example).

 

这个辅助函数将会确保所有部分正确初始化和妥善
退出。


也将确保clock模块正常运作(作为 orx的核心部分)并且当(备注,一个模块不断被触发,不太好理解,事实上是表示clock一直在正常计时)

orxSYSTEM_EVENT_CLOSE事
件发送时退出。


事件在关闭窗口时发送,但是也可以按你的标准发送(例如按下Esc键)。

 

This code is also a basic C++ example to show
how to use orx without having to write C code.

This tutorial could
have been architectured in a better way (cutting it into pieces with
headers files, for example) but we wanted to keep a single file per
*basic* tutorial.

 


些代码同样也是一个基础的C++示例,用来演示如何通过C语言以外的语言来使用orx。

本教程本来应该用另外一种更好的方式组织起来
(例如分割成多个头文件)但是我们希望每个基础教程都只有一个文件。

 

This stand alone executable also creates a
console (as does the default orx executable), but you can have you own
console-less program if you wish.

In order to achieve that, you only need to
provide an argc/argv style parameter list that contains the executable
name.

If
you don't, the default loaded config file will be orx.ini instead of
being based on our executable name (ie. 10_StandAlone.ini).

这个独立可执行文件会创建一个终端(和默认的
orx可执行文件一样),但是如果你喜欢也可以创建一个没有终端的可执行文件。

为了实现上述目标,你只需要提供一个包含该可执行文件名的argc/argv风格的
参数表即可。


果不这样的话,默认加载的配置文件是orx.ini,取代基于可执行文件名的配置文件(例如  10_StandAlone.ini)。

 

For
visual studio

users (windows), it
can easily be achieved by writing a WinMain() function instead of
main(), and by getting the executable name (or hardcoding it, as it's
shamelessly done in this tutorial

 

对visual studio
用户(windows)而言,可以轻松通过撰写WinMain() 替代main()
函数,并且获取可执行文件的名称(或者硬编码实现,正如本教程中可耻地这么做鸟^.^) 。

 

This tutorial simply
display orx's logo and a localized legend. Press space or click left
mouse button to cycle through all the availables languages for the
legend's text.

 


教程简单的现实了orx的logo和一个本地化的说明。按空格键或者点击鼠标左键以循环显示所有可用语言的说明文本。

 

Some explanations
about core elements that you can find in this tutorial:

 

下面是一些你可以在本教程中找到的核心元素的解
释:

 

  • Run
    function: Don't put *ANY* logic code here, it's only a backbone where
    you can handle default core behaviors (tracking exit or changing locale,
    for example) or profile some stuff. As it's directly called from the
    main loop and not part of the clock system, time consistency can't be
    enforced. For all your main game execution, please create (or use an
    existing) clock and register your callback to it.

 

  • 运行
    函数(Run
    function):不要在这里放置任何逻辑代码,它只是一个处理默认核心行为(例如跟踪退出或者更改locale)或简要描述一些东西的主干。由于它直
    接从main循环中调用并且不是clock系统的的一部分,时间一致性无法被强制执行。对你所有的主游戏可执行文件,请在此创建(或者使用已有
    的)clock并且注册你的回调函数。

 

  • Event handlers: When
    an event handler returns orxSTATUS_SUCCESS, no other handler will be
    called after it for the same event. On the other hand, if
    orxSTATUS_FAILURE is returned, event processing will continue for this
    event if other handlers are listening this event type. We'll monitor
    locale events to update our legend's text when the selected language is
    changed.

 

  • 事件处理器(Event
    handlers):当一个事件响应函数返回orxSTATUS_SUCCESS后,对此事件就不会再调用其他事件响应函数。另一方面,如果返回的是
    orxSTATUS_FAILURE,事件会传递给其他正在监听这个事件的响应函数。我们将监视locale事情以便当选择的语言切换时更新我们的说明文
    本。(备注:这个翻译有点乱,主要要了解Orx的事件处理方式)

 

  • orx_Execute():
    Inits and executes orx using our self-defined functions (Init, Run and
    Exit). We can of course not use this helper and handles everything
    manually if its behavior doesn't suit our needs. You can have a look at
    the content of orx_Execute()

    2)

    to have a better idea
    on how to do this.

 

  • orx_Execute():通过我们自定义
    的函数(Init,Run和Exit)初始化和执行orx。当然,如果它不符合我们的需求,我们可以不使用这个辅助函数并且手动处理所有事情。你可以通过
    参考orx_Execute()的内容(注2,在orx.h中实现)了解怎么这样做。(备注,作者的better
    idea不是说更好的注意,而是对于how to do this的修饰,就是我们不知道时候说,I have no idea一样)

Details

详细说明

Let's start with the
includes.


我们从包含的文件开始。

 

#include "orx.h"

That's all you need to
include so as to use orx. This include works equally with a C or a C++
compiler

3)

.


    这就是你要使用orx所需要包含的唯一文件。它在C和C++(注释3,在这种情 况下预编译宏 __orxCPP__
会被自动定义)编译器下都工作良好。

Let's
now have a look at our StandAlone class that contains orx's Init(),
Run() and Exit() callbacks.

现在看下我们的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;


};

All
the callbacks could actually have been defined out of any class. This
is done here just to show how to do it if you need it.


We see that our
StandAlone class also contains our Logo object and an index to the
current selected language.

所有的回调函数实际上都可以定义在任何类之外。这里这么做只是演示当你需要的时候你可以这么做。
我们看到StandAlone类也包含了我们的logo对象和一个当前选中的语言的索引。

Let's now have a look
to our Logo class definition.


现在看一下Logo类的定义:

class Logo

{

   private:

    orxOBJECT
*m_pstObject;


    orxOBJECT *m_pstLegend;

    public:

    Logo();

    ~Logo();

};

Nothing fancy here, we
have a reference to an orxOBJECT that will be our logo and another one
that will be the displayed localized legend.


As you'll see we won't
use the reference at all in this executable, we just keep them so as to
show a proper cleaning when our Logo object is destroyed. If we don't
do it manually, orx will take care of it when quitting anyway.

这里没有什么特别的,我们用指针指向一个
orxOBJECT作为我们的logo,另一个用来指向显示的本地化说明。如你所见,我们在这个可执行文件里将不会使用这个可执行文件的所有引用,我们只
是保持它们以便显示在销毁Logo对象时被正确地清理。如果我们不手动做,在退出的时候orx会替我们搞定。

Let's now see its
constructor.


现在让我们看一下它的构造函数:

Logo::Logo()

{

    m_pstObject =
orxObject_CreateFromConfig("Logo");


     
orxObject_SetUserData(m_pstObject, this);


    m_pstLegend =
orxObject_CreateFromConfig("Legend");


}

As seen in the previous tutorials we
create our two objects (Logo and Legend) and we link our Logo C++ object
to its orx equivalent using orxObject_SetUserData().

用前面的教程中讲的方法,我们创建了两个对象
(Logo和Legend)并且我们通过


orxObject_SetUserData()把Logo C++对象链接到它对应的orx对象上。

Logo::~Logo()

{

     
orxObject_Delete(m_pstObject);


      orxObject_Delete(m_pstLegend);

}

Simple cleaning here
as we only delete our both objects.

这里只是简单的删除了我们的两个对象。

Let's now see our main
function.



在看看我们的main函数:

int
main(int argc, char **argv)


{

      orx_Execute(argc, argv,
StandAlone::Init, StandAlone::Run, StandAlone::Exit);


    return
EXIT_SUCCESS;


}

As
we can see, we're using the orx_Execute() helper that will initialize
and execute orx for us.


In order to do so, we need to provide it our
executable name and the command line parameters along with three
callbacks: Init(), Run() and Exit().

正如我们看见的,我们使用 orx_Execute()
辅助函数来初始化和执行orx。


这样我们需要提供我们的可执行文件名称和命令行参数和三个回调函数:Init()、Run() 和Exit()。

We will only exit from
this helper function when orx quits.

只有当orx退出时我们才从这个辅助函数退出。

Let's have a quick
glance at the console-less version for windows.


我们快速浏览一下windows的无终端版本。

#ifdef __orxMSVC__  

int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE PrevInstance,


        LPSTR
lpCmdLine, int nCmdShow) {


    // Inits and executes orx

   
orx_WinExecute(StandAlone::Init, StandAlone::Run, StandAlone::Exit);


    // Done!

    return
EXIT_SUCCESS;


}   #endif

Same as for the traditional main() version
except that we use the orx_WinExecute() helper that will compute the
correct command line parameters and use it.

4)(the ones given
as parameter don't contain the executable name which is needed to
determine the main config file name






This only works for a
console-less windows game

5)

.(which uses WinMain()
instead of main())


旧的main()
版本一样除了我们使用orx_WinExecute()辅助函数来计算正确的命令行参数并使用它(注释4,这些给出的参数并没有包含我们需要的用来决定主
配置文件名的可执行文件的名字)。


这只能在一个无命令行(终端)的windows游戏下工作。(注释5,使用WinMain()替代main())

Let's now see how our
Init() code looks like.


现在看看我们的Init() 代码是怎么样的:

orxSTATUS
StandAlone::Init()


{

      orxLOG("10_StandAlone Init() called!");

    return
soMyStandAloneGame.InitGame();


}

We simply initialize our StandAlone instance
by calling its InitGame() method.

我们简单地用StandAlone实例中的InitGame()方法来初始化。

Let's see its content.

让我们看看它的内容:

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");

We simply register a
callback to catch all the orxEVENT_TYPE_LOCALE events.


We then instanciate
our Logo object that contains both logo and legend.


We also outputs all
the available languages that have been defined in config files. We could
have used the orxLOG() macro to log as usual (on screen and in file),
but we did it the C++ way here to show some diversity.


We finish by creating
our viewport, as seen in all the previous tutorials.

我们简单地注册了一个捕捉所有
orxEVENT_TYPE_LOCALE事件的回调函数。


然后实例化所有在配置文件中定义的可用语言。我们通常可以用orxLOG()
宏来记录(在屏幕上和文件里),但是我们这里用C++的方式来实现以表示多样性。


我们通过创建一个视口来结束,就像我们在之前所有教程中做的那样。

Let's now see our
Exit() callback.


在看下我们的Exit()回调函数:

void
StandAlone::Exit()


{

    delete soMyStandAloneGame.m_poLogo;

   
soMyStandAloneGame.m_poLogo = NULL;   


    orxLOG("10_StandAlone Exit()
called!");


}

Simple Logo object
deletion here, nothing surprising.

没有什么特别的,简单地在这里销毁了Logo对象。

Now let's have a look
to our Run() callback.


让我们看下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;

}

Two things are done here.

First when the input
CycleLanguage is activated we switch to the next available language,
then when the Quit one is activated, we simply return orxSTATUS_FAILURE.


When the Run()
callback returns orxSTATUS_FAILURE orx (when used with the helper
orx_Execute()) will quit.

这里完成了两件事情。

首先我们当CycleLanguage被激活时,我们切换到下一个可用的语言,其次
如果Quit被激活,我们简单地返回orxSTATUS_FAILURE。


当Run()回调函数返回orxSTATUS_FAILURE时orx(使用
orx_Execute()辅助函数)将会退出。

Let's have a quick look to the
SelectNextLanguage() method.

让我们快速的浏览一下 SelectNextLanguage() 方法。

void
StandAlone::SelectNextLanguage()


{

s32LanguageIndex = (s32LanguageIndex ==
orxLocale_GetLanguageCounter() - 1) ? 0 : s32LanguageIndex + 1;


orxLocale_SelectLanguage(orxLocale_GetLanguage(s32LanguageIndex));

}

We basically go to the
next available language (cycling back to the beginning of the list when
we reached the last one) and selects it with the
orxLocale_SelectLanguage() function.


When doing so, all created orxTEXT
objects will be automatically updated if they use a localized string.
We'll see how to do that below in the config description.


We can also catch any
language selection as done in our EventHandler callback.

基本上我们只是移动到下一个可用的语言(如果到
最后一个则循环到列表的开头)并通过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;


}

As
you can see, we only track the orxLOCALE_EVENT_SELECT_LANGUAGE event
here so as to display which is the new selected language.

如你所见,我们只跟踪
orxLOCALE_EVENT_SELECT_LANGUAGE事件来显示新选择的语言。

We're now done with
the code part of this tutorial. Let's now have a look at the config.

现在我们完成了本教程代码的部分。让我们看看配
置吧。

First of all, as you
might have seen, we use different folder for different architectures.


In other words, the
tutorials for Mac OS X are in the /mac folder, the ones for Linux in the
/linux and so on. By default orx will look in the current folder to
find the main config file.


As we don't want to duplicate the config file
in all the architecture folders, we create a very simple one which
purpose is only to include the one that contains all the info and which
is in the parent folder.

首选,正如你已经见到的,我们使用对不同的平台使用不同的文件夹。

换而言之,Mac OS X的教程放在
/mac文件夹,Linux的教程放在/linux,以此类推。默认的情况下,orx会查找当前目录下的主配置文件。


为了避免在不同的平台下都有重复的配置文件,我
们创建了一个简单地配置文件包含了父文件夹中配置文件的全部信息。

Let's see how we do this by looking at the
content of 10_StandAlone.ini from one of the sub-folder (ie. one that is
stored in the same folder than the tutorial executable).

让我们通过其中一个子目录(即和教程可执行文件
存储位置相同的文件夹)下的10_StandAlone.ini 的内容看看怎么实现的。

@../10_StandAlone.ini@

That's all we can find
in it. As you can see in the

template files

, we can include other
config files by writing @path/to/FileToInclude@.

所有的内容如上。就像你在
配置语法说明

中看到的,我们可以通过@path/to
/FileToInclude@ 在一个配置文件中包含其他的配置文件。(译注:这里怀疑是作者的问题,template
files实际是想链接到WIKI的配置的说明上去)

Let's now have a look at the config file
which is stored in the parent folder (ie.

../10_StandAlone.ini

).

现在我们看看父文件夹中存储的配置文件(即
../10_StandAlone.ini

link):

First let's define our
display.

首先定义我们的display配置段:

[Display]

ScreenWidth   = 800

ScreenHeight  = 600

Title         = Stand
Alone/Locale Tutorial

As you can see, we're creating a window of
resolution 800×600 and define its title.

如你所见,我们将要创建一个分辨率为
800×600的窗口,并且定义了他的标题。

We now need to provide info for our viewport
and camera.

现在我们要提供视口(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)

Nothing new here as
everything was already covered in the

viewport tutorial

.

与我们在
视口教程

(viewport
tutorial)中提到的没有任何区别。

Let's now see which inputs are defined.

现在看看输入(inputs)是怎么定义的:

[Input]

SetList = MainInput



[MainInput]

KEY_ESCAPE  = Quit

KEY_SPACE   =
CycleLanguage


MOUSE_LEFT  = CycleLanguage

In the Input section, we define all our
input sets. In this tutorial we'll only use one called MainInput but we
can define as many sets as we want (for example, one for the main menu,
one for in-game, etc…).


The MainInput sets contain 3 mapping:

  • KEY_ESCAPE
    will trigger the input named Quit
  • KEY_SPACE
    and MOUSE_LEFT will both trigger the input named CycleLanguage

在Input配置段,我们定义我们所有的输入集
合。本教程中我们只会用到一个叫做MainInput的集合,但我们也定义其他任意想要使用的集合(例如,主菜单一个,游戏中一个,等等)。


MainInput集合包括3个映射:

  • KEY_ESCAPE
    会触发名为Quit的输入
  • KEY_SPACE 和 MOUSE_LEFT 都会触发名为CycleLanguage的输入

We can add as many
inputs we want in this section and bind them to keys, mouse buttons
(including wheel up/down), joystick buttons or even joystick axes.

我们可以在这个配置段加入任意多的输入集合并且
将它们绑定到按键、鼠标按钮(包括滚轮上/下)、游戏摇杆按钮甚至游戏摇杆的方向轴。

Let's now see how we
define languages that will be used by the orxLOCALE module.

现在让我们看看怎么定义将要被
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)

To
define languages for localization we only need to define a Locale
section and define a Language List that will contain all the languages
we need.


After
that we need to define one section per language and for every needed
keys (here Content and Lang) we set their localized text.

为了定义本地化需要的语言我们要定义一个
Locale配置段和一个包含我们所需要全部的语言的列表。

As the localization system in based on orx's
config one, we can use its inheritance capacity for easily adding new
languages to the list (in another extern file, for example), or even for
completing languages that have been partially defined.

由于本地化系统是基于orx配置部分,我们可以
使用它的继承能力来简化把语言加入列表的过程(例如在另一个外部文件中),甚至也可以完善曾经只被部分定义的语言。

Let's now see how we
defined our Logo object.

现在看看我们是怎么定义Logo对象:

[LogoGraphic]

Texture =
../../data/object/orx.png


Pivot   = center



[Logo]

Graphic   =
LogoGraphic


FXList
   = FadeIn # LoopFX # ColorCycle1


Smoothing = true

Again, everything we
can see here is already covered in the

object tutorial

.

又一次,所有的内容我们都已经在
对象教程

(object tutorial)中涵盖了。

If you're curious you
can look directly at

10_StandAlone.ini

to see which kind of
FXs we defined, but we won't cover them in detail here.

如果你对我们定义了哪些FX感到好奇,你可以直
接查看

10_StandAlone.ini

,但是我们不会在这里讨论它们的细节。

 

Next thing to check:
our Legend object.


一个要查看的是:我们的Legend对象:

[Legend]

ChildList = Legend1 # Legend2

Surprise! Actually
it's an empty object that will spawn two child objects: Legend1 and
Legend2.

奇怪吧!其实它只是一个我们由两子对象繁衍出来的空对象。

Code-wise we were
creating a single object called Legend but apparently we'll end up with
more than one object.


The same kind of technique can be used to
generated a whole group of objects, or a complete scenery for example,
without having to create them one by one code-wise.


It's even possible to
chain objects with ChildList and only create a single object in our code
and having hundreds of actual objects created.


However, we won't have
direct pointers on them, which means we won't be able to manipulate
them directly.


That being said, for all non-interactive/background object
it's usually not a problem.


Be also aware that their frames (cf.
frame tutorial

) will reflect the
hierarchy of the ChildList 'chaining'.

通过这样的编码方式,我们创建了一个叫做Legend的单独对象但显然最终将超过一
个对象。同样的技术也可以用来创建一组的对象,或者是完成一个场景,而不是一个一个创建。同样可以将对象通过ChildList串联起来并只在我们的代码
中创建一个单独的对象而同时有数百个对象被创建。


然而我们对它们不会有直接的指针,这意味着我们将不可能直接操作它们。

话虽这么说,对所有非交互/后台对象这却不是一
个问题。


同时
请注意他们的帧(参考:frame tutorial LINK)会影响ChildList ‘串联’的继承。

Ok, now let's get back
to our two object, Legend1 and Legend2.

好了,现在让我们回到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

They
look very basic, they're both using the same FX (ColorCyle2), they both
have a Position and each of them has its own Graphic.

它们看起来很基本,都是用了相同的
FX(ColorCyle2),它们也都有一个位置并且各自有它们的Graphic。

NB: We can also see
that we defined the ParentCamera attribute for both of them. This means
that their actual parent will become the camera and not the Legend
object in the end.


意:我们也可以看到我们为它们定义了ParentCamera属性。这意味着最终它们实际的父对象为Camera而不是Legend对象。

However Legend will
still remain their owner, which means that they'll automatically be
erased when Legend will be deleted.

然而Legend还将是它们的拥有者,这说明它们将会在Legend被销毁时自动被
销毁。

Let's now finish by
having a look at their Graphic objects.

现在让我们看一下它们的Graphic对象作为
结束。

[Legend1Text]

String = $Content



[Legend2Text]

String = $Lang



[Legend1Graphic]

Pivot = center

Text  = Legend1Text



[Legend2Graphic]

Pivot = center

Text  = Legend2Text

We can see that each
Graphic has its own Text attribute: Legend1Text and Legend2Text.


They both have a
different String.


The leading $ character indicates that we won't display a raw
text but that we'll use the content as a key for the localization
system.


So
in the end, the Legend1 object will display the localized string with
the key Content, and Legend2 the one which has the key Lang.

我们可以看到每一个Graphic都有自己的
Text属性:Legend1Text和Legend2Text。


它们都有不同的String字段。(译注:这里的String是指配置)

开头的$字符说明我们不会显示一个原始的文本但
内容作为我们将会把内容作为本地化系统的关键字。


所以在最后,Legend1对象会显示该关键字Content的本地化字符串,Legend2会
显示关键字Lang的本地化字符串。

Everytime
we will switch to another language, both orxTEXT objects (ie.
Legend1Text and Legend2Text) will have their content updated
automagically in the new selected language.



As we saw earlier, we can catch the
orxLOCALE_EVENT_SELECT_LANGUAGE event to do our own specific processing
in addition, if needed.

每一次我们会切换到另一个语言,所有的orxTEXT对象(例如Legend1Text和
Legend2Text)会根据新选择的语言自动更新它们的内容。:)


正如我们早前看到的,如果需要,我们还可以捕获
orxLOCALE_EVENT_SELECT_LANGUAGE事件来进行特定的处理。

Resources

资源

源代码:
10_StandAlone.cpp

配置文件:
10_StandAlone.ini

1)

即不再依靠ORX 启动器

2)

在orx.h中实现

3)

在这种情 况下预编译宏
__orxCPP__ 会被自动定义

4)


这些给出的参数并没有包含我们需要的用来决定主配置文件名的可执行文件的名字

5)


使用WinMain()替代main()

 

阅读全文....

【转】【翻译】Orx官方教程:07.特效(FX)

本文译自
orx tutorials

FX
胡四娃
译最新版本见Orx
官方Wiki中文教程

。转载自:胡四娃的博客
。原文链接在http://www.cppblog.com/Husiwa/archive/2010/07/07/119534.aspx

 

 

综述

这篇教程介绍了什么是特效以及
如何创建它们

特效是将曲线及其组合而成的一组数据(正弦线、三角型边、矩形或者线性),应用在不同类型的参数
中。如:

缩放
、旋转、位置、速度、颜色等。

 

特效在配置文件中设置,仅仅只
需要一行代码就可以在对象上使用这些特效。

可以有最多8条任意类型的曲线组合在一起形成一个特效。

在同一时间,可以有最多4个特
效应用于同一个对象上面。

 

特效可以使用绝对值或者相对值,这取决于配置文件中Absolute标签。

控制曲线的周期、相位、和振幅
都是允许的。

对于位置和速度特效来说,输出值可以使用对象的方向 和/或
缩放值,以相对方式应用于对象目前的状态。

这也就允许我们创造极其拉风的视觉特效。

 

除非特效已经缓存在内存中,否
则特效参数全部在配置文件中进行调整,并且使用退格键来即时重载。 (cf.通过 ''KeepInCache'' 属性来实现内存的缓存).

比如说:你不能调整正在运行的
循环特效,因为他已经在默认的配置文件中定义好了。在这个测试程序运行的时候,所有其它的特效能够被更新。

 

通常说来,随机值的使用可以给
特效带来更多的变化。

比如, 晃动方式的缩放(the wobble scale), 带颜色的闪光(the
flash color) 和 攻击式的移动(the "attack" move) 等特效就使用了少量的随机值。

 

就像显示事件一样,我们也可以
注册特效的开始播放和停止的事件。

因为循环时间是永远不会停下来的,所以对应的停止事件
(''orxFX_EVENT_STOP'')永远不会发生.

 

们也会简单的介绍一下如何一些个性数据(仅仅包
含一个布尔值的结构)添加到orxOBJECT中。((九天注:这里作者有点穿越了,需要看下面的例子才能懂,作者定义了一个仅包含一个Bool值的结构
MyObject))

在事件的回调函数中,我们通过它,在特效开始的时候为对象加锁,在结束的时候解锁。

我们使用锁是为了让
soldier(士兵)在同一时刻只有一个特效在发挥作用。

把这些东西写在这里,仅仅具有教育意义。
((九天注:本来一个对象可以同时有4个特效发
生,这里作者仅仅是告诉你怎么使用“个性数据”才这样做的,所以说仅仅具有教育意义。))


 

 

详细内容

通常,我们先载入配置文件,创
建一个时钟,然后注册更新函数,最后,创建我们的soldier和盒对象。请在之前的教程中获取更多信息。

 

注册 输入和特效事件

 

orxEvent_AddHandler(orxEVENT_TYPE_FX, EventHandler);

orxEvent_AddHandler(orxEVENT_TYPE_INPUT, EventHandler);

 

大家可以看到,在这两个事件中,我们使用了同一个回调函数
(EventHandler).

现在我们迅速的扫一眼自己的“对象”数据结构。

 

typedef
 struct
 MyObject
{
 orxBOOL bLock;

} MyObject;

接下来,看看如何用
orxObject_SetUserData()将它绑定到soldier上

 

MyObject *pstMyObject;
 
pstMyObject = orxMemory_Allocate(sizeof
(MyObject), orxMEMORY_TYPE_MAIN);
pstMyObject->bLock = orxFALSE;
 

orxObject_SetUserData(pstSoldier, pstMyObject);

 

现在看看如何在Update函数中使用特效

 

orxSTRING zSelectedFX;
 
if
(orxInput_IsActive("SelectWobble"
))
{
 zSelectedFX = "WobbleFX"
;
}
else
 if
(orxInput_IsActive("SelectCircle"
))
{
 zSelectedFX = "CircleFX"
;
}
 
[...]
 
// Soldier not locked?

if
(!((MyObject *)orxObject_GetUserData(pstSoldier))->bLock)
{
 if
(orxInput_IsActive("ApplyFX"
) && orxInput_HasNewStatus("ApplyFX"
))
 {
   orxObject_AddFX(pstSoldier, zSelectedFX);
 }

}

 

可以看到,我们通过orxObject_GetUserData()这个函数得到了
我们想要的数据,向solder里添加特效的方法跟添加声音的方法如出一辙,用的都是这个函数orxObject_AddFX()。

 

接下来,看看EventHandler这个函数

首先是输入方面,这里只展示了每次输入时哪个按
键被使用了。

 

if
(_pstEvent->eType == orxEVENT_TYPE_INPUT)
{
 if
(_pstEvent->eID == orxINPUT_EVENT_ON)
 {
   orxINPUT_EVENT_PAYLOAD *pstPayload;
 
   pstPayload = (orxINPUT_EVENT_PAYLOAD *)_pstEvent->pstPayload;
 
   if
(pstPayload->aeType[1
] != orxINPUT_TYPE_NONE)
   {
     orxLOG("[
%s
] triggered by '
%s
' + '
%s
'."
, pstPayload->zInputName, orxInput_GetBindingName(pstPayload->aeType[0
], pstPayload->aeID[0
]), orxInput_GetBindingName(pstPayload->aeType[1
], pstPayload->aeID[1
]));
   }
   else

   {
     orxLOG("[
%s
] triggered by '
%s
'."
, pstPayload->zInputName, orxInput_GetBindingName(pstPayload->aeType[0
], pstPayload->aeID[0
]));
   }
 }

}

 

正如你所见,我们通过按下的是一个单键还是一个组合键来判断展示不同的信息。

我们仅使用了两个首次输入点,因为我们知道,我
们的配置文件中没有超过两个的组合键。尽管orx支持最多四个组合键来做为一个单键。

 

orxInput_GetBindingName()
函数给了我们一个输入的文字显示。

注意:这些名称在配置文件中也绑定到了对应的按键上面。

现在来看下如何处理这个事件

 

if
(_pstEvent->eType == orxEVENT_TYPE_FX)
{
 orxFX_EVENT_PAYLOAD *pstPayload;
 orxOBJECT           *pstObject;
 
 pstPayload = _pstEvent->pstPayload;
 pstObject  = orxOBJECT(_pstEvent->hRecipient);
 
 switch
(_pstEvent->eID)
 {
   case
 orxFX_EVENT_START:
     orxLOG("FX <
%s
>@<
%s
> has started!"
, pstPayload->zFXName, orxObject_GetName(pstObject));
 
     if
(pstObject == pstSoldier)
     {
       // Locks it

       ((MyObject *)orxObject_GetUserData(pstObject))->bLock = orxTRUE;
     }
     break
;
 
   case
 orxSOUND_EVENT_STOP:
     orxLOG("FX <
%s
>@<
%s
> has stoped!"
, pstPayload->zFXName, orxObject_GetName(pstObject));
 
     if
(pstObject == pstSoldier)
     {
       // Unlocks it

       ((MyObject *)orxObject_GetUserData(pstObject))->bLock = orxFALSE;
     }
     break
;
 }
}

在soldier上的动画开始
的时候,我们用自己的数据结构来锁定它,相应的,停止的时候解锁。

 

看完了代码部分,我们再去看看配置文件。

首先看个简单的特效
:盒子上旋转的特效。

 

[RotateLoopFX]

SlotList  =
 Rotate
Loop      =
 true
 
[Rotate]

Type        =
 rotation
StartTime   =
 0.0
EndTime     =
 2.0
Curve       =
 sine
Pow         =
 2.0
StartValue  =
 0
EndValue    =
 360
 
[Box]

FXList =
 RotateLoopFX

 

看到了吧,特效是在它创建之初
直接应用在盒对象上面的,而不是在代码中。

RotateLoopFX包含仅包含一个时间段(Rotate)并且一直循环
(attribute Loop)

然后定义Rotates时间段。时间的单位都是秒,角度的单位都是度。

定义这个旋转动画的时候,我们使用了一个正弦曲
线,让他每两秒旋转360度。

 

下面看下我们的摇摆特效。

 

[WobbleFX]

SlotList =
 Wobble
 
[Wobble]

Type          =
 scale
StartTime     =
 0.0
EndTime       =
 1.0
Period        =
 0.2
Curve         =
 sine
Amplification =
 0.0
StartValue    =
 (1.0, 1.0, 1.0)

EndValue      =
 (2.0, 2.0, 1.0) ~ (6.0, 6.0, 1.0)

 

我们修改了scale属性,并赋予它一个
''StartValue''(开始值)和''EndValue''(结束值)。

他们都是用向量来表示的,如果不想使用任何
各向异性

的值(译者注:专业名
词anisotropic

(各向异性)去知道确切意思)的话,也可是使用
float类型来表示。

虽然看起来我们正在使用一个
isotropic(各向同性

)
((Z值不影响2D元素))的值,这个EndValue也 不过是一个随机值。

也就是说,它的X和Y部分可能是完全统统的随机值!

除此之外,我们使用了一个简单的周期为0.2秒
的正弦曲线,它将会播放1秒钟。

 

看到了吧,我们将Amplification(增幅)
的值设为0,这就是说,随着时间的推进,曲线的振幅会逐渐变低。

注意:默认的Amplification是1,表示不随时间变化,保持稳定,当值大于1时,振幅
就会加大;当值小于1时,振幅就会减少。

 

看看圆是如何运动的。

 

[CircleFX]

SlotList        =
 CircleX#CircleY
KeepInCache     =
 true
 
[CircleX]

Type            =
 position
StartTime       =
 0.0
EndTime         =
 1.0
Curve           =
 sine
StartValue      =
 (0.0, 0.0, 0.0)
EndValue        =
 (-50.0, 0.0, 0.0)
UseOrientation  =
 true
UseScale        =
 true
 
[CircleY@CircleX]

Phase       =
 0.25
StartValue  =
 (0.0, -25.0, 0.0)
EndValue    =
 (0.0, 25.0, 0.0)

我们使用两个时间段来控制它的位置,这样才能做
出一个圆形的运动。第一个时间段是CircleX,他将会应用在对象的X轴向的振幅。第二个时间段CircleY,会产生一个同样幅度的作用效果在Y轴
上。

如果我们不更改CircleY的相位,是不会发
生圆形的运动。

 

现在假设一个正弦曲线,在初始值
(''StartValue'')是相位0,准备增加

在相位0。25的时候,到达中间点,将会继续增加

在相位0.5的时候,到达最高值
(''EndValue''),准备下降


相位0.75的时候,回到中间点,继续下降

在相位1.0的时候,就跟相位0(''StartValue'')是一样的了

注意:这段描述正弦曲线的工作过程也同样适用于
三角形,但是却不适用于线形。


们将略过大多数其他的特效,因为那里没有什么我们不知道的新知识了。

 

但是我们还是要迅速的看一眼翻转的特效,他将会向我们展示如何翻转一个对象。就像Paper
Mario Wii((九天注:Wii上的[[wp>Paper
Mario|纸片马里奥]]是个很出名的游戏,作者的意思就是这里的flip描述的就是那个游戏里面的风格和效果))的风格.

 

[FlipFX]

SlotList =
 Flip
 
[Flip@Wobble]

EndTime       =
 0.5
Period        =
 1.0
Amplification =
 1.0

EndValue      =
 (-1.0, 1.0, 1.0)

 

看到了吧,我们很简单的使用负值完成了这个效果。

同时也注意到,我们给Period(周期)设了一个明确的值。

我们选了一个两倍于定义的正弦曲线的
Period,这样我们就只使用了正弦曲线的上升的那一半。同时,我们也将Amplification改 回了1。(在”“Wobble”“中被设为0)

 

资源

源代码:
07_FX.c

配置文件:
07_FX.ini

阅读全文....

【转】【翻译】Orx官方教程:05.视口与摄像机 (viewport & camera)

本文译自 orx tutorials 视口与摄像机
(viewport & camera)


落后的簔羽鹤译。最新版本见Orx 官方中文Wiki

本文转自落后的簔羽鹤的博客
。原文链接在:http://blog.csdn.net/wind2006/archive/2010/07/07/5717831.aspx
。望有新人能够加入这个翻译者的队伍,早日将Orx的WIKI页中文化。有兴趣的请加入qq群73063577,并与我取得联系,防止重复翻译。

 

综述

请阅读前面的基本教程
basic object creation(基本类创建),clock handling(时钟) ,fremes hierarchy(层次结构) 和
animations(动画)。

此教程显示了如何使用有多个摄像机的多视口技术。教程中将同时创建4个视口。

分别为左上角的(Viewport1),右下角的(Viewport4),它们共用一个摄像机
(Camera1),实现此功能,只需要在配置文件中配置2个视口的Camera属性,为同一个(也就是Camera1)。当我们使用鼠标的左右键旋转摄
像机(Camera1),left Control或left
Shift键+方向键进行摄像机的缩放操作,关联的两个Viewport1和Viewport4将相应的发生变化。

右上角视口(Viewport2)是基于另一个摄像机(Camrea2),此摄像机的视锥较第一
个窄,所以显示时比例是其的两倍大。在教程的程序中,我们不能通过任何操作设置此视口。

最后一个视口(Viewport3)是基于Camera3的,Camera3的配置与
Camera1完全一样。

NB:当两个视口重叠,较先创建的将显示在顶层。

最后,有一个固定不动的箱子和一个世界坐标随着鼠标实时移动的小兵,也就是说无论如何设置视口的
摄像机,无论鼠标在那个视口上移动,小兵在它所属的视口中,相对于鼠标在在屏幕中的位置移动。

在配置文件中使用随机关键字符‘~’,使的视口和基本对象的颜色和大小可以随机创建。

NB:摄像机将它的坐标/缩放尺度/旋转存放在
orxFRAME
结构中,在[[frame|frame]]教程中我们看到他们是orxFrame继承体系的一部分。另一方面Object应该置于其Camera所关联的
Viewport中。

详细说明


  通常我们需要首先载入配置文件,创建时钟和注册回调的Update函数,最后创建主要的Object信息。关于实现的详情,请联系前面的教程。


  虽然这次我们创建了4个视口,却没有什么新东西,仅仅是以下4行代码。

 

pstViewport =
orxViewport_CreateFromConfig("Viewport1");

orxViewport_CreateFromConfig("Viewport2");

orxViewport_CreateFromConfig("Viewport3");

orxViewport_CreateFromConfig("Viewport4");

 

正如你所看到的,我们只使用了
Viewport1的引用,以便后面进行操作。

让我们直接跳到Update函数的代码。

首先我们通过捕捉鼠标的坐标,
设置士兵的位置。我们已经在frame
tutorial里实现过了。这里我们做了一样的事情,但在4个视口中工作的都很完美。当鼠标离开视口时,世界坐标的指针,将被orxNull值所代替,
也就不会触发士兵的移动了。

orxVECTOR vPos;

 

if(orxRender_GetWorldPosition(orxMouse_GetPosition(&vPos),
&vPos) != orxNULL)

{

 orxVECTOR
vSoldierPos;

 


 orxObject_GetWorldPosition(pstSoldier, &vSoldierPos);

 vPos.fZ =
vSoldierPos.fZ;

 

 orxObject_SetPosition(pstSoldier,
&vPos);

}

在操作视口之前,我们先关注下视口所关联的摄像机,我们可以移动,旋转和缩放它。获
取摄像机的代码如下所示:

pstCamera =
orxViewport_GetCamera(pstViewport);

非常简单。让我们实现旋转。

((其他方向仅仅只有部分代码,但是逻辑是一样的)).

if(orxInput_IsActive("CameraRotateLeft"))

{


 orxCamera_SetRotation(pstCamera, orxCamera_GetRotation(pstCamera) +
orx2F(-4.0f) * _pstClockInfo->fDT);

}

我们再次看到旋转的角度时间并
不依赖于FPS而且可以做时间的伸缩控制(译者注:比代码依然很简单。

现在让们来看看视口的数据配置情况。如慢动作)
 因为用的是时钟的DT。


们再次看到旋转的角度时间并不依赖于FPS而是时钟的DT。我们也可以通过设置System这个配置选项来设置旋转速度,而不是使用硬编码。

实现缩放如下:

if(orxInput_IsActive("CameraZoomIn"))

{


 orxCamera_SetZoom(pstCamera, orxCamera_GetZoom(pstCamera) *
orx2F(1.02f));

}

 

因为这个代码没有使用时钟信息,所以他将会被时钟频率和帧率所影响。

最后让我们移动摄像机。

orxCamera_GetPosition(pstCamera,
&vPos);

 

if(orxInput_IsActive("CameraRight"))

{

 vPos.fX +=
orx2F(500) * _pstClockInfo->fDT;

}

 

orxCamera_SetPosition(pstCamera,
&vPos);


了,与摄像机有关的先到这里吧。

在下面的配置中我们将看到,同一个摄像机被连接到两个不同的视口。操作摄像机将同时
影响两个视口。

我们可以直接修改视口的位置和尺寸,如下所示:

orxFLOAT
fWidth, fHeight, fX, fY;

 

orxViewport_GetRelativeSize(pstViewport,
&fWidth, &fHeight);

 

if(orxInput_IsActive("ViewportScaleUp"))

{

 fWidth *=
orx2F(1.02f);

 fHeight*= orx2F(1.02f);

}

 

orxViewport_SetRelativeSize(pstViewport,
fWidth, fHeight);

 

orxViewport_GetPosition(pstViewport,
&fX, &fY);

 

if(orxInput_IsActive("ViewportRight"))

{

 fX +=
orx2F(500) * _pstClockInfo->fDT;

}

 

orxViewport_SetPosition(pstViewport,
fX, fY);

 

如上 所示,没有什么惊奇的,非常简单。

让我们来接着看看
viewport的配置方面的东西。

 

[Viewport1]

Camera
           = Camera1

RelativeSize      = (0.5, 0.5, 0.0)

RelativePosition
 = top left

BackgroundColor   = (0, 100, 0) ~ (0, 255, 0)

 

[Viewport2]

Camera
           = Camera2

RelativeSize      = @Viewport1

RelativePosition
 = top right

BackgroundColor   = (100, 0, 0) ~ (255, 0, 0)

 

[Viewport3]

Camera
           = Camera3

RelativeSize      = @Viewport1

RelativePosition
 = bottom left

BackgroundColor   = (0, 0, 100) ~ (0, 0, 255)

 

[Viewport4]

Camera
           = @Viewport1

RelativeSize      = @Viewport1

RelativePosition
 = bottom right

BackgroundColor   = (255, 255, 0)#(0, 255,
255)#(255, 0, 255)

 

一共有3个摄像机,它们关联了4个视口,其中Camera1关联了
Viewport1和Viewport4。

我们注意到Viewport1的配置文件中relativeSize设置为
(0.5,0.5,0).它代表的意思在x轴和y轴方向上分别使用一半的显示尺寸(z轴被忽略)。也就是说,任何一个视口实际上显示部分的内容是可调的,
可以是全屏或者非全屏。

接下来我们注意到其他视口的RelativeSize属性被设置成@Viewport1。它的意
思是RelativeSize属性继承Viewport1的RelativeSize属性,也就是说它们的RelativeSize属性和
Viewport1的RelativeSize属性一样。我们也可以看到Viewport4的Camera属性被设置成@Viewport1,表明它继承
自Viewport1的摄像机。

为了避免视口在屏幕中互相重叠遮盖,我们可以设置RelativePosition属性为常量字
符或者使用vector(向量)设置它们的合理位置。

最后前三个视口使用随机的红色作为背景颜色,设置如下:

BackgroundColor
= (200, 0, 0) ~ (255, 0, 0)

如果我们希望通过准确的随机颜色进行设置,可以使用一下列表的形式设置,随机的颜色
分别为黄、青和品红,设置如下:

BackgroundColor = (255, 255, 0)#(0, 255,
255)#(255, 0, 255)

这种使用方式是相当于在三个颜色(黄色,蓝绿色,品红)中进行随机。

最后让我们关注摄像机的设置。

[Camera1]

FrustumWidth
 = @Display.ScreenWidth

FrustumHeight = @Display.ScreenHeight

FrustumFar
   = 1.0

FrustumNear   = 0.0

Position
     = (0.0, 0.0, -1.0)

 

[Camera2]

FrustumWidth
 = 400.0

FrustumHeight = 300.0

FrustumFar
   = 1.0

FrustumNear   = 0.0

Position
     = (0.0, 0.0, -1.0)

 

[Camera3@Camera1]


基本属性frustum(视
锥),被摄像机所拍摄的世界空间的一部分,将被映射到视口显示。

NB:使用2D摄像机视锥的形状是
长方体

我们可以发现Camera3完
全继承自Camera1,它没有覆盖Camera1的任何属性。

NB:使用完全继承所有属性可以写成:
[MySection@ParentSection]。

为什么实用两个不同的摄像头呢?仅仅因为可以有
两个不同的物理实体(physical entities):我们在代码中修改了Camera1的属性,而 Camara3将保持不变。

我们注意到Camera1的
FrustumWidth和FrustumHeight属性继承自Display的屏幕设置。

NB: 当继承某个属性,可以写成MyKey =
@ParentSection.ParentKey.当两个key一样时,其中父选关键字可以省略如:SameKey =
@ParentSection.

最后我们注意到Camera2具有较小的视锥。

也就是说Camera2只能看
到世界空间的较小部分。所以视口看起来具有了放大的效果。

 

资源

源代码: 
05_Viewport.c

配置文件

: 
05_Viewport.ini

1) very useful
for making HUD & UI, for example

在HUD和UI中很有用

2) 
其他方向仅仅只有部分代码,但是逻辑是一样的

3) composed of
keywords top, bottom, center, right and left

由关键字
top,bottom,center,right和left组成

4) the '~' character is used as a
random operator between two numeric values

'~'
字符被用在两个数字之间,作为随机操作符

阅读全文....

【转】【翻译】Orx官方教程:4.(anim)动画

本文译自 orx tutorials 的动画(Anim
)
。胡四娃译。最新版本见Orx 官方中文Wiki

本文转自胡四娃的博客
。原文链接在:http://www.cppblog.com/Husiwa/archive/2010/07/05/119366.html
望有新人能够加入这个翻译者的队伍,早日将Orx的WIKI页中文化。有兴趣的请加入qq群73063577,并与我取得联系,防止重复翻译。

 

 

综述

这篇教程只涉及了orx中最基本的动画使
用。

更多关于动画的东西在这里 猛击我.


图定义了动
画间所有可能的切换方式。动画通过一个唯一的字符串来引用。所有的切换和动画都是通过配置文件来创建的。
当一个动画被请求的时候,引擎会计算从当
前动画到请求动画之间的链路
如果这个链路存在,它会自动执行。用户将通过事件被告知动画何时开始、停止、删节或者循环。
如果我们不能具体
制定任何目标动画,引擎就会很自然的沿着属性中定义的线路(走下去)。
也有一个方法来越过这个寻路过程并且迅速的指向一个动画。

详细内容


通常,我们先载入config
file(配置文件),创建一个viewport,创建一个clock(时钟)并且注册Update(更新)函数,最后创建一个主对象。
请从之前
的教程中获得更多的信息。

现在我们开始从代码入手,我们将会从本页的底部看到数据是如何组织的。
在Update函数中,当输入
GoLeft激活的时候会触发WalkLeft动画;GoRight激活的时候会触发WalkRight函数.
当没有激活态的输入时,我们会移除
目标动画,让这个图保持一个自然的状态

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


if
(orxInput_IsActive("GoRight"
))
{
  orxObject_SetTargetAnim(pstSoldier, "WalkRight"
);
}
else
 if
(orxInput_IsActive("GoLeft"
))
{
  orxObject_SetTargetAnim(pstSoldier, "WalkLeft"
);
}
else

{
  orxObject_SetTargetAnim(pstSoldier, orxNULL);
}

 

就是这样!如何从任意当前动画切换到目标动画将会通过这个矢量图来计算。如果需要切换,他们将会自动播放。
注意:有很多的函数可以用高级的方法来控制动画,但是99%的时候,这两个函数是最常用的
(orxObject_SetCurrentAnim() 和 orxObject_SetTargetAnim())。




我们来看一下,动画是如何通知我们发生了什么的(比如,就像同步语音一样)。
首先,我们要向动画事件注册回调函数。

 

orxEvent_AddHandler(orxEVENT_TYPE_ANIM, EventHandler);

 

好了!让我们看下现在可以做什么了。
我们说我们想要打印出对象中哪个动画被播放、停止、剪切或者循环。需要写一下的回调函数。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


orxSTATUS orxFASTCALL EventHandler(const
 orxEVENT *_pstEvent)
{
orxANIM_EVENT_PAYLOAD *pstPayload;
 
pstPayload = (orxANIM_EVENT_PAYLOAD *)_pstEvent->pstPayload;
 
switch
(_pstEvent->eID)
{
  case
 orxANIM_EVENT_START:
    orxLOG("Animation <
%s
>@<
%s
> has started!"
, pstPayload->zAnimName, orxObject_GetName(orxOBJECT(_pstEvent->hRecipient)));
    break
;
 
  case
 orxANIM_EVENT_STOP:
    orxLOG("Animation <
%s
>@<
%s
> has stoped!"
, pstPayload->zAnimName, orxObject_GetName(orxOBJECT(_pstEvent->hRecipient)));
    break
;
 
  case
 orxANIM_EVENT_CUT:
    orxLOG("Animation <
%s
>@<
%s
> has been cut!"
, pstPayload->zAnimName, orxObject_GetName(orxOBJECT(_pstEvent->hRecipient)));
    break
;
 
  case
 orxANIM_EVENT_LOOP:
    orxLOG("Animation <
%s
>@<
%s
> has looped!"
, pstPayload->zAnimName, orxObject_GetName(orxOBJECT(_pstEvent->hRecipient)));
    break
;
  }
 
  return
 orxSTATUS_SUCCESS;
}

 

先得到了事件的payload指针,因为我们只是在这里传递动画事件,所以我们可以安全的将payload
转化为orxANIM_EVENT_PAYLOAD类型,它在 orxAnim.h中定义。
如果我们在不同的事件(译者注:原文是even
根据上下文推断是作者拼写错误)类型中调用了同一个回调函数,我们首先将会查看是否得到了一个动画事件,可以这样做:

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html

if
(_pstEvent->eType == orxEVENT_TYPE_ANIM)

 

最后,事件接收者(_pstEvent→hRecipient)通常是播放动画的那个对象。将其用宏orxOBJECT()来转化为orOBJECT类型
的对象。

现在让我们来看一眼数据方面的东西吧。
首先,我们需要定义一个动画集,它将会包含指定对象的动画的整个矢量图。

画集在不会再内存中重复,并且它与矢量图相对应的多有动画和链路。
在上面这个例子中,我们又4个动画和10条可以用来切换的链路。

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[AnimSet]

AnimationList =
 IdleRight#WalkRight#IdleLeft#WalkLeft

LinkList =
 IdleRightLoop#IdleRight2Left#IdleRight2WalkRight#WalkRightLoop#WalkRight2IdleRight#IdleLeftLoop#IdleLeft2Right#IdleLeft2WalkLeft#WalkLeftLoop#WalkLeft2IdleLeft

 

 

现在我们来开始定义动画!
在这之前,为了减少文章篇幅,我们将要使用orx 配置文件的集成特性。
先锚点的位置定义一项。
也许你
可能在对象教程中看到了锚点的相关知识,锚点的位置信息将会匹配世界中的对象。如果没有确定的话,将会把左上角做为默认值。
锚点可以通过语义关键
字来确定,如: top, bottom, center, left and right也可以通过实际的值来确定。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[Pivot]

Pivot =
 (15.0, 31.0, 0.0)

 

现在,我们来定义从锚点继承过来的图像对象。在我们这个例子中,它是一个位图,,包含了对象中所有的帧。因此基本的属性就是
位图文件的名字和一帧的大小。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[FullGraphic@Pivot]

Texture     =
 ../../data/anim/soldier_full.png
TextureSize =
 (32, 32, 0)

 

创建帧的准备工作都做好了。
让我们定义所有都是right-oriented的动画。一共6个。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[AnimRight1@FullGraphic]

TextureCorner =
 (0, 0, 0)

[AnimRight2@FullGraphic]

TextureCorner =
 (0, 32, 0)

[AnimRight3@FullGraphic]

TextureCorner =
 (0, 64, 0)

[AnimRight4@FullGraphic]

TextureCorner =
 (32, 0, 0)

[AnimRight5@FullGraphic]

TextureCorner =
 (32, 32, 0)

[AnimRight6@FullGraphic]

TextureCorner =
 (32, 64, 0)

 

看到了吧,他们全都继承于FullGraphic,唯一能区分他们的属性就是TextureCorner.
好,我们已经定义完了所有的图形对象(他们载入的时候会转变为orxGraphic结构),下面定义动画本身。让我们从ideright动画开始说起,它
包含一个单帧并持续0.1秒。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[IdleRight]

KeyData1      =
 AnimRight6
KeyDuration1  =
 0.1

 

太简单了,来尝试下第二个:

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[WalkRight]

DefaultKeyDuration  =
 0.1
KeyData1            =
 AnimRight1
KeyData2            =
 AnimRight2
KeyData3            =
 AnimRight3
KeyData4            =
 AnimRight4
KeyData5            =
 AnimRight5
KeyData6            =
 AnimRight6

 

当我们使用DefaultKeyDuration属性同时为所有的帧定义时并不是很难。我们可以像idleright动画中所做的那样,通过一个确定的键
值来覆盖任意一帧。我们如法炮制做出left-oriented动画。通常我们使用翻转图形对象时,我们将会在代码运行中做这件事。但是那不是我们的目
的!让我们来用与前面那个完全不同的方法来实现它!只有链路没有提到了让我们添上它。基本的链路结构非常简单,我们指定源动画和目的动画。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[IdleRightLoop]

Source      =
 IdleRight
Destination =
 IdleRight

 

这里,我们有跟之前一样的基本信息,但是多了一个immediate属性做为键值。这就是说,当我们处于IdleRight动画时,并且目标是
WalkRight,我们不必等到IdleRight完成,将直接完成这个动作,这就给了我们一个剪切动画的方法。
正如在代码中看到的一样。当我们已经开始行走的时候,没有显式的调用空闲动画,这是怎么做到的?看下从WalkRight到IdleRight的链路。

 

E:/MyProgram/ClipboardHighlighterVersion0.2/Untitled.html


[IdleRight2WalkRight]

Source      =
 IdleRight
Destination =
 WalkRight
Property    =
 immediate

 

 

当我们再WalkRight状态并且移除了目标动画,引擎不得按照自然的路线走下去。这个意思是说,它会选
取高优先级的链路。默认的优先级是8,它的范围是0到15.在这里,优先级是9,也就是说当我们没有目标的时候,就会选取它。它将会带我们回到
IdleRight状态。这里也加了immdiate属性,这样,我们就不必等“走”这个循环完事再回到“空闲”
 
注意:这只是
一个非常基本的图,用来阐述基本的动画切换过程,但是这个系统的扩展性很高。比如假设这样一个场景:你想从坐的状态变为走的状态,中间没有别的过度。随着
游戏的开发,你可能觉得在这两个状态间加一个站立的状态会比较好。这时,你只需要再配置文件中添加这多出来的一步,而整个代码文件都不用更改。

资源:


源文件: 
04_Anim.c



配置文件: 
04_Anim.ini

阅读全文....

【转】【翻译】Orx官方教程:1. object

本文译自
orx tutorials


象(object)

phpxer

译,九天雁翎 (

)修订。最新版本见Orx
官方中文Wiki

本文转自phpxer的博客

。原文链接在:http://blog.feihoo.com/2010/07/orx_tutorial_cn_object.html

 

望有新人能够加入这个翻译者的队伍,早日将Orx的WIKI页中文化。有兴趣的请加入qq群73063577,并与我取得联系,防止重复翻译。

Object (对象)教程

总结

由于orx是数据驱动的,我们只需要两行代码创建一个viewport(视口)和一个object。它们的所有属性都定义在配置文件
(01_Object.ini)中。

Viewport关联到一个按照配置文件中的信息隐含创建的camera(摄像头)。在配置文件里,你还可以设置它们的大小,坐标,对象的颜色,缩
放,旋转,动画,物理属性等等。你甚至无需增加一行代码就可以让任何的配置获得随机值。

在后面的一个示例中我们将看到如何使用一行代码生成复杂的object体系甚至整个 scene(场景)(所有的背景对象和普通对象)。

现在,你可以尝试取消01_Object.ini中某些行的注释,自己尝试一下,然后再继续学习这个教程。完整的选项列表请查看
CreationTemplate.ini。

详细说明

创建一个object是相当简单的。不过,我们首先需确保已经加载了定义了所有object(对象)的属性的配置文件。我们还要通过
viewport/camera组合显示创建好的object(对象)。

不要慌张!所有这些都很容易。

在这篇教程中,我们将加载一个位于父目录中的配置文件。正如你可能想到的,在所有的可执行程序都根据其构建类别(mingw, msvs2005,
msvs2008, 等)位于各自的子目录的情况下,我们不打算在每个地方重复同样的配置文件。1)

在我们的例子中,加载配置文件使用类似下面这行代码的方式实现:

orxConfig_Load(”../01_Object.ini”);

然后我们创建viewport(视口)。注意 camera的创建是按照为这个viewport预置的配置信息自动完成的。

orxViewport_CreateFromConfig(”Viewport”);

我们差不多完成了。现在我们只需要创建 object!

orxObject_CreateFromConfig(”Object”);

就这样了!object(对象)已经创建,并且由于在camera的视觉平截体(frustum)内,将会被显示出来。

现在,因为我们使用Orx默认的启动器,我们需要申明我们的插件入口点(这里是我们的Init函数)。这可以使用一个宏很容易地实现。

orxSTATUS Init(){...}

orxPLUGIN_DECLARE_ENTRY_POINT(Init);

因为orx是数据驱动的,我们不需要手动加载任何数据,例如一个sprite(精灵)。一切都由数据管理器为我们搞定,它会确保sprites不在
内存中重复并在其不再使用时自动释放的

如果你查看配置文件,在[Object]这一节,你将看到你可以设定所有的对象属性,例如 graphic
(sprite),锚点,颜色,透明度,物理属性,坐标,旋转,缩放,tiling(平铺)(重复),动画,视觉特效,等等。

不要担心,这一切都将在后面的教程中讲到。

现在我们拥有了一个object(对象),我们需要学习如何与之交互。这将我们带入第二个教程:clock.

资源

  • 源代码: 01_Object.c
  • 配置文件: 01_Object.ini

1) 不过,如果你的配置文件名字与可执行文件匹配并且在同一个文件夹下,它将被自动加载。

阅读全文....

【转】【翻译】Orx官方教程:0.基础(Basic)

本文译自
orx tutorials


页(main)

phpxer
译,九天雁翎 (

)修订。最新版本见Orx
官方Wiki中文教程

。转载自:phpxer的博客
。原文链接在http://blog.feihoo.com/2010/07/orx_tutorial_cn_basic.html

希望有新人能够加入这个翻译者的队伍,早日将Orx的WIKI页中文化。有兴趣的请加入qq群73063577,并与我取得联系,防止重复翻译。

教程

本教程主要包含Orx的基础和
高级教程。Orx 是一个开源、跨平台、轻量级、数据驱动的2D游戏引擎。

安装

这些教程演示了如何设置不同的
编程环境(IDE)

来运行
orx

1)

基础

本节将要介绍orx的基础知
识。

你可以从
这里

下载Windows(mingw,
msvs2005 & msvs2008). Linux 和 MacOS X下的

可执行文件
(包括项目文件,数据和源码)。

前九个基础教程(#1 –
#9)使用默认的orx启动程序为

基础
(underlying
layer),这样易于快速测试/制作原型

2

它们被编译成运行时加载(在命
令行

3)

或配置文件中指定它们的名字)的动态连接库。

此外,下面的内容

4)


解释了哪些行为是由默认的orx.exe/orx 启动程序提供的。

这是一个基础的C教程。

由于我们在本教程中使用默认的可执行文件,下面
的代码将以插件的方式加载和执行。

另外,一些
基础设施

主执行文件
为我们处理。

首先,它会加载所有可用的插件和模块。如果你只
需要其中的一些,最好编写你自己的

可执行文件
而不是插件。这部分包含在
后面的教程

中。

主执行文件还处理下面这些
键盘输入

* F11 是
纵向对齐切换

* Escape 退出

* F12 截屏

* 退格键(Backspace)
重新载入全部配置文件

如果有
orxSYSTEM_EVENT_CLOSE事件发生,程序也会退出。

不过,如果使用
orx作为传统库构建你自己的可执行文件当然也是可以的(也很容易做到)。在

教程 #10

(使用C++编写) 和
教程 #11

(使用 C编写)。
教程 #10

还演示了如何使用orx编写C++代码
5)

同样地,你可以用任何可与C连接的语言编写程序。

在将来的发布中将会为某些常见
语言提供封装。如果你想编写这种封装库,为orx做贡献,请通过

论坛

联系我们。

当前提供的基础教程列表:

  1. [C]

    object
  2. [C]

    clock
  3. [C]

    frame
  4. [C]

    animation
  5. [C]

    viewport &
    camera

  6. [C]

    sound & music
  7. [C]

    fx
  8. [C]

    physics
  9. [C]

    scrolling
  10. [C++]

    stand alone &
    localization

  11. [C]

    spawner &
    shader

社区

下面这些教程由社区创建,它们
是了解如何使用 orx的不错的资源,可以在这里寻找到对一些简单问题的解答。

1)

所有的IDE都是免费可以从英特网上下载的。

2)

one line for the
whole initialization, no main function to write, no loop to handle


用一行代码完成初始化,不需要写main函数,
没有

循环

处理


3)

另提供了 .bat/.sh
脚本方便启动所有示例


4)


你将在在所有教程的源文件的开始处看到这些内容


5)

Orx本身使用C编写

阅读全文....

站在巨人的肩膀上开发游戏(4) -- 做一个打砖块游戏

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

    虽然很早就想用做一个完整游戏来完成此教程,但是在做什么游戏的问题上很纠结,太大太好的游戏太费精力,太小的游戏又不足以展示Orx的特点,选来选去也没有自己感觉最合适的,最后还是选择打砖块吧,此游戏虽然不能展示Orx的全部特点,但是很好的展示了其内嵌物理引擎的特点。因为Orx内嵌Box2D物理引擎,所以在游戏中使用物理,从来没有这么方便过,也许,哪天我该写一篇用Cocos2D+Box2D的类似文章来做比较。

Orx 中的Object概述

    在Orx中一个Object到底表示什么?简单的说,表示一切。一切有形的无形的,可见的不可见的东西。在Orx中,所有所有的概念全部归结于 Object。所有其他的东西,都是Object的属性。包括通常概念里面的sprite,animation等等,在Orx中还包括特效(fx),物理属性等。在几乎所有的2D游戏引擎中,几乎都是是Sprite为基础的,而在Orx中,是以Object为基础的。

显示一个 Object

    在几乎所有的2D游戏引擎中,几乎都是是Sprite为基础的,所以最基本的操作都是显示一个Sprite,那么,换到Orx中,最基础的那就是显示一个 Object了。
    其实,在原来《站在巨人的肩膀上开发游戏(2) -- Orx入门引导及Hello World》中,我们已经显示过一个 Object了,没错,那个Hello World的文字就是一个Object.........只不过其图形是显示文字而已。所以,我们创建Hello World的时候,调用的接口是orxObject_CreateFromConfig
    要将其换成显示图形,只需要改配置,将其显示成一个图形即可,因为是做打砖块游戏,这里,我显示一个球。(这里的资源全部来自于《How To Create A Breakout Game with Box2D and Cocos2D Tutorial》)顺便可以将Orx版本的程序与Cocos2D + Box2D(另外一个我非常喜欢的组合)做比较。
    原代码的改动仅出于代码可读性考虑,将HelloWorld改为Ball,Orx的特点之一,不改代码,你甚至可以使用原来编译好的Hello World程序(必须是教程1老的那个,教程2新的那个我做了特殊处理),只需要将新的配置中的Ball改为HelloWorld即可。当然,出于可读性,这样做不自然,但是我还是提及这样做的可能性。
新添加配置如下:
[Ball]
Graphic   = BallGraphic
Position  = (0.0, 0.0, 0.0)    ;球所在的位置

[BallGraphic]
Texture = data/ball.png    ;球图形的png文件的位置
Pivot   = center   

原来的代码如下:

// Init game function
orxSTATUS GameApp::InitGame()
{
  orxSTATUS result = orxSTATUS_SUCCESS;

  // Creates viewport
  if ( orxViewport_CreateFromConfig("Viewport") == NULL ) {
      result = orxSTATUS_FAILURE;
  }

  if (orxObject_CreateFromConfig("Ball") == NULL) {
      result = orxSTATUS_FAILURE;
  }

  // Done!
  return result;
}

然后,就能显示出个球了。(显示个球-_-!)

就这么一个Object显示出来以后,就可以继续自由发挥了,很多的想象空间。
比如Scale     = XXX调整球的大小。
比如Speed     = (xxx, xxx, xxx) 给球初始速度,
(上面的属性都添加到 [Ball]段)

按照上面的方法,按打砖块游戏的特点,添加砖块及paddle。
配置:
[Ball]
Graphic   = BallGraphic
Position  = (0.0, 180.0, 0.0)

[BallGraphic]
Texture = data/ball.png
Pivot   = center

[Paddle]
Graphic   = PaddleGraphic
Position  = (0.0, 230.0, 0.0)

[PaddleGraphic]
Texture = data/paddle.png
Pivot   = center

[Blocks]
ChildList = Block1 # Block2 # Block3 # Block4

[Block1]
Graphic   = BlockGraphic
Position  = (-50.0, -30.0, 0.0)

[Block2]
Graphic   = BlockGraphic
Position  = (50.0, -30.0, 0.0)

[Block3]
Graphic   = BlockGraphic
Position  = (-50.0, 30.0, 0.0)

[Block4]
Graphic   = BlockGraphic
Position  = (50.0, 30.0, 0.0)

[BlockGraphic]
Texture = data/block.png
Pivot   = center

代码:

// Init game function
orxSTATUS GameApp::InitGame()
{
  orxSTATUS result = orxSTATUS_SUCCESS;

  // Creates viewport
  if ( orxViewport_CreateFromConfig("Viewport") == NULL ) {
      result = orxSTATUS_FAILURE;
  }

  if (orxObject_CreateFromConfig("Ball") == NULL) {
      result = orxSTATUS_FAILURE;
  }

  if (orxObject_CreateFromConfig("Paddle") == NULL) {
      result = orxSTATUS_FAILURE;
  }

  if (orxObject_CreateFromConfig("Blocks") == NULL) {
      result = orxSTATUS_FAILURE;
  }

  // Done!
  return result;
}

代码实在就是没有太多好说的了,在Orx中,永远是配置复杂,代码简单。说说配置中的新东西,我在这里用
[Blocks]
ChildList = Block1 # Block2 # Block3 # Block4

的形式+一行创建Blocks的代码,来完成了4个砖块的创建。这是Orx中使用子列表的一种方式。
效果如下:(我把窗口大小也改了)

是不是有那么一点意思了?
到目前为止,我们学到什么了?4行配置。。。。。。。。。。且只有Graphic加Texture算是新内容。只要这些,你通过position就可以完成你想要的任何图形布局了。
当然,其实远远不止这些,请参考Orx的WIKI获取更多的信息:

物理的加入

    好了,现在是添加真的游戏内容的时候了。光是静态图形可做不了游戏。
    在打砖块的游戏中,很重要的就是球的碰撞,反弹,以及碰撞的检测了。由于Orx中内嵌了Box2D引擎,我们能够很方便的使用,我多次提到是内嵌,而不是外挂,不是如Cocos2D那种仅仅包含一个Box2D,然后需要你调用Box2D的API去完成的那种,事实上,你可以根本不知道Box2D是啥。(其实个人感觉,了解Box2D的相关概念是必要的,不然怎么知道各个属性应该怎么配置啊)

首先,物理世界的加入:
[Physics]
DimensionRatio    = 0.1
WorldLowerBound   = (-300.0, -300.0, 0.0)
WorldUpperBound   = (300.0, 300.0, 0.0)

这是必须的,似乎属于Box2D为了优化而添加的,Orx为了灵活,没有自动的去配置这些属性,一般而言,将其设为包含整个游戏屏幕即可。(稍微大一点点)配置的是一个矩形的左上角和右下角。(注意Orx的坐标系啊)

然后,为各个物体添加物理属性,最主要的是Body段的属性:
[Ball]
Graphic   = BallGraphic
Body      = BallBody
Speed     = (0, -40, 0)
Position  = (0.0, 180.0, 0.0)

[BallGraphic]
Texture = data/ball.png
Pivot   = center

[BallBody]
Dynamic   = true
PartList  = BallPartTemplate

[BallPartTemplate]
Type = sphere;
Friction = 0.0;
Restitution = 1.0;
Density = 1.0;
SelfFlags = 0x0001;
CheckMask = 0x0001;
Solid = true;

注意Ball的中添加了一个Body      = BallBody,然后所有的物理部分都写在了BallBody和BallPartTemplate中。先说明一下,之所以我把part叫template,而且Orx的作者添加了这样一个新的段来表示物理部分,包括命名为part,是因为Orx允许一个body有多个part组合成一个object的物理。这在某些时候也极为有用。比如希望有个组合图形,一个part无法表示的时候。
至于各个物理的属性的含义,推荐先去了解一下Box2D 的各个定义。要图省事,看看Orx的说明也行。

然后,如法炮制,基本的意思就有了。
[Paddle]
Graphic   = PaddleGraphic
Body      = PaddleBody
Position  = (0.0, 230.0, 0.0)

[PaddleGraphic]
Texture = data/paddle.png
Pivot   = center

[PaddleBody]
Dynamic   = false
PartList  = PaddlePartTemplate

[PaddlePartTemplate]
Type = box;
Friction = 0.0;
Restitution = 1.0;
Density = 1.0;
SelfFlags = 0x0001;
CheckMask = 0x0001;
Solid = true;

[Blocks]
ChildList = Block1 # Block2 # Block3 # Block4

[Block1]
Graphic   = BlockGraphic
Body      = BlockBody
Position  = (-50.0, -30.0, 0.0)

[Block2]
Graphic   = BlockGraphic
Body      = BlockBody
Position  = (50.0, -30.0, 0.0)

[Block3]
Graphic   = BlockGraphic
Body      = BlockBody
Position  = (-50.0, 30.0, 0.0)

[Block4]
Graphic   = BlockGraphic
Body      = BlockBody
Position  = (50.0, 30.0, 0.0)

[BlockGraphic]
Texture = data/block.png
Pivot   = center

[BlockBody]
Dynamic   = false
PartList  = BlockPartTemplate

[BlockPartTemplate]
Type = box;
Friction = 0.0;
Restitution = 1.0;
Density = 1.0;
SelfFlags = 0x0001;
CheckMask = 0x0001;
Solid = true;

特别需要注意的是,Orx的设计上常常会让人感觉很多时候一个段的东西拆了几个段,写起来很麻烦,但是每个段都是可以复用的,比如此例中,所有的Block都共用一个Body。所以作者从长远考虑才这样做。

然后,再给Ball 一个速度。你就能够看到物理的作用了。球从paddle反弹到block再反弹到paddle。带角度。。。。。。。。。

碰撞检测

    打砖块的游戏要求球碰到砖块时砖块消失的,这个需要做碰撞检测,这在Orx中也是很简单的,需要进行物理的Event响应,这是个新内容。
首先,初始化的时候,添加关注的事件。
  orxEvent_AddHandler(orxEVENT_TYPE_PHYSICS, GameApp::EventHandler);
这个没有什么好说的,别忘了就行。

然后,就是在注册函数中物理的响应了,此例中是GameApp::EventHandler。

// Event handler
orxSTATUS orxFASTCALL GameApp::EventHandler(const orxEVENT *_pstEvent)
{
    orxSTATUS eResult = orxSTATUS_SUCCESS;
    if(_pstEvent->eType == orxEVENT_TYPE_PHYSICS) {
        if( _pstEvent->eID == orxPHYSICS_EVENT_CONTACT_ADD ) {
            /* Gets colliding objects */
            orxOBJECT *object_recipient = orxOBJECT(_pstEvent->hRecipient);
            orxOBJECT *object_sender = orxOBJECT(_pstEvent->hSender);

            string recipient_name(orxObject_GetName(object_recipient));
            string sender_name(orxObject_GetName(object_sender));
            if(recipient_name == "Ball" && sender_name != "Paddle") {
                orxObject_Delete(object_sender);
            }
        }
    }
  // Done!
  return orxSTATUS_SUCCESS;
}
有了代码后,其实基本上意思都很明显了,先判断事件的类型,然后判断事件的ID(其实相当于某类型事件中的子类型),这里判断的是物理的contact_add,表示有碰撞(外国人喜欢说有接触?)产生的时候。然后通过名字去判断两个物体是什么。这里没有考虑效率,直接用名字来判断了(事实上可以通过设定 userdate,然后通过ID判断),再进一步,为了方面直接用std::string而没有通过strcmp了。
判断被推开的物体是球,而且还不是paddle推开的,那么就肯定是block了,此时用orxObject_Delete将其删除,实现打砖块的消除效果。

 

需要完善的部分

    游戏其实基本成型了,剩下的,就是给游戏加个边框,(这个都不需要我额外讲方法了)不然球飞出去了,然后就是操作部分了,下一节再讲。

 

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....

Orx系列视频教程。Orx作者亲自录制。

Orx作者iarwain亲自录制,品质保证,非Youtube,中国可流畅播放。

 

- Part1: setup and
build(设置及构建)

- Part2:
simple object display(简单的物体显示)

- Part3: advanced object properties(高级物体属性)

- Part4: simple visual FX(简单的特效)

-
Part5: spawner
combined with FX(加特效的spawner)   spawner不知道怎么翻译,大概类似于一个游戏中的物体创建发生器

- Part6: more spawner controls(更多的spawner控制)

- Part7: config override
and release/debug builds(配置覆盖和release/debug构建)

- Part8: final summary(总结)

 

因为有些老,我都从来没有看到过。。。。。。。。作者不保证全部的内容现在都还有效(新版的API,Config可能有些变化),但是,对Orx有个大概的了解是肯定没有问题。对于不想一行一行阅读英文教程的人也是个福音吧。

 

有意思的是,整个视频,没有一点声音,但是作者还是非常想表达自己的观点,那么怎么办?举个例子。在final summary中,作者连续选中唯一的两行createfromconfig代码N次,然后不停的改配置,就是告诉你,我只有2句代码,通过配置能实现什么效果,从一个小女孩(iarwain惯用),到旋转的气泡,到与气泡一起旋转的小女孩,作者没有改过一行代码,一直使用一个编译好的程序,仅仅通过notepad++来编辑配置。那就是iarwain的总结,估计其一直以此为自豪,所以在VS中高亮选择那么两行代码,其实,整个过程,VS几乎就是摆设,因为从来没有用到过。

阅读全文....

勤奋的人是怎么工作的。。。。。。。。。。看看Orx的作者更新Orx的频率就知道了


作为一个没有任何盈利并且code for fun的项目Orx,iarwain用在Ubisoft工作之余,几乎每天没有间断过的维护着。。。。。。。。。从代码提交记录上来看,这么积极的维护的开源项目,真的是少有了。。。。。。。。。。

 

 

想到自己,真是惭愧啊。。。。。。。。。

因为Orx的数据驱动的特点,因为iarwain的勤奋和热心,我也真是喜欢多多学习使用Orx,因为这是一个用心在做的项目。

 

甚至,同期全职上班的人,用上班时间做的东西,将提交记录总结出来,也不见的有iarwain用业余时间做的这么多吧?他还常说他很忙,需要带孩子。。。。我的天哪。。。。。。。。。。。

 

 

 

 

 

 

阅读全文....

现有Orx作品展示

write by 九天雁翎(JTianLing) -- www.jtianling.com

讨论新闻组及文件

 

 

Orx作品展示

    一个相对成熟的引擎背后不可能没有相对成熟的游戏。这点我深信不疑,毕竟引擎不是闷着脑袋在家里开发的,而且通过开发游戏来促进的。相对来说,目前还没有发现用Orx制作的非常大型的精良的游戏,这点也说明了Orx的不成熟,我一点都不忘提及,Orx的确还不成熟,我只能说,iarwain的开发思想很好,Orx的设计很有意思,用于开发一款游戏的速度也很快,很灵活。但是,这里还是有一些用Orx制作的小作品,起码可以看出,Orx可以做什么,已经做到什么效果。同时,也对对于Orx不了解,没有信心的人一点新的关于Orx的信息。
    这些作品在Orx的论坛上都有,但是鉴于很多时间已经很久,并且语言的原因,没有人去深挖或者寻找了,我这里将一些我见到的提出来,给大家看看。

其一:Mushrooms Stew

    此作品由Orx目前的主要维护者iarwain自己主要负责开发,甚至还实现了一个小规模的level editor。
    该游戏讲述的是一个蘑菇间的故事。。。。。呵呵,动画效果其实很不错,虽然个人感觉游戏性薄弱了一点,但是还算是值得一玩。
    原论坛帖子地址在此
开源发布
。因为Orx的跨平台特性,你可以在Windows,Macos,Linux上玩到。

截图:

编辑器截图:

其二:Drops

    一个有趣的游戏,与音乐相结合。特别是一些效果处理的非常好,比如选择颜色那个动画,相当的酷。整个工程完全用C语言写的,也算是怎么用C语言+Orx做游戏的一个非常好的例子。
    论坛原址
开源发布

截图:

其三: DragonCube
    一个有非常好的动画效果,非常有意思特性的Demo,论坛原址

    这里先提出论坛原址,因为想说说这个Demo背后的故事,帖子名叫First steps, first project
,这是 Blarg
,一个iarwain说的原本是做Flash的设计师,原来根本不是程序员,在看了Orx的教程后,仅仅是通过模仿Orx教程中的一条一条特性,前后只用了一周多的时间(从帖子也可以看出来iarwain所说属实)开发出来的。。。。。。。。闭源发布

    因此,我感觉那是有非常非常让人诧异和惊艳的效果,呵呵,你说那是用Flash做的,估计也没有人不相信。。。。。。。。推荐每一个准备学习Orx的人看看,一个尚且不是程序员的人,两周之内能用Orx做到什么程度。。。。。。。。。


 

不清楚为啥在csdn上发布的时候我的图先前还在,为啥到后来丢失了。不可理喻。。。。。。。。。

 

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- www.jtianling.com

阅读全文....