2010-01-25 53 views
2

我有一个用C++编写的游戏引擎设计,其中平台无关的游戏对象包含在平台特定的应用程序对象中。在独立于平台的设计中传递特定于平台的数据?

我试图解决的问题是我需要从应用程序传递特定于操作系统的数据到游戏的情况。在这种情况下,我需要将Windows的DirectX主要HWND或其他平台的OpenGL上下文传递给我正在使用的渲染器。不幸的是,我无法控制渲染器,它可以预期特定于平台的数据。

我意识到我可以初始化应用程序方面的渲染器,但我宁愿让游戏决定何时何地做这件事。一般来说,我可以控制应用程序方面,而不是游戏方面。游戏作者可能会选择使用不同的渲染器。

我也喜欢有一种“物业经理”的想法,我可以通过字符串传递数据,但我不太喜欢这个想法。

任何想法?

+0

如果游戏对象是平台独立的,那么为什么它需要通过平台相关变量? – 2010-01-25 15:10:41

+0

好问题!长话短说,我们可以控制应用程序类,但不能控制渲染器或游戏类。 这只是我们目前正在探索的内容。 – djcouchycouch 2010-01-25 15:27:21

回答

3

请记住,您只需要在编译时了解目标平台。有了这些信息,您就可以为正确的平台“换入和换出”组件。

在一个好的设计中,游戏应该是而不是需要关于它的平台的任何信息;它只应该掌握逻辑和相关组件。

您的'引擎'类应该担心该平台。

游戏类只能通过公共函数与引擎对象进行交互,这些公共函数并非特定于平台;您可以为每个平台提供多个Engine对象版本,并在编译时选择使用哪一个。

例如,您可以有一个表示游戏纹理的纹理“引擎”类。如果您支持OS X和Windows,则可以使用“Texture.h”,其中包含“Windows/Texture.h”或“OSX/Texture.h”,具体取决于您正在编译的平台。这两个头文件将定义一个具有相同接口的Texture类(即它们都具有相同的参数的相同公共函数),但它们的实现将是特定于平台的。

为了澄清,游戏应告诉应用程序初始化渲染器;游戏逻辑和实现细节之间应该有严格的界限。渲染器是实现细节,而不是游戏逻辑的一部分。游戏类应该对系统一无所知,而只涉及游戏世界。

1

查看模板模式(在抽象基类中使用可以在派生类中配置的纯虚函数)。

http://en.wikipedia.org/wiki/Template_pattern

如果你喜欢一个更可控的(和更少的面向对象)的方式,游戏的部分应该调用的应用程序部分配置的回调函数,以执行特定于平台的配置。

例如为:

// in Application: 
static void SetWindowHandle(GameEngine const& p_game_engine, void* p_callback_data) 
{ 
    p_game_engine.DoSomethingWithHandle(static_cast<ApplicationManager*>(p_callback_data)->GetHWND()); 
} 

void Initialize() { 
    this->m_game_engine.Initialize(this, &Application::SetWindowHandle); 
} 

// ... 
// in Game Engine: 
// ... 

typedef void (*TSetWindowsHandleCallback)(GameEngine const*, void*); 

void* m_application_data; 
TSetWindowsHandleCallback m_windows_handle_callback; 

void Initialize(void *p_application_data, TSetWindowsHandleCallback p_callback) 
{ 
    this->m_application_data = p_application_data; 
    this->m_windows_handle_callback = p_callback; 
} 

void SetWindowsHandle() 
{ 
    this->m_windows_handle_callback(*this, m_application_data); 
} 
+0

+1,但我更喜欢dauphic的方法,因为使用派生类可以一次封装多个特定于平台的行为。实际上,基类中的每个公共方法==“可配置的回调函数”。 – 2010-01-25 15:16:04

1

怎么样得到一个SystemContext类传入?你会有一个Win32Context,LinuxContext等。这是OGRE处理它的方式(RenderContext就是这种情况)。

Renderer类需要一个SystemContext指针。

在内部,DirectXRenderer(Renderer的后代)dynamic_casts(一次)指向Win32Context的指针,并从中挑选出所有依赖于平台的数据。

0

我喜欢做的是让一个基类与所有通用数据成员实现共享。然后我有一个本地类,它包含基类本身包含的特定于平台的信息。这需要一个特定的目录结构。例如,你有:

code 
    renderer 
    context.h 
    platforms 
    win32 
     renderer 
     context_native.h 
    osx 
     renderer 
     context_native.h 

code/renderer/context.h 
class RenderContextBase { /* shared members */ }; 
#include "renderer/context_native.h" 

code/platform/win32/renderer/context_native.h 
class RenderContext : public RenderContextBase { /*win32 specific */ }; 

code/platform/osx/renderer/context_native.h 
class RenderContext : public RenderContextBase { /*osx specific */ }; 

使用你的编译器“附加包含目录”,你只需添加取决于平台上正确的目录。例如,在win32上,添加“code/platform/win32”作为附加目录。当包含renderer/renderer_native.h时,它将不会在“默认”位置找到,并会尝试使用其他目录。

从代码中的任何地方RenderContext是本地实现。你不需要有一个指向基类和新的本地类的指针,因为你真的有1个实现。当你真的有一个给定平台的实现时,这可以避免有基本的虚拟功能。