3

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

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

我意识到我可以在应用程序端初始化渲染器,但我宁愿让游戏决定何时何地执行它。一般来说,我可以控制应用程序端,但不能控制游戏端。游戏编写者可能会选择使用不同的渲染器。

我也有过使用某种“属性管理器”的想法,我可以在其中通过字符串传递数据,但我不太喜欢这个想法。

有任何想法吗?

4

4 回答 4

4

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

在一个好的设计中,游戏不应该要求任何关于其平台的信息;它应该只包含逻辑和相关组件。

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

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

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

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

于 2010-01-25T15:08:25.193 回答
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);
}
于 2010-01-25T15:09:34.567 回答
1

一个通过的 SystemContext 类怎么样?您将拥有 Win32Context、LinuxContext 等。这是 OGRE 处理它的方式(在这种情况下为 RenderContext)。

Renderer 类接受一个 SystemContext 指针。

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

于 2010-01-25T15:11:58.760 回答
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 个实现。当您确实拥有给定平台的 1 个实现时,这可以避免使用基本虚拟功能。

于 2010-01-25T16:51:39.330 回答